6. Lær at programmere

Kontrol med strømmen

 Kontrol med strømmen

Ahhhh, at kontrollere en strøm  (flow control) . Her samles alt hvad vi har lært. Selvom dette kapitel er kortere og lettere end kapitlet om metoder, vil det åbne en helt ny verden af program muligheder. Efter dette kapitel vil vi være i stand til at skrive rigtige 'spørgsmål og svar' programmer. Indtil nu har vi lavet programmer som sagde forskellige ting afhængig af hvad du skrev på dit keyboard, men efter dette kapitel vil de også lave andre ting. Men før vi går ind i det, må vi lære at  sammenligne ting  i dine programmer. Vi  skal have ...

 Sammenlignings metoder

Lad os skynde os gennem denne del så vi kan komme til  den næste del, forgreninger, hvor alt det seje sker. Så for at se om et objekt (tal, strenge og lignende)  er større eller mindre end et andet bruger vi metoderne > og <, sådan her:


puts 1 > 2
puts 1 < 2


false
true


Det var ikke noget problem. På samme måde kan vi finde ud af om et objekt er større end eller lig med  et andet (eller mindre end eller lig med) med metoderne >= og <=


puts 5 >= 5
puts 5 <= 4


true
false


Og tilsidst kan vi se om to objekter er lig med hinanden eller ej ved at bruge == (som betyder: "er disse lig hinanden") og != (som betyder: "er disse forskellige?").  Det er vigtigt ikke at blande = og == sammen. = bruges til at pege på et objekt (tildeling) og == bruges til at stille spørgsmålet: "Er disse to objekter lig med hinanden".

puts 1 == 1
puts 2 != 1


true
true


Vi kan selvfølgelig også sammenligne strenge. Når strenge bliver sammenlignet så sammenligner man deres  leksikale rækkefølge som faktisk betyder deres rækkefølge i ordbogen. 'hund' kommer før 'kat' i ordbogen, så:

puts 'hund' < 'kat'

true

Der er dog et problem her: normalt når computere stiller bogstaver på rækker, så kommer store bogstaver før små bogstaver. (Det er den måde de lagrer bogstaver på i fonte (computerskriftstyper) . For eksempel: alle store bogstaver først, så små bogstaver.) Dette betyder  at den vil tænke at 'Zoo' kommer før 'myre', så hvis du ønsker at finde ud af hvilket ord der kommer først i en rigtig ordbog, skal du sørge for at lave dem alle til små (eller store) bogstaver før du sammenligner dem, med metoderne:upcase, downcase eller capitalize.

 Et sidste ord inden vi kommer til Forgrening: Sammenligningerne giver os ikke strengene 'true' eller 'false' tilbage. De giver os nogle specielle objekter 'true' eller 'false'. (Selvfølgelig vil 'true'.to_s give os 'true' og derfor printede 'puts' også   'true'. 'true' og 'false' bruges hele tiden i ...


 Forgrening.


Forgrening er en simpel men kraftfuld begreb. Faktisk er det så simpelt at jeg vil vædde på at jeg ikke engang behøver at forklare det. Jeg vil bare vise dig det:

puts 'Hej! Hvad hedder du ?'
name = gets.chomp
puts 'Hej, ' + name + '.'
if name == 'simon'
  puts 'Dejligt navn!'
end


Hej! Hvad hedder du
simon
Hej simon
Dejligt navn.

Men hvis vi skriver et andet navn får vi:

Hej! Hvad hedder du?
Karen
Hej, Karen.


Det er hvad forgrening går ud på. Hvis det, der kommer efter 'if' er sandt, så kører vi koden mellem 'if' og 'end'. Hvis det der kommer efter 'if' er false, køres det ikke. Såre simpelt.

Jeg rykkede koden mellem 'if' og 'end' ind alene fordi jeg mener at det så er lettere at holde styr på forgreningen. Næsten alle programmører gør det uanset hvilket sprog de programmerer i. Det er måske ikke til den store hjælp i dette simple eksempel, men når tingene bliver mere kompekse gør det en stor forskel.

Ofte vil vi gerne have et program til at gøre én ting når noget er sandt, og noget andet hvis det er falsk. Det er hvad vi bruger 'else' til:

puts 'Jeg er en spåkone. Skriv dit navn:'
name = gets.chomp
if name == 'simon'
  puts 'Jeg ser store ting for dig i fremtiden.'
else
  puts 'Din fremtid vil bringe dig .... .Hold da op - tiden er gået!'
  puts 'Jeg må afsted nu. Desværre!'
end


Jeg er en spåkone. Skriv dit navn:
simon
Jeg ser store ting for dig i fremtiden.


Prøv nu et andet navn ...

Jeg er en spåkone. Skriv dit navn:
Finn
Din fremtid vil bringe dig ... ..Hold da op - tiden er gået!
Jeg må afsted nu. Desværre!


 Forgrening er en som at komme til en skillevej: skal vi tage vejen for dem der hedder 'simon' eller skal vi tage den anden vej.

Og lige som veje i det virkelige liv kan man også komme til en en ny skillevej efter at have valgt den ene vej til at starte med:
Det er lige som en man går ud af en gren og når man gå kommer til en ny gren så kan den nye gren også have andre grene på sig:


puts 'Hej og velkommen til engelsk i 7. klasse.'
puts 'Mit navn er Bjørn.  Og dit navn er ... ?'
name = gets.chomp

if name == name.capitalize
  puts 'Værsgo at sætte dig, ' + name + '.'
else
  puts name + '?  Du mener ' + name.capitalize + ', ikke?'

  puts 'Ved du ikke engang hvordan du staver dit eget navn??'
  reply = gets.chomp

  if reply.downcase == 'jo'
    puts 'Hmm....Så sæt dig da!'
  else
    puts 'UD!!'
  end
end


Hej og velkommen til engelsk i 7. klasse.
Mit navn er Ole . Og dit navn er ... ?
simon
Du mener Simon, ikke
jo
 
Hmm....Så sæt dig da!

  Ok, så jeg vil skrive det med stort...Fine, I'll capitalize it...
Hej og velkommen til engelsk i 7. klasse.
Mit navn er Ole . Og dit navn er ... ?
Simon

Værsgo at sætte dig, Simon.  

Nogle gange kan det blive forvirrende at finde ud af hvorhen man kommer med de forskellige 'if','else' og 'end' sætninger. Jeg skriver selv 'end' samtidigg med at jeg skriver 'if' Så da jeg skrev det ovenstående program så det sådan her ud i starten:

puts 'Hej og velkommen til engelsk i 7. klasse.'
puts 'Mit navn er Ole . Og dit navn er ... ?'
name = gets.chomp
if
else
end
 

Så skrev jeg kommentarer, ting i koden som computeren vil ignorere:

puts 'Hej og velkommen til engelsk i 7. klasse.'
puts 'Mit navn er Ole . Og dit navn er ... ?'
name = gets.chomp
if
        # Han er venlig
else
        # han er ikke venlig
end
 

Alt efter et # betragtes som en kommentar (medmindre du, selfølgelig, er i en streng). Bagefter det skrev jeg virkelig kode i stedet for kommentarerne. Nogle foretrækker at lade kommentarerne stå. Personligt synes jeg at kode taler for sig selv. Engang skrev jeg flere kommentarer, men jo mere flydende jeg ''taler' ruby, jo mindre bruger jeg dem. Nogle gange synes jeg faktisk de distraherer. Men det er op til ens personlige smag. Du finder nok din egen personlige (og hele tiden udviklende) stil. Så mit næste trin så således ud:

puts 'Hej og velkommen til engelsk i 7. klasse.'
puts 'Mit navn er Ole . Og dit navn er ... ?'
name = gets.chomp
if name == name.capitalize
  puts 'Værsgo at sætte dig, ' + name + '.'
else
  puts name + '?  Du mener ' + name.capitalize + ', ikke?'
  puts 'Ved du ikke engang hvordan du staver dit eget navn??'
  reply = gets.chomp
  if reply.downcase == 'jo'
  else
  end
end
 

Igen skrev jeg 'if', 'else', og 'end' på samme tid. Det hjælper virkelig til at holde en på sporet af hvor man er i sin kode. Det gør også lettere fordi jeg kan koncentrere mig om én ting f.eks. at udfylde koden mellem 'if' og 'else'. Man får yderligere den fordel at computeren kan forstå programmet på et hvilket som helst trin. Alle de ufærdige versioner som jeg har vist dig, vil køre som et ruby program. De var ikke færdige, men programmet kunne køre uden fejl. På den måde kunne jeg teste programmet på samme tid som jeg skrev det, noget, der hjælper med at vise hvordan det går og hvad der mangler at blive lavet. Da det kunne klare alle tests, vidste jeg at programmet var færdigt.

 Disse tips vil hjælpe dig med at skrive programmer med forgrening, men de vil også hjælpe med den anden hoved type af kontrol over en strøm (flow control) :

 At køre i ring (Looping)

Ofte  vil du gerne bede din computer gøre den samme ting igen og igen - det er jo det computere regnes for at være gode til.

 Når du beder computeren om at gentage noget, skal du også fortælle dem hvornår de skal stoppe. Computere keder sig aldrig, så hvis du aldrig bad dem om at  stoppe, ville de aldrig gøre det. Vi sikrer os at det ikke sker ved at bede computeren om at gentage bestemte dele af programmet så længe en bestemt tilstand er sand. Det ligner meget den måde 'if' virker på:
command = ''

while command != 'farvel'
  puts command
  command = gets.chomp
end

puts 'Kom snart tilbage!'

 

 
Hej?
Hej?
Hi
Hi
Dejligt at se dig
Dejligt at se dig
farvel
Kom snart tilbage!

 Sådan virker en loop. (Du har måske opdaget den tomme linie i starten af programmet. Det er fra den første 'puts' før den første 'gets'. Hvordan kunne  du ændre programmet så du bliver fri for den første linie? Test det! Virkede den nøjagtig på samme måde som programmet ovenfor, udover den første linie?)

Jeg er sikker på at du kan se at loops kan bruges til en masse interessante ting. De kan dog også skabe problemer hvis du laver fejl. Hvad sker der hvis din computer bliver fanget i en uendelig loop ? Hvis du tror det er sket for dig, skal du bare holde Ctrl tasten nede og trykke på c.

 Før vi starter med at lege med loops, skal vi dog lige se på nogle få ting som vil gøre arbejdet lettere.


En smule logik

  Lad os lige se på vores første forgrenings program en gang til. Hvad nu hvis min kone kom hjem og så programmet, prøvede at køre det og programmet ikke sagde  "Dejligt navn" til hende ? Jeg har ikke lyst til at såre hende (og ikke lyst til at sove på sofaen) så lad os ændre det:


puts 'Hej hvad hedder du?'
name = gets.chomp
puts 'Hej , ' + name + '.'
if name == 'simon'
  puts 'Dejligt navn!'
else
  if name == 'karin'
    puts 'Dejligt navn!'
  end
end


Hej hvad hedder du?
simon
Hej simon
dejligt navn
Hej hvad hedder du?
karin
Hej karin
Dejligt navn


 Nåe ja, det virker, men det er ikke et kønt program. Hvorfor ikke? Jamen fordi,  den bedste regel jeg nogensinde har lært indenfor programmering er GID reglen: Gentag Ikke Dig selv. Jeg tror jeg kunne skrive en hel lille bog om hvorfor det er sådan en god regel. Her i vores eksempel gentog vi: puts 'Dejligt navn'.  Hvad er det så lige problemet er med det? Joe, for eksempel kunne jeg lave en tastefejl da jeg skrev det igen. Eller hvad nu hvis jeg hellere ville skrive 'smukt navn' i begge linier. Som du sikkert kan huske er jeg doven anlagt. Altså hvis programmet skal gøre det samme når  man skriver 'simon' som når man skriver 'karin' ja så skal det  gøre det samme.

puts 'Hej hvad hedder du?'
name = gets.chomp
puts 'Hej, ' + name + '.'
if (name == 'simon' or name == 'karin')
  puts 'Deligt navn!'
end


Hen hvad hedder du?
simon
Hej simon

Dejligt navn

Meget bedre. For at få det til at virke brugte jeg 'or'. De andre logiske operatorer er 'and' og 'not'. Det er altid en god ide at bruge paranteser når man arbejder med dem. Lad os se hvordan man bruger dem:

jegHedderSimon  = true
jegErBlond = false
jegElskerMad = true
jegSpiserSten = false


puts (jegHedderSimon  and jegElskerMad)
puts (jegElskerMad and jegSpiserSten)
puts (jegErBlond and jegElskerMad)
puts (jegErBlond and jegSpiserSten)
puts
puts (jegHedderSimon  or jegElskerMad)
puts (jegElskerMad or jegSpiserSten)
puts (jegErBlond or jegElskerMad)
puts (jegErBlond or jegSpiserSten)
puts
puts (not jegErBlond)
puts (not jegHedderSimon )


true
false
false
false

true
true
true
false

true
false


 Den eneste af dem som kan forvirre dig er 'or'. På Dansk bruger vi 'or' (eller) når vi mener "den ene eller den anden men ikke begge". F.eks kan din mor sige: "Til dessert kan du få is eller kage" Hun mente ikke at du kunne få begge dele. En computer derimod, bruger 'or' i betydningen "den ene eller den anden, eller begge". (En anden måde at sige det på er "mindst en af disse er sand"). Computere er sjovere end mødre.


 Ting til Afprøvning


* "En elefant kom marcherende.." Skriv et program som printer sangteksten til denne børnesang. Slut ved 10 elefanter.
  "1 elefant(er)  kom marcherende, hen ad  edderkoppens fine spind, fandt at vejen var så interessant, at den byder op endnu en elefant"
  "2 elefant kom ... osv"

*  Skriv et program der hedder "Døve mormor". Ligemeget hvad du siger til mormor (lige meget hvad du skriver) så skal hun svare med: "HVAD SIGER DU, MIN VEN? TAL EN SMULE HØJERE" medmindre du råber det (skriver alt med store bogstaver). Hvis du råber, kan hun høre dig (eller det tror hun i hvert fald) og  hun råber tilbage: "JA DET VAR I 1949". Måske skal det være et tilfældigt år mellem 1930 og 1950. (Den sidste del er valgfri, og vil være meget lettere hvis du har fået læst afsnittet om 'tilfældig tal generator' i slutningen af kapitlet om metoder.) Du kan ikke afslutte programmet før du råber 'FARVEL'.
TIP: Glem ikke 'chomp!' 'FARVEL' med et Enter er ikke det samme som 'BYE' uden.
TIP: Prøv først at tænke på hvilke dele af programmet der skal ske igen og igen. Alle disse skal være i din 'while' loop.

*  Udvid dit "Døve mormor" program: Hvad med at mormor ikke ønsker at du skal gå? Når du råber "FARVEL" vil hun foregive ikke at høre dig. 

*Ændr dit program så man er nødt til at  råbe "FARVEL" 3 gange i streg. Sørg for at teste dit program: hvis du råber "FARVEL" 3 gange men ikke i streg, skal du stadig tale med mormor.

*  Skudår. Skriv et program som spørger efter et start år og et slut år, og som så skriver alle skudår mellem dem (hvis de selv er skudår skal de tages med) Skudår er år der kan deles med 4 (såsom 1984 og 2004). Dog er år delelig med 100 ikke skudår (såsom 1800 og 1900) medmindre de er delelig med 400 (såsom 1600 og 2000 som faktisk var skudår.(Ja det er faktisk ret forvirrende men ikke så forvirrende som at have Juli midt om vinteren, hvad der netop ville ske hvis vi ikke havde indført skudår.

* Når du er færdig med disse kan du tage en pause. Du har allerede lært en masse. Tillykke! Er du overrasket over hvor mange ting du få en computer til at gøre ? Nogle få kapitler mere og du vil være i stand til at programmere alt ligemeget hvad. Seriøst! Se bare på alle de ting du kan gøre nu som du
ikke kunne uden forgrening og looping.

 Lad os nu lære noget om sæt, en ny slags objekter som holder styr på lister af andre objekter.








Af Chris Pine

oversat af Gunner Carstens

Original tekst

Indledning

Kapitel 1 - Tal

Kapitel 2 -Bogstaver

Kapitel 3 Variable og tildelinger

Kapitel 4 Blande det hele sammen

Kapitel 5 Mere om metoder

Kapitel 6 Kontrol med strømmen

Kapitel 7 Sæt og Gentagere

Kapitel 8 Skriv dine egne metoder

Kapitel 9 Klasser

Kapitel 10 Blokke og Procs

Kapitel 11 Hvad nu?