Rochambeau

Deze pagina bevat uitvoerbare code.

Opdracht: Rochambeau

De opgave vraagt één potje steen, papier en schaar: de gebruiker kiest een wapen, de computer kiest er willekeurig een, en het programma drukt af wie er wint.

Deze uitwerking blijft bij die drie wapens en speelt eerlijk. Koos jij andere wapens, of maakte je een spel waarin de speler altijd wint - de opgave geeft je die ruimte - dan is jouw programma daarom niet fout. Kijk in dat geval naar de opbouw hieronder en niet naar de woorden.

Op één regel na gebruikt de uitwerking alleen wat je deze week hebt gezien: input, print, if, elif, else en ==. Die ene regel is from random import choice uit de begincode, en die is met opzet een vooruitwijzing: neem hem voor nu aan. Hij haalt de functie choice op, die een willekeurig element uit een lijst kiest. Wat een module en een import precies zijn, komt in week 3.

Het commentaar uit de begincode staat hieronder niet, omdat de uitleg boven elk programma staat - in je eigen code mag je het gerust laten staan.

De cellen hieronder vragen om invoer en worden daarom niet uitgevoerd bij het maken van deze pagina. Wil je ze zien draaien, kopieer ze dan naar je eigen bestand.

De uitwerking

Het gaat om negen combinaties: drie keuzes van jou maal drie van de computer. Die negen hoef je niet stuk voor stuk op te schrijven, als je de vragen in de goede volgorde stelt.

Stel eerst de makkelijkste vraag: koos de computer hetzelfde als jij? Dan is het gelijkspel en valt er verder niets te vergelijken. Daarmee liggen drie van de negen combinaties al vast.

Blijft over: de computer koos iets anders dan jij. Dan bepaalt wat de computer koos welke ene vraag er nog overblijft. Koos de computer steen, dan heb jij papier of schaar - schaar verliest van steen, en anders heb je papier en win je. Zo houd je drie takken over met elk één vraag erin.

De laatste tak is elif comp == "schaar": en geen else:. Allebei mag: comp komt uit choice en kan alleen steen, papier of schaar zijn, dus wie hier aankomt heeft schaar. Met de naam erbij lees je in alle drie de takken waar het over gaat.

from random import choice

user = input("Kies een wapen (steen, papier of schaar): ")
comp = choice(["steen", "papier", "schaar"])

print("De gebruiker (jij) koos", user)
print("De computer (ik) koos", comp)

if comp == user:
    print("Gelijkspel!")
elif comp == "steen":
    if user == "schaar":
        print("Steen verslaat schaar, ik win!")
    else:
        print("Papier verslaat steen, jij wint!")
elif comp == "papier":
    if user == "steen":
        print("Papier verslaat steen, ik win!")
    else:
        print("Schaar verslaat papier, jij wint!")
elif comp == "schaar":
    if user == "papier":
        print("Schaar verslaat papier, ik win!")
    else:
        print("Steen verslaat schaar, jij wint!")

Twee andere vormen

Dezelfde uitwerking is op meer manieren op te schrijven, en schreef je een van de twee hieronder, dan deed je het goed: alle drie de programma’s stellen dezelfde vragen en geven op elke combinatie hetzelfde antwoord.

Waarin ze verschillen is hoeveel ze hardop zeggen. De vorm hierboven benoemt elk geval apart - steen, papier, schaar - en daarom is het de vorm om nu te schrijven: je leert deze week condities, en dan helpt het als je in de code kunt lezen waar elke tak over gaat. De twee hieronder zeggen minder. De eerste zegt hetzelfde met meer regels, de tweede zegt alles in één voorwaarde.

Alleen met if en else

elif is een afkorting: het is een if binnen de else van de vorige vraag. Schrijf je die afkorting uit, dan krijg je het programma hieronder - dezelfde drie vragen over comp, alleen staat elke volgende vraag nu binnen de else van de vorige.

Daarmee zie je meteen waarvoor de afkorting goed is. Dit programma is vijf regels langer dan het vorige, en zijn diepste regel ligt vijf niveaus naar rechts tegen twee hierboven. Elk wapen dat je erbij zou verzinnen kost er nog een.

from random import choice

user = input("Kies een wapen (steen, papier of schaar): ")
comp = choice(["steen", "papier", "schaar"])

print("De gebruiker (jij) koos", user)
print("De computer (ik) koos", comp)

if comp == user:
    print("Gelijkspel!")
else:
    if comp == "steen":
        if user == "schaar":
            print("Steen verslaat schaar, ik win!")
        else:
            print("Papier verslaat steen, jij wint!")
    else:
        if comp == "papier":
            if user == "steen":
                print("Papier verslaat steen, ik win!")
            else:
                print("Schaar verslaat papier, jij wint!")
        else:
            # "schaar" is de laatste mogelijkheid, dus achter deze if
            # hoeft geen else meer
            if comp == "schaar":
                if user == "papier":
                    print("Schaar verslaat papier, ik win!")
                else:
                    print("Steen verslaat schaar, jij wint!")

Compacter, met and en or

De computer wint bij precies drie van de negen combinaties: steen tegen schaar, papier tegen steen, en schaar tegen papier. Die drie kan je ook in één voorwaarde zetten, met and voor “allebei waar” en or voor “een van beide”. Wint de computer niet en is het geen gelijkspel, dan win jij - daar is geen aparte vraag meer voor nodig.

Haakjes ken je al uit het college, twee keer: als groepering in de operatorentabel, en als het paar om een conditie dat in Python niet verplicht is. Hier doen ze allebei tegelijk. Elk binnenste paar groepeert - het zegt welke twee vergelijkingen bij elkaar horen voordat or ze naast elkaar zet - en het buitenste paar, direct achter elif, doet er iets bij: zolang een haakje nog niet gesloten is, loopt de regel door op de volgende. Zo past de voorwaarde over vier regels in plaats van op één hele lange, en staat de : pas achter het sluithaakje.

Deze vorm is met tien regels de kortste van de drie, en toch niet de vorm om nu te schrijven: nergens staat meer welk geval je te pakken hebt, en om dat te weten moet je de voorwaarde regel voor regel nalopen. Herken haar dus; schrijf haar nog niet. Bij de uitbreiding hieronder verandert die afweging.

from random import choice

user = input("Kies een wapen (steen, papier of schaar): ")
comp = choice(["steen", "papier", "schaar"])

print("De gebruiker (jij) koos", user)
print("De computer (ik) koos", comp)

if comp == user:
    print("Gelijkspel!")
elif (
    (comp == "steen" and user == "schaar")
    or (comp == "papier" and user == "steen")
    or (comp == "schaar" and user == "papier")
):
    print("Ik win!")
else:
    print("Jij wint!")

Uitbreidingen

RPS-5 (RPSSL)

Met vijf wapens gaat het om vijfentwintig combinaties, en verslaat elk wapen er precies twee: steen verslaat schaar en hagedis, papier verslaat steen en Spock, schaar verslaat papier en hagedis, Spock verslaat schaar en steen, en hagedis verslaat papier en Spock.

Hier verandert de afweging. De opzet blijft dezelfde - eerst gelijkspel, dan de gevallen waarin de computer wint, en anders win jij - maar de drie vormen groeien niet even hard mee. Elk geval benoemen kost nu vijf takken en 27 regels; met alleen if en else word je 32 regels lang en zeven niveaus diep. De compacte voorwaarde groeit van tien regels naar twaalf, met per regel één wapen. Dát is waar zij voor is: het punt waarop benoemen niet meer betaalt.

Spock schrijf je met een hoofdletter, in de code en in je invoer. De opgave zegt erbij dat je mag aannemen dat de gebruiker foutloos typt; spock met een kleine letter komt er dus niet door.

from random import choice

user = input("Kies een wapen (steen, papier, schaar, Spock of hagedis): ")
comp = choice(["steen", "papier", "schaar", "Spock", "hagedis"])

print("De gebruiker (jij) koos", user)
print("De computer (ik) koos", comp)

if comp == user:
    print("Gelijkspel!")
elif (
    (comp == "steen" and (user == "schaar" or user == "hagedis"))
    or (comp == "papier" and (user == "steen" or user == "Spock"))
    or (comp == "schaar" and (user == "papier" or user == "hagedis"))
    or (comp == "Spock" and (user == "schaar" or user == "steen"))
    or (comp == "hagedis" and (user == "papier" or user == "Spock"))
):
    print("Ik win!")
else:
    print("Jij wint!")

RPS-25 en RPS-101 werken op precies dezelfde manier, maar de voorwaarde groeit mee: bij RPS-25 verslaat elk wapen er twaalf, en dat zijn driehonderd combinaties waarin de computer wint. Die schrijf je niet meer in een if. Je wilt de regels dan náást het programma zetten, in een datastructuur, en daarvoor heb je technieken nodig die verderop in de cursus komen.

De uitbreiding Blijven spelen vraagt een lus (while), en die komt in week 4. Het practicum laat daar zelf twee patronen zien; deze uitwerking stopt bij het spel zelf.