Steg 4: flytt på slangen

forrige steg
oversikt
neste steg

I dette steget skal vi la slangen gå ett steg hver gang brukeren trykker på mellomromstasten. Senere skal vi få programmet til å flytte slangen av seg selv; men i utviklingsfasen er det fint å kunne jobbe i «sakte film» og da er det fint å bruke mellomromstasten til å kontrollere tiden.


Steg 4a: utvidelse av modellen

Først må vi utvide modellen vår slik at den inneholder informasjon om slangens lengde og slagehodet sin posisjon. I funksjonen app_started:

En tuple er en liste som ikke kan muteres. De aller fleste ikke-destruktive operasjoner på lister fungerer helt likt for tupler. Les også om tupler i kursnotater om lister.

# Opprett en tuple
pos = (3, 4)
print(pos) # (3, 4)

# "Pakk ut" en tuple i variabler
row, col = pos
print(f'{row} {col}') # 3 4

Når vi er i debug-modus, er det fint om vi kan se verdiene til disse variablene.


Steg 4b: selve forflyttningen
Tilstand før Tilstand etter
før forflyttning etter forflytning

Nå kommer vi til selve forflyttningen; bildene over viser tilstanden før og etter en forflytning i retning «east». Vi oppretter en egen funksjon move_snake(app) for å utføre flyttingen. Denne funksjonen skal utføre følgende:

  1. Oppdater app.head_pos: finn hva som er neste posisjon for slangen sitt hode.
  2. Oppdater app.board: for alle positive verdier, trekk fra 1.
  3. Oppdater app.board: la den nye posisjonen til slangen sitt hode få verdi lik slangen sin størrelse

Det er klokt å skille dette ut som en egen hjelpefunksjon get_next_head_position(head_pos, direction) som returnerer en tuple med rad og kolonne for neste posisjon.

  • I move_snake, gjør et kall til denne hjelpefunksjonen med app.head_pos og app.direction som argumenter.
  • La retur-verdien fra dette funksjonskallet bli den nye verdien til app.head_pos.

I før/etter -bildene over ser vi at verdien app.head_pos endres fra (3, 4) til (3, 5). Den endringen gjør vi her.

Test hjelpefunksjonen din ved å kopiere denne testen inn i snake.py (legg testen inn før kallet til run_app, men etter at funksjonen get_next_head_position er definert)

print("Tester get_next_head_position...", end="")
assert((3, 9) == get_next_head_position((3, 8), "east"))
assert((3, 7) == get_next_head_position((3, 8), "west"))
assert((2, 8) == get_next_head_position((3, 8), "north"))
assert((4, 8) == get_next_head_position((3, 8), "south"))
assert((1, 6) == get_next_head_position((1, 5), "east"))
assert((1, 4) == get_next_head_position((1, 5), "west"))
assert((0, 5) == get_next_head_position((1, 5), "north"))
assert((2, 5) == get_next_head_position((1, 5), "south"))
print("OK")

  • Husk at en tuple (akkurat som en liste) kan «pakkes opp» til individuelle variabler (se kursnotater om lister). For eksempel:
foo = (3, 4) # foo er en tuple med to elementer
x, y = foo   # nå er x lik 3 og y lik 4
  • Benytt if-setninger og sjekk hva direction er. Legg til eller trekk fra 1 på row eller col alt ettersom. Se «test deg selv underveis» over.

Det er klokt å skille også dette ut som en egen hjelpefunksjon subtract_one_from_all_positives(grid) som muterer en 2D-liste med tall gitt som input.

  • I move_snake, gjør et kall til denne hjelpefunksjonen med app.board som argument.

I før/etter -bildene over ser vi at verdien i rute (3, 2) endres fra 1 til 0, verdien i rute (3, 3) endres fra 2 til 1 og verdien i rute (3, 4) endres fra 3 til 2. Disse endringene gjør vi her.

PS: Vi sier at en verdi er positiv dersom den er strengt større enn 0; altså er 0 ikke en positiv verdi.

Test hjelpefunksjonen din ved å kopiere denne testen inn i snake.py (legg testen inn før kallet til run_app, men etter at funksjonen subtract_one_from_all_positives er definert)

print("Tester subtract_one_from_all_positives...", end="")
a = [[2, 3, 0], [1, -1, 2]]
subtract_one_from_all_positives(a)
assert [[1, 2, 0], [0, -1, 1]] == a

b = [[2, 0], [0, -1]]
subtract_one_from_all_positives(b)
assert [[1, 0], [0, -1]] == b
print("OK")

Husk at slangen sin størrelse befinner seg i variabelen app.snake_size.

I før/etter -bildene over ser vi at verdien i ruten (3, 5) endres fra 0 til 3. Den endringen gjør vi her.

  • Har du husket å oppdatere app.head_pos med returverdien fra kallet til get_next_head_position?
  • Slangehodet sin posisjon som rad og kolonne er row, col = app.head_pos.
  • Muter app.board[row][col] slik at verdien blir app.snake_size.

Til slutt gjenstår det å gjøre et kall til move_snake når brukeren trykker på mellomrom.

Du skal nå kunne flytte slangen ved å trykke på mellomrom, og du skal også kunne endre hvilken retning slangen flytter seg ved å benytte piltastene.


Guide til snake av Torstein Strømme er lisensiert under CC-NC-SA 4.0.