onsdag 26 september 2012

Mer om logiska uttryck och elif-satsen

Vi ska nu titta på mer komplicerade logiska uttryck.

Minns att vi har en logisk datatyp som kallas bool som kan ha två olika värden. Sant, True, och falskt, False.
En jämförelse som x>5 resulterar i ett svar av typen bool; True om x är större än 5 och False annars.

And, or och not

För att kombinera olika jämförelser används de logiska operatorerna: and (och), or (eller) och not (icke).
Om A och B är bool fungerar de som i tabellerna nedan:

A B A and B
False False False
False True False
True False False
True True True
Både A och B måste vara sanna för att A and B skall bli sant


A B A or B
False False False
False True True
True False True
True True True
Minst en av A eller B måste vara sann för att A or B skall bli sant

A not A
False True
True False

Övning 1.18
Använd det interaktiva skalet för att pröva de logiska operatorerna. Pröva med följande:
a) True and False
b) True or False
c) not False
d) 3 > 2 or 2 > 3

Prioriteringsregler

Liksom i vanliga matematiken, där tex.  * görs före +, finns det prioriteringsregler för logiska operatorer. Se följande tabell som går från högsta till lägsta av de vi kommit i kontakt med:
Prioritet Operatorer
1 ()
2 vanlig matematik
enligt dess regler
3 jämförelser: >, <,
 ==, !=, >=, <=
4 not
5 and
6 or

I övning 1.18d görs alltså jämförelserna 3>2 som blir True och 2>3 som blir False först. Sedan True or False som blir True.

Notera:
or görs efter and
not görs före både and och or

Övning 1.19
Använd det interaktiva skalet för att pröva de logiska operatorerna. Pröva med följande:
a) not True and False
b) not (True and False)

Varför blir det skillnad mellan resultaten?

Övning 1.20
Skriv och testa följande program:

while True :
    try : 
        a=int(input("Skriv ett tal "))
        if a < 100 and a > 50 :
            print("Du skrev ett tal mellan 50 och 100")
    except ValueError:
        print("Tack för mig")
        break


Uppgift 1.7
 Ändra det logiska uttrycket i if-satsen i övning 1.20 så den talar om om man skriver tal som antingen är större än 100 eller mindre än 50.

elif-satsen

En if-sats kan följas av en eller flera elif-satser, förkortning för "else if". Detta är användbart i många sammanhang.

Övning 1.21
Skriv och testa:

while True :
    try : 
        a=int(input("Skriv ett tal "))
        if a > 100 : print("Du skrev ett tal större än 100")
        elif a > 50 :
            print("Du skrev ett tal mellan 50 och 100 (inkl.)")
        else : print("Du skrev ett tal mindre än 50")
    except ValueError:
        print("Tack för mig")
        break
 
Funktion:
  • Först utförs testet i if-satsen. Om det är sant görs följande print-sats sedan hoppar programmet över följande elif och else. Annars går programmet vidare till elif-satsen.
  • Om if-satsen svarade falskt utförs testet i elif-satsen. Om det är sant görs följande print-sats sedan hoppar programmet över följande else. Annars går programmet vidare till else-satsen.
  • Om inte if- eller elif-satsen var sann görs satserna efter else.
Övning 1.22
Skriv ett program som talar om om ett inmatat heltal är jämnt delbart med 2, 3 eller 5. Tips: Se övning 1.10.

onsdag 12 september 2012

Månlanda


Månlanda är ett enkelt och klassisk spel inspirerat av Apollo-programmet. Spelaren ska landa en månlandare på månen. När spelet startar är landaren på väg ner och spelaren kan reglera bromsraketernas gaspådrag en gång per sekund för att landa mjukt. Dock har landaren begränsad mängd bränsle så det gäller att inte slösa.

Spelfysiken

Spelet bygger på Newtons fysik och rörelseformlerna som du mött i fysikkurserna.

Spelets simulering tar tidssteg på en sekund och acceleration, hastighet och höjd beräknas för varje tidssteg.

Månens gravitation är inte lika stark som på jorden utan tyngdaccelerationen är ungefär en sjättedel av den på jorden. I spelet kan det vara bekvämt att sätta tyngdaccelerationen lika med 1,5 m/s2.

Bromsraketerna motverkar tyngdaccelerationen. Accelerationen under ett tidssteg kan skrivas som:

a =  fK - G                                     (Ekv. 1)

Där f är bränsleflödet i liter per sekund, K en konstant och G månens tyngdacceleration. Konstanten K är ett mått på kraften från motorn, vid pådraget 1 l/s, i förhållande till landarens massa. Notera att positiv acceleration är uppåt då höjden ökar åt det hållet.

Hastigheten ändras alltså med a under ett tidssteg:

vt = vt-1 + a                                 (Ekv. 2)

Där vt är den nya hastigheten och vt-1 är hastigheten förra tidssteget.

Höjden kommer att ändras med medelhastigheten under tidssteget:

ht = ht-1 + (vt + vt-1) / 2            (Ekv. 3)

vilket kombinerat med Ekv. 2 blir

ht = ht-1 + vt - a/2                     (Ekv. 4)


För varje nytt tidssteg beräknas alltså:

a =  fK - G

vt = vt-1 + a 

ht = ht-1 + vt - a/2


Gaspådrag och bränsle

Varje nytt tidssteg börjar med att spelaren anger det valda gaspådraget f. Gaspådraget har ett maximalt värde, full gas, som spelaren inte kan överskrida. Naturligtvis kan spelaren inte ange negativt gaspådrag eller använda mer än det kvarvarande bränslet.

Vid varje tidssteg minskas kvarvarande bränsle med pådraget f:

bt = bt-1 - f

Där bt är kvarvarande bränsle.

Landningen

När höjden är noll, eller mindre, sker landningen...eller kraschen. Om farten då är mindre än 2 m/s, alltså vt > - 2 , så anses landningen lyckad annars är det en kraschlandning.

Flödesschema

Nedanstående visar ett förslag på flödesschema för programmet:

Lämpliga startvärden

Följande värden är lämpliga för att få ett fungerande spel:
Tyngdacceleration G=1,5
Full gas MAX=60
Konstant K=0,1
Bränslemängd b=600
Starthöjd h=500
Starthastighet v=-10

Inlämningsuppgift 1.3

Skapa spelet Månlanda och skicka in. Tänk på att hantera eventuella undantag.

Tips: När du fått spelet att fungera så kan du testa olika värden på bränslemängd eller andra variabler för att göra spelet lagom svårt.

Tips: Som standard skrivs alla decimaler ut för höjd och hastighet och bränsle. Detta kan leda till svårlästa rader. Det går att få en snyggare formatering med tex två decimaler genom att använda formaterings-funktionen för texter:

print("Höjd= {0:.2f}".format(h))

Om h=2.248432 ger ovanstående texten: Höjd= 2.25


Överkurs: Läs mer om textformatering här och se om du ytterligare kan snygga upp utskrifterna.

tisdag 11 september 2012

Repetitionsuppgifter 1.1

Dessa uppgifter repeterar tidigare kunskaper. Göres i mån av tid på lektionen eller som repetition hemma.

Rep 1.1
Skriv ett program som simulerar kast med två vanliga tärningar och visar ögonsumman.

Rep 1.2
Skriv ett program som beräknar medelvärdet av inmatade positiva tal. Efter varje nytt tal användaren skriver in ska medelvärdet av de inskrivna talen skrivas ut. Avslutas genom att användaren skriver in -1.

Rep 1.3
Skriv ett program som i repetitionsuppgift 1.2 men som efter avslutat inskrivande skriver ut det största av de inmatade talen.

söndag 9 september 2012

Fel och undantag

Det finns tre grundtyper av fel i programmeringssammanhang:
  • Syntax-fel: Fel i källkoden pga stavfel eller felaktig satsbyggnad
  • Buggar: Fel i källkoden så att programmet inte uppför sig som förväntat
  • Undantag (eng. Exceptions) Fel av typen division med noll, inmatning av text när en siffra förväntas mm.
Syntaxfelen brukar upptäckas av skalet du använder för att skriva ditt program. Buggar är upp till dig som programmerare att leta efter och rätta. För små program är det ofta enkelt att finna dem men för större kan det vara mycket svårt.

Undantag kan även beskrivas som förväntade problem. Sådant som du när du programmerat räknar med kan hända. Till exempel att någon råkar trycka ENTER istället för att skriva in ett tal. Det är att hantera undantag vi ska titta på här.

try-satsen

Satsen try används för att hantera förväntade problem. De består av två delar try och except.  Se nedanstående exempel:

Övning 1.15
Skriv följande program som hanterar division med noll och testa funktionen

a=float(input("nämnaren="))
try :
    print(100/a)
except ZeroDivisionError :
    print("Division med noll")
print("Tack för mig")

Hur det fungerar:
  • Först utförs de indragna satserna mellan try och except.
  • Om inget undantag inträffar hoppas de indragna satserna efter except över och programmet går vidare vid print("Tack för mig") .
  • Om ett undantag inträffar vid någon av satserna mellan try och except så hoppar programmet direkt till except. Där kontrolleras om undantaget är av den klass (typ) som beskrivs av nyckelordet ZeroDivisionError. Om så är fallet utförs de indragna satserna efter except. Texten "Division med noll" skrivs ut. Sedan fortsätter programmet till sitt slut.
  • Om ett undantag inträffar av en annan klass än ZeroDivisionError kommer programmet att hantera detta på standardsätt. Alltså programmet avslutas med ett felmeddelande.


Övning 1.16
Kör programmet i övning 1.15 och skriv in en bokstav istället för ett tal.

Notera att programmet nu avslutas med ett felmeddelande och sista raden inte körs. Du har nu skapat ett icke hanterat undantag (eng. unhandled exception).

Några undantagsklasser

Det finns en stor mängd färdigdefinierade undantag i Python. De är också ordnade i en hierarki med vissa undantag som är generella och täcker in flera underklasser.

Klass Beskrivning
Exception Huvudklassen för alla undantag. Används med försiktighet för att fånga upp undantag. Använd i första hand mer specifika klasser i stället.
IOError Undantag vid tex. läsning av och skrivning till filer.
IndexError Undantag vid hantering av listor och dylikt. Mer om detta senare i kursen
TypeError Undantag då typen är fel för operationen/fuktionen.  Tex: print("a"+2).
ValueError Undantag vid ogiltigt värde. Tex. math.sqrt(-2)
Även försök att omvandla en sträng bokstäver till tal med float() och int(). Se nedan övning 17
ZeroDivisionError Undantag vid division med noll.

Det går att ha flera olika klasser av undantag listade efter except. Man sätter de då inom parentes och med komma mellan dem. Till exempel kan det ibland vara bra att hantera matematiska fel med:

except (ValueError, ZeroDivisionError) :


Överkurs: Läs mer om undantag och hierarkin. Följ länkarna i texten ovanför tabellen.

Överkurs: Det går att ha flera except i en och samma try-sats för att hantera olika undantag. Läs om detta här.

Övning 1.17
Denna övning visar hur man skriver ett program som hanterar inmatning så att frågan upprepas tills användaren matar in korrekt datatyp. Skriv och testa.

while True :
    try :
        a=float(input("Skriv en siffra "))
        break
    except ValueError :
        print("Ooops! Ej ett tal")
print("Du skrev " + str(a))

Programmet snurrar i while-loopen om det blir ett undantag i tilldelningen av a. Om tilldelningen sker korrekt når programmet break-satsen och hoppar ur loopen  till sista raden.

Uppgift 1.5
Skriv om inlämningsuppgift 1.2, andragradsekvationsprogrammet, så att det hanterar felaktiga värden vid inmatning (så som text eller bara ENTER) samt använder undantag istället för if-sats för att hantera negativa rötter.

Uppgift 1.6
Då man ska mata in många värden är det extra viktigt att använda undantagshantering. Ingen vill mata in 143 värden och sedan kraschar programmet pga att man råkar trycka fel vid det 144...
Skriv om uppgift 1.4 så att felaktiga inmatningar hanteras. Tips: det går att utnyttja den oändliga loopen som redan finns för att effektivt genomföra detta.

tisdag 4 september 2012

While-loopar

I en loop upprepas samma satser flera gånger. Vi ska här se på en av två vanliga loopar nämligen while-loopen

While-loopen

While-loopen upprepar satserna i loopen tills logiska uttrycket i while-satsen inte är sant. Precis som för if-satser används indrag för att markera vilka satser som ska loopas:

while logiskt uttryck:
   sats(er) 

Övning 1.12
Skriv och testa följande program.
#Gissa tal

import random #modulen random gör så att jag kan generera slumptal

a = random.randint(1, 10) #Genererar ett slumpmäsigt heltal 1 till 10
b = 0                     #Initierar gissat tal utanför intervallet
gissningar = 0            #Antal gjorda gissningar 
while a != b :
    b = int(input("gissa talet:"))
    gissningar = gissningar + 1 #Ökar antalet gissningar med 1
print("Du gissade rätt på " + str(gissningar) + " försök")

Det finns några saker att notera i detta program:
  • Användningen av random.randint(1, 10) som generar ett slumpat heltal från och med 1 till och med 10. Läs gärna mer om generering av slumptal här.
  • Initieringen av b före loopen. Variabeln b sätts till 0 som är utanför intervallet för slumptalet. Vad kunde ha hänt annars?
  • Initieringen av gissningar till 0 då den kommer att ökas med 1 efter den första gissningen.
  • Tilldelningen gissningar=gissningar+1 gör att gissningar ökas med 1 efter varje gissning. Lägg märket till att denna typ av =-användning är felaktig matematiskt men vanlig inom programmering.
Överkurs: Tilldelningen a = a + 1 kan skrivas mer kortfattat med operatorn += så som a += 1 . Ändra i programmet så att denna operator används.

Övning 1.13
Ändra programmet i övning 1.12 så att ett slumpat heltal mellan 1 och 100 genereras samt att användaren får reda på om gissningen var större eller mindre än rätt svar efter varje gissning.

Uppgift 1.3
Skriv ett program som för varje varv i en loop genererar ett slumpat heltal 1 till 6 och adderar det med föregående tal samt skriver ut summan. Programmet ska loopa tills summan blivit minst 100.


Oändlig while-loop och break

Nedanstående är en oändlig loop.

while True :
    print("loop the loop")

OBS! Ovanstående köres på egen risk. Prova ctrl+C för att bryta loopen men inga garantier ges.

Dessa kan vara användbara ibland men vanligen vill man ha något sätt att bryta loopandet. Då kommer kommandot break till hjälp. Med break bryts loopen och programmet fortsätter nedanför loopens satser.

Kommandot break kan användas i alla loopar för att hoppa ur loopen.

Övning 1.14
Skriv programmet nedan och testa funktionen

while True :
    a=int(input("Skriv in ett tal. (0 för att sluta) "))
    if a == 0 : break
print("Du skrev noll. Avslutar")

Uppgift 1.4
Genom att  använda en oändlig loop samt break  i stället för att göra testet om gissningen är korrekt i while-satsen kan programmet i övning 1.13 skrivas kortare och med färre variabler. Gör det.