Boter, kaas en eieren + N op een rij…¶
In deze opgave schrijf je acht kleine functies, die allemaal erg op elkaar lijken, die 2D-lijsten in Python verwerken.
De applicatie die we in gedachten hebben is een spelbord waarvan je programma gaat bepalen:
Of er drie op een rij is voor een bepaald karakter (vier functies), en
Of er
nop een rij is voor een bepaald karakter (vier functies die op de vorige vier lijken)
Gegeven code: een 2D-lijst afdrukken en aanmaken¶
Deze twee functies krijg je kant en klaar. Neem ze over in je eigen bestand en voer ze uit; je gebruikt create_array in alle tests hieronder.
# een functie om een 2D-lijst af te drukken
def print_2d(array):
"""Drukt de 2D-lijst array af, met een regel per rij.
Argument: array, een 2D-lijst
Resultaat: None (geen returnwaarde)
"""
n_rows = len(array)
n_cols = len(array[0])
for row_ix in range(n_rows): # n_rows == aantal rijen
for col_ix in range(n_cols): # n_cols == aantal kolommen
print(array[row_ix][col_ix], end=" ")
print()
return None # dit is impliciet aanwezig
# als er geen return-statement aanwezig is
# een paar tests voor print_2d
array = [["X", " ", "O"], ["O", "X", "O"]]
print("2-row, 3-col array is")
print_2d(array)
array = [["X", "O"], [" ", "X"], ["O", "O"], ["O", "X"]]
print("4-row, 2-col array is")
print_2d(array)
# maak een 2D-lijst van een eendimensionale string
def create_array(n_rows, n_cols, s):
"""Geeft een 2D-lijst terug met n_rows rijen en n_cols kolommen.
De gegevens komen uit de string s: eerst de eerste rij vol,
dan de tweede, enzovoort. We testen alleen met genoeg gegevens!
"""
array = []
for _ in range(n_rows):
new_row = []
for _ in range(n_cols):
new_row += [s[0]] # voeg dat karakter toe
s = s[1:] # verwijder het eerste karakter
array += [new_row]
return array
# een paar tests voor create_array:
array = [["X", " ", "O"], ["O", "X", "O"]]
new_array = create_array(2, 3, "X OOXO")
assert new_array == array
print("Is new_array == array? moet True zijn:", new_array == array)
array = [["X", "O"], [" ", "X"], ["O", "O"], ["O", "X"]]
new_array = create_array(4, 2, "XO XOOOX")
assert new_array == array
Gegevensformaat
Merk op dat elke 2D-lijst in deze opgave rijen van losse karakters bevat:
arrayis de 2D-lijst als geheelElk element van
arrayis een rij, en die rij is zelf een lijstElk element van een rij is een string van één karakter
Sterker nog, we beperken ons tot slechts drie strings:
'X', een hoofdletter X,'O', een hoofdletter O,en
' ', het spatieteken (dit is niet de lege string!).
Drie op een rij¶
De eerste vier functies die je gaat schrijven controleren of er drie op een rij is
in een specifieke richting (opgenomen in de functienaam),
voor een specifiek karakter
char,op een specifieke startrij- en kolom:
row_startencol_start, enin een gegeven 2D-lijst
array.
Elk van de functies moet False teruggeven
als er GEEN RUIMTE is voor drie op een rij vanaf de startpositie gegeven door
row_startencol_start(controleer dit eerst!), ofals
row_startofcol_startbuiten de grenzen vanarrayvalt, of(zelfs als er ruimte binnen de grenzen is), als er GEEN drie-op-een-rij-patroon binnen
arrayis die helemaal bestaat uit het karaktercharin de specifieke richting beginnend bij de locatie gegeven doorrow_startencol_start.
Elke functie moet daarentegen True teruggeven
alleen maar als er een drie-op-een-rij-patroon in
arrayis die helemaal bestaat uit het elementcharin de specifieke richting beginnend bij de locatie vanrow_startencol_start.
Voorbeeld¶
Bekijk het volgende patroon, ontworpen voor de richting “oost”. Hier zie je een paar grenscontroles en een voorbeeld van een for-lus:
# voor de functie voor drie op een rij naar het oosten:
n_rows = len(array) # aantal rijen is len(array)
n_cols = len(array[0]) # aantal kolommen is len(array[0])
if row_start >= n_rows:
return False # buiten de grenzen van de rijen
# andere grenscontroles...
if col_start > n_cols - 3:
return False # buiten de grenzen van de kolommen
# zijn alle gegevenselementen correct?
for ix in range(3): # lusindex is ix
if array[row_start][col_start + ix] != char: # controleer op fouten
return False # fout gevonden; geef False terug
return True # geen fouten gevonden in de lus; geef True terug
Merk op dat voor andere richtingen
Je andere controles nodig hebt (om te kijken of je niet uit de grenzen loopt).
Ook moet je de lus aanpassen voor andere richtingen
Het voorbeeld hierboven kijkt alleen naar drie op een rij in oostelijke richting.
Opdracht 1¶
Schrijf in_a_row_3_east(char, row_start, col_start, array). Deze moet bij row_start en col_start beginnen, kijken of er een drie op een rij van karakter char is in oostelijke richting en een toepasselijke True of False teruggeven.
Als je functie klopt, slagen deze tests zonder foutmelding:
# tests voor in_a_row_3_east
array = create_array(3, 4, "XXOXXXOOOOOO")
assert not in_a_row_3_east("X", 0, 0, array)
assert in_a_row_3_east("O", 2, 1, array)
assert not in_a_row_3_east("X", 2, 1, array)
assert not in_a_row_3_east("O", 2, 2, array)
# jouw oplossing
def in_a_row_3_east(char, row_start, col_start, array):
"""Geeft True terug als er vanaf (row_start, col_start) drie keer char naar het oosten staat."""
...
Opdracht 2¶
Schrijf in_a_row_3_south(char, row_start, col_start, array). Deze moet bij row_start en col_start beginnen, kijken of er een drie op een rij van karakter char is in zuidelijke richting en een toepasselijke True of False teruggeven.
Als je functie klopt, slagen deze tests zonder foutmelding:
# tests voor in_a_row_3_south
array = create_array(4, 4, "XXOXXXOXXOO OOOX")
assert in_a_row_3_south("X", 0, 0, array)
assert not in_a_row_3_south("O", 2, 2, array)
assert not in_a_row_3_south("X", 1, 3, array)
assert not in_a_row_3_south("O", 42, 42, array)
# jouw oplossing
def in_a_row_3_south(char, row_start, col_start, array):
"""Geeft True terug als er vanaf (row_start, col_start) drie keer char naar het zuiden staat."""
...
Opdracht 3¶
Schrijf in_a_row_3_southeast(char, row_start, col_start, array). Deze moet bij row_start en col_start beginnen, kijken of er een drie op een rij van karakter char is in zuidoostelijke richting en een toepasselijke True of False teruggeven.
Als je functie klopt, slagen deze tests zonder foutmelding:
# tests voor in_a_row_3_southeast
array = create_array(4, 4, "XOOXXXOXX XOOOOX")
assert in_a_row_3_southeast("X", 1, 1, array)
assert not in_a_row_3_southeast("X", 1, 0, array)
assert in_a_row_3_southeast("O", 0, 1, array)
assert not in_a_row_3_southeast("X", 2, 2, array)
# jouw oplossing
def in_a_row_3_southeast(char, row_start, col_start, array):
"""Geeft True terug als er vanaf (row_start, col_start) drie keer char naar het zuidoosten staat."""
...
Opdracht 4¶
Schrijf in_a_row_3_northeast(char, row_start, col_start, array). Deze moet bij row_start en col_start beginnen, kijken of er een drie op een rij van karakter char is in noordoostelijke richting en een toepasselijke True of False teruggeven.
Als je functie klopt, slagen deze tests zonder foutmelding:
# tests voor in_a_row_3_northeast
array = create_array(4, 4, "XOXXXXOXXOXOOOOX")
assert in_a_row_3_northeast("X", 2, 0, array)
assert in_a_row_3_northeast("O", 3, 0, array)
assert not in_a_row_3_northeast("O", 3, 1, array)
assert not in_a_row_3_northeast("X", 3, 3, array)
# jouw oplossing
def in_a_row_3_northeast(char, row_start, col_start, array):
"""Geeft True terug als er vanaf (row_start, col_start) drie keer char naar het noordoosten staat."""
...
Deze functies kunnen gecombineerd worden om elke drie op een rij op een spelbord te herkennen, bijvoorbeeld voor Boter, Kaas en Eieren. Je gaat hierna meer algemene versies hiervan maken…
Van 3 naar N: N op een rij¶
Leerdoel: je kunt een werkende oplossing generaliseren. Je hebt nu zelf vier functies geschreven die drie op een rij vinden. Hieronder staat wat de N-versies moeten doen, en verder niets: geen sjabloon en geen half ingevulde functie. Wat er verandert aan de grenscontrole, wat hetzelfde blijft en wat er met de vier richtingen gebeurt, zoek je zelf uit. Dat uitzoeken is de opdracht.
Boter, Kaas en Eieren is al lang opgelost! Laten we onbeperkt grote spelborden bekijken…
Om dit te doen, ga je je drie-op-een-rij-functies uitbreiden naar N-op-een-rij-functies.
Elke functie krijgt een extra argument aan het einde, een integer n, die het aantal identieke elementen (gelijk aan char) voorstelt die gevonden moeten worden om True terug te geven.
Als de positie buiten de grenzen valt; of binnen de grenzen, maar alsnog buiten de grenzen valt door de waarde van
n, moet je functieFalseteruggeven.Je functie moet natuurlijk ook
Falseteruggeven als de rij wel binnen de grenzen valt, maar er geen N op een rij is!
Opdracht 5¶
Schrijf in_a_row_n_east(char, row_start, col_start, array, n). Deze moet bij row_start en col_start beginnen, kijken of er een N op een rij van karakter char is in oostelijke richting en een toepasselijke True of False teruggeven.
Als je functie klopt, slagen deze tests zonder foutmelding:
# tests voor in_a_row_n_east
array = create_array(5, 5, "XXOXXXOOOOOOXXXX XXXOOOOO")
assert in_a_row_n_east("O", 1, 1, array, 4)
assert in_a_row_n_east("O", 1, 3, array, 2)
assert not in_a_row_n_east("X", 3, 2, array, 4)
assert in_a_row_n_east("O", 4, 0, array, 5)
# jouw oplossing
def in_a_row_n_east(char, row_start, col_start, array, n):
"""Geeft True terug als er vanaf (row_start, col_start) n keer char naar het oosten staat."""
...
Opdracht 6¶
Schrijf in_a_row_n_south(char, row_start, col_start, array, n). Deze moet bij row_start en col_start beginnen, kijken of er een N op een rij van karakter char is in zuidelijke richting en een toepasselijke True of False teruggeven.
Als je functie klopt, slagen deze tests zonder foutmelding:
# tests voor in_a_row_n_south
array = create_array(5, 5, "XXOXXXOOOOOOXXXXOXXXOOOXO")
assert not in_a_row_n_south("X", 0, 0, array, 5)
assert in_a_row_n_south("O", 1, 1, array, 4)
assert not in_a_row_n_south("O", 0, 1, array, 6)
assert in_a_row_n_south("X", 4, 3, array, 1)
# jouw oplossing
def in_a_row_n_south(char, row_start, col_start, array, n):
"""Geeft True terug als er vanaf (row_start, col_start) n keer char naar het zuiden staat."""
...
Opdracht 7¶
Schrijf in_a_row_n_southeast(char, row_start, col_start, array, n). Deze moet bij row_start en col_start beginnen, kijken of er een N op een rij van karakter char is in zuidoostelijke richting en een toepasselijke True of False teruggeven.
Als je functie klopt, slagen deze tests zonder foutmelding:
# tests voor in_a_row_n_southeast
array = create_array(5, 5, "XOO XXXOXOOOXXXXOXXXOOOXX")
assert in_a_row_n_southeast("X", 1, 1, array, 4)
assert not in_a_row_n_southeast("O", 0, 1, array, 3)
assert in_a_row_n_southeast("O", 0, 1, array, 2)
assert not in_a_row_n_southeast("X", 3, 0, array, 2)
# jouw oplossing
def in_a_row_n_southeast(char, row_start, col_start, array, n):
"""Geeft True terug als er vanaf (row_start, col_start) n keer char naar het zuidoosten staat."""
...
Opdracht 8¶
Schrijf in_a_row_n_northeast(char, row_start, col_start, array, n). Deze moet bij row_start en col_start beginnen, kijken of er een N op een rij van karakter char is in noordoostelijke richting en een toepasselijke True of False teruggeven.
Als je functie klopt, slagen deze tests zonder foutmelding:
# tests voor in_a_row_n_northeast
array = create_array(5, 5, "XOO XXXOXOOOXOXXXOXXXOOXX")
assert in_a_row_n_northeast("X", 4, 0, array, 5)
assert in_a_row_n_northeast("O", 4, 1, array, 4)
assert not in_a_row_n_northeast("O", 2, 0, array, 2)
assert not in_a_row_n_northeast("X", 0, 3, array, 1)
# jouw oplossing
def in_a_row_n_northeast(char, row_start, col_start, array, n):
"""Geeft True terug als er vanaf (row_start, col_start) n keer char naar het noordoosten staat."""
...