FizzBuzz

Þetta verkefni gengur út á að skrifa lítið forrit sem fer í gegn um (skoðar) talnarunu og prentar texta eða tölu eftir ákveðnum skilyrðum.

  • Ef viðkomandi tala er deilanleg með 3 er prentaður strengurinn Fizz.

  • Sé hún deilanleg með 5 prentast Buzz.

  • Gangi bæði 3 og 5 upp í hana prentast FizzBuzz.

  • En ef hvorki 3 né 5 ganga upp í töluna, þá er talan sjálf prentuð.

Ef tala er deilanleg með einhverri tölu, til dæmis 3, þýðir það að við skipt henni, til dæmis í þrennt, og það verður enginn afgangur. Þetta er klassískt verkefni sem er meira að segja stundum notað í atvinnuviðtölum. Það sem mörgum finnst svo skemmtilegt við þetta verkefni er hversu margar leiðir er hægt að fara til að leysa það. Við munum núna skoða eina leið til að leysa verkefnið með glæsibrag ;)

Í þessu verkefni koma fyrir eftirfarandi þættir:

  • for-lykkja

  • heiltölur

  • strengir

  • if-elif-else setningar

  • stofnleif (e. modulus)

  • tagskipti

Hverju stefnum við að?

Virkni einfaldrar útgáfu þessa forrits gæti litið svona út:

Sláðu inn hæstu töluna: 20
Sláðu inn lægstu töluna: 1
1
2
Fizz
4
Buzz
Fizz
7
8
Fizz
Buzz
11
Fizz
13
14
FizzBuzz
16
17
Fizz
19
Buzz

Hvar eigum við að byrja?

Ef skoðum inngangsorð þessa verkefnis þá sjáum við að þar er talað um talnarunu. Til að fá margar tölur í röð (talnarunu), þá er tilvalið að nota for-lykkju (meira um for-lykkjur í kafla um lykkjur og skilyrðingar).

for-lykkjan

Eins og við vitum þá þurfa for-lykkjur eitthvað til að „endurtaka“ og því ætlum við í þessu dæmi að nota innbyggða fallið range() til þess. Fallið range() þarf minnst eitt inntaksgildi (e. argument) en við ætlum að nota tvö, annað sem upphafstölu og hitt sem endatölu (meira um range() í kafla um innbyggð föll). Lykkjusetningin, þar sem talið er frá 1 og að 20, gæti þá litið svona út:

for tala in range(1, 20):

skilyrtar setningar

Þá er komið að því að skilgreina hvað gerist ef skilyrðum okkar er mætt. Við ætlum að nota reikniaðgerð sem kallast stofnleif (e. modulus) en hún skilar okkur alltaf afganginum.

Dæmi:

10 % 3 = 1 | Vegna þess að 3 gengur þrisvar sinnum upp í 10 (3x3=9) og þá er einn í afgang.

Við erum sem sagt að leita eftir tölum þar sem enginn afgangur er þegar við deilum 3 eða 5.

Hverju erum við að leita eftir?

Nú vitum við að tilvikin sem við erum að leita eftir eru þrjú:

  • Tala er deilanleg með 3 og 5

  • Tala er einungis deilanleg með 3

  • Tala er einungis deilanleg með 5

Þá skulum við raða þessum tilvikum í if og elif setningar. Við látum strangasta/þrengsta skilyrðið koma fyrst í if setningu vegna þess að komi það upp, þá er óþarfi að kanna önnur skilyrði. if setningin gæti þá litið svona út:

for tala in range(1, 20):
    if tala % 3 == 0 and tala % 5 == 0:
        print('FizzBuzz')

Takið eftir and skilyrðingunni í if setningunni, hún gerir okkur kleift að setja tvær skilyrðingar í eina setningu. Við hefðum getað hreiðrað aðra if setningu undir þá fyrri og fengið þannig sömu virkni en það hefði leitt af sér ljótari kóða sem væri ekki eins læsilegur. Það hefði þá litið svona út:

for tala in range(1, 20):
    if tala % 3 == 0:
        if tala % 5 == 0:
            print('FizzBuzz')

Næst skulum við bæta við elif setningum fyrir tilfelli þar sem talan er ekki deilanlega með bæði 3 og 5 en er samt deilanleg með annað hvort 3 eða 5:

for tala in range(1, 20):
    if tala % 3 == 0 and tala % 5 == 0:
        print('FizzBuzz')
    elif tala % 3 == 0:
        print('Fizz')
    elif tala % 5 == 0:
        print('Buzz')

Við megum ekki gleyma að prenta töluna sjálfa í þeim tilfellum sem if og elif setningarnar eiga ekki við. Þá bætum við else setningu í lokinn sem prentar töluna:

for tala in range(1, 20):
    if tala % 3 == 0 and tala % 5 == 0:
        print('FizzBuzz')
    elif tala % 3 == 0:
        print('Fizz')
    elif tala % 5 == 0:
        print('Buzz')
    else:
        print(tala)

Þá er grunnvirkni forritsins komin, fyrst athugar það hvort talan sé bæði deilanleg með 3 og 5, ef ekki, þá hvort talan sé deilanleg með annað hvort 3 eða 5. Ef ekkert af þessu á við þá er talan sjálf prentuð.

Í upphafi verkefnis, þar sem við sáum virknina sem við stefndum að, þá sést forritið spyrja notandann um talnabilið. Við skulum nú bæta þeirri virkni við forritið okkar. Fallið range() tekur inn tvö gildi sem eru annars vegar fyrsta talan og hins vegar talan sem við viljum telja að. Ef við skilgreinum tvær breytur fyrir þessi gildi getum við notað þær sem inntaksgildi (e. argument) fyrir range() fallið. Köllum þar bara l_tala (fyrir „lægri tala“) og h_tala (fyrir „hærri tala“) en þær geta auðvitað heitað hvað sem er. Við gefum þeim ekkert gildi heldur notum input() fallið sem sér um að fá gildi frá notandanum. Forritið okkar gæti því litið svona út:

l_tala = input('Sláðu inn lægstu töluna: ')
h_tala = input('Sláðu inn hæstu töluna: ')

for tala in range(l_tala, h_tala):
    if tala % 3 == 0 and tala % 5 == 0:
        print('FizzBuzz')
    elif tala % 3 == 0:
        print('Fizz')
    elif tala % 5 == 0:
        print('Buzz')
    else:
        print(tala)

Ef við prófum að keyra forritið lendum við í smá vandræðum:

Sláðu inn lægstu töluna: 1
Sláðu inn hæstu töluna: 20
Traceback (most recent call last):
  File "/home/sverrir/py_verkefni/fizzbuzz.py", line 4, in <module>
    for tala in range(l_tala, h_tala):
TypeError: 'str' object cannot be interpreted as an integer

Við sjáum neðst í þessum villuboðum að við fengum tagvillu eða TypeError sem segir okkur að einhvers staðar erum við að nota rangt tag (e. type). Villuboðin vísa einnig í fjórðu línu forritsins og birta jafnframt þá línu:

for tala in range(l_tala, h_tala):

Þessi er villa er vegna þess að fallið range tekur inn heiltölugildi (og ekkert annað!) en þegar við notum fallið input() fáum við alltaf streng.

Ábending - skilagildi input() fallsins er alltaf strengur

Því þurfum við að breyta tagi l_tala og h_tala í heiltölu og við gerum það með fallinu int(). Það skiptir ekki mála hvar við gerum það, við gætum bæði gert það þegar við skilgreinum breyturnar:

h_tala = int(input('Sláðu inn hæstu töluna: '))
l_tala = int(input('Sláðu inn lægstu töluna: '))

Við getum einnig gert það þegar við köllum á range() fallið:

for tala in range(int(l_tala), int(h_tala)):

Þá erum við komin að lokum þessa verkefnis og forritið okkar gæti þá litið einhvernveginn svona út:

h_tala = int(input('Sláðu inn hæstu töluna: '))
l_tala = int(input('Sláðu inn lægstu töluna: '))

for tala in range(l_tala, h_tala):
    if tala % 3 == 0 and tala % 5 == 0:
        print('FizzBuzz')
    elif tala % 3 == 0:
        print('Fizz')
    elif tala % 5 == 0:
        print('Buzz')
    else:
        print(tala)

Munið að prófa að leysa verkefnið án leiðbeininga, skoðið leiðbeiningarnar eftir þörfum. Önnur nálgun við verkefnið getur verið að breyta forritinu í fall. Til að þyngja verkefnið má til dæmis leita leiða til að koma í veg fyrir að forritið hrynji ef notandinn slær ekki inn tölustafi fyrir hæstu eða lægstu tölurnar.

Last updated