Kihagyás

6. gyakorlat

Szerkesztés alatt!

Az oldal további része szerkesztés alatt áll, a tartalma minden további értesítés nélkül többször, gyakran, jelentősen megváltozhat!

Library-k és virtuális környezetek

Csomagkezelés

Egy program futtatásához elég gyakran van szükség előre megírt library-kre, csomagokra. Bizonyos rendszereken ezeket a csomagokat rendszer szinten tudjuk telepíteni. Van viszont a Python-nak egy "saját" csomagkezelője, a pip (vagy pip3), melynek segítségével egyszerűen tudjuk az egyes Python csomagokat telepíteni (már ha a rendszer ezt engedi):

pip csomagkezelő használata
1
2
3
4
pip install PACKAGE
pip list
pip freeze > requirements.txt
pip install -r requirements.txt

A pip install PACKAGE telepíteni fogja a PACKAGE nevű legújabb verzióját, és az összes szükséges függőségét. A pip list listázza az adott környezetben telepített csomagokat. A pip freeze szintén a telepített csomagok neveit és pontos verzióját listázza olyan módon, hogy a kimenetét pl. egy requirements.txt fájlba mentve a pip install -r requirements.txt parancs (egy eredetileg "üres" környezetben kiadva) vissza tudja állítani a pontos környezetet.

Virtuális környezetek

Egy program futtatásához néha egész különleges bolygóegyüttállások szükségesek. Egy adott gépen futtatandó különböző programok különféle library-ket, sőt, azok különböző verzióit használhatják. Ha a gépen központilag telepítjük ezen library-ket, akkor lesz olyan programunk, amely az adott központi környezetben nem tud futni.

A megoldás a virtuális környezetek használata lehet.

A virtuális környezet használata
1
2
3
4
python -m venv VENVNAME
. VENVNAME/bin/activate
# work in the virtual environment
deactivate

A python -m venv VENVNAME parancs létrehoz egy VENVNAME könyvtárat, benne egy virtuális környezetet. (Erre a virtualenv parancs is használható, ha telepítve van.) Ezt a környezetet a . VENVNAME/bin/activate (vagy source VENVNAME/bin/activate) parancs segítségével tudjuk aktiválni Unix típusú rendszerek (Linux/MacOS) alatt, Windows alatt pedig a VENVNAME\Scripts\activate paranccsal. Ezek után bármilyen, a fejlesztői környezetet megváltoztató parancs (pl. pip install) ebben a virtuális környezetben lesz érvényes. A környezetet a deactivate paranccsal tudjuk elhagyni.

Feladat: Virtuális környezet használata

Készíts egy virtuális környezetet, és aktiváld! Telepítsd a rich Python csomagot! Futtasd a következő main_rich.py programot:

1
2
3
4
from rich.console import Console

console = Console()
console.print("Helló, színes Világ!", style="green on blue")

Python hibakezelés

TODO: try, except, finally, else

Tesztelés

Mi a tesztelés?

A tesztelés az a tevékenység, amikor megnézzük, hogy ez elkészített szoftver megfelelően működik-e.

Az előző mondat kezdetnek nem rossz, de nem igaz: a tesztelés ennél sokkal-sokkal több, rengeteg formája, módja, szintje van. Tesztelés (verifikáció) az is, ha az első mondatnak megfelelően egy adott inputra lefuttatom a programomat, és megnézem, hogy a kapott eredmény az-e, amit vártam, de az is, ha átnézem a másik fejlesztő kódját (futtatás nélkül), hogy találok-e hibát valamelyik függvény megvalósításában. Ahogyan a követelményspecifikáció átnézése vagy a követelményeknek megfelelő program éles környezetben való kipróbálása is tesztelési tevékenység (validáció).

Alapelv, hogy a tesztelést minél korábban el kell kezdeni. Egy (szűken értelmezett) programozó esetében ez azt jelenti, hogy a megírt kódot minél hamarabb tesztelni kell, még akár az előtt, hogy a szoftver többi része is elkészülne. Vagyis, amint a szoftver egy részével, önálló egységével (ami a mi esetünkben most függvényt fog jelenteni, de lehetne akár osztály is) elkészülünk, azt -- a szoftver többi egységétől függetlenül -- le kell tesztelni. Ez az egységteszt, és ez programozói feladat (merthogy például egy függvény teszteléséhez kódra van szükség, olyan kódra, ami meghívja a függvényt és ellenőrzi az eredményét).

Ahhoz viszont, hogy a szoftver megfelelő legyen, ezeknek az egységeknek nem csak önmagukban kell jól működniük, hanem más egységekkel is megfelelően kell együttműködniük. Ezt szintén le kell ellenőrizni, úgynevetezz egység-integrációs tesztek segítségével. Ez még szintén eléggé forrásközeli dolog, tehát általában programozói feladat.

Az egység és egység-integrációs tesztelés között a gyakorlatban nincs éles határvonal. A valódi egységtesztekre rendkívül szigorú (elméleti) elkülönítési szabályok vonatkoznak, amiket a gyakorlatban egész egyszerűen nem mindig éri meg betartani.

Egységteszt keretrendszerek

Bárki tud olyan programot írni, amely meghív egy függvényt, és leellenőrzi annak visszatérési értéket; vagyis bárki tud egységtesztet készíteni. De ha rengeteg tesztelendő egységünk (függvényünk) van, akkor ez a program nagyon sok dolgot kell, hogy csináljon, a bővítése, módosítása igencsak nehézkessé válhat. Erre a problémára találták ki az egységteszt keretrendszereket. Ezek olyan library-k, amelyek lehetővé teszik a fejlesztő/tesztelő számára, hogy a lényegre, azaz a tesztesetek megírására koncentráljanak, az olyan dolgokat pedig, mint a tesztesetek összegyűjtése, lefuttatása, az eredmények összegyűjtése és mindenféle fancy riportok generálása, már egységesen a keretrendszer adja.

Különböző nyelvekhez különböző keretrendszerek vannak, Java-hoz például a JUnit, C-hez a CUnit, C++-hoz a cppunit vagy a gtest. Python-hoz többek között a unittest és pytest modulok használhatók. Utóbbi könnyen használható objektumorientált programozás nélkül is, ezért most ezzel fogunk kicsit jobban megismerkedni.

Pytest

A pytest modult a pip install pytest paranccsal lehet telepíteni, telepítés után pedig a python -m pytest paranccsal lehet futtatni. A parancs futtatása után a pytest megkeresi a test_AKÁRMI nevű függvényeket, és ezeket egységtesztként lefuttatja. Az ilyen függvényekben kell, hogy legyen (legalább) egy assert utasítás, ami a teszt ellenőrzését végzi. Ha ennek az utasításnak az argumentuma hamis(ra értékelődik ki), akkor a teszt "bukik" vagy "törik"; ezt a pytest észleli és megjegyzi, az összes teszt lefuttatása után pedig egy riportot kapunk arról, hogy hány teszt és milyen eredményekkel (pass, fail, error) lett futtatva.

Ha a pytest egy fájlt kap paraméterként, akkor ebben keresi a tesztfüggvényeket. Ha egy mappát kap, akkor ebben keresi a test_*.py nevű fájlokat, és ezekben a tesztfüggvényeket. Ha nem kap paramétert, akkor a test nevű mappában kezd el keresgélni.

Feladat: készíts teszteket a chess modulhoz

Adott a következő -- fejlesztés alatt álló, nem kész -- chess python package:

chess/init.py
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
"""
Szoftverfesztelési folyamatok példaprogram
SZTE TTIK, Informatikai Intézet, Szoftverfejlesztés Tanszék
cc-by-nc-nd

A chess package __init__.py fájlja.
"""

from . import constants
from . import board
from . import figures
chess/board.py
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
"""
Szoftverfesztelési folyamatok példaprogram
SZTE TTIK, Informatikai Intézet, Szoftverfejlesztés Tanszék
cc-by-nc-nd

A chess package board modulja.
"""

from . import constants

from rich.console import Console

"""
Új tábla létrehozása, melyen a bábuk a kezdőállásnak megfelelően állnak.
"""
def new_default_table():
    return [
        [{'fig':constants.FROOK, 'col':constants.CLGT},{'fig':constants.FPAWN, 'col':constants.CLGT},{'fig':None, 'col':None},{'fig':None, 'col':None},{'fig':None, 'col':None},{'fig':None, 'col':None},{'fig':constants.FPAWN, 'col':constants.CDRK},{'fig':constants.FROOK, 'col':constants.CDRK}],
        [{'fig':constants.FKNGT, 'col':constants.CLGT},{'fig':constants.FPAWN, 'col':constants.CLGT},{'fig':None, 'col':None},{'fig':None, 'col':None},{'fig':None, 'col':None},{'fig':None, 'col':None},{'fig':constants.FPAWN, 'col':constants.CDRK},{'fig':constants.FKNGT, 'col':constants.CDRK}],
        [{'fig':constants.FBSHP, 'col':constants.CLGT},{'fig':constants.FPAWN, 'col':constants.CLGT},{'fig':None, 'col':None},{'fig':None, 'col':None},{'fig':None, 'col':None},{'fig':None, 'col':None},{'fig':constants.FPAWN, 'col':constants.CDRK},{'fig':constants.FBSHP, 'col':constants.CDRK}],
        [{'fig':constants.FQUEN, 'col':constants.CLGT},{'fig':constants.FPAWN, 'col':constants.CLGT},{'fig':None, 'col':None},{'fig':None, 'col':None},{'fig':None, 'col':None},{'fig':None, 'col':None},{'fig':constants.FPAWN, 'col':constants.CDRK},{'fig':constants.FQUEN, 'col':constants.CDRK}],
        [{'fig':constants.FKING, 'col':constants.CLGT},{'fig':constants.FPAWN, 'col':constants.CLGT},{'fig':None, 'col':None},{'fig':None, 'col':None},{'fig':None, 'col':None},{'fig':None, 'col':None},{'fig':constants.FPAWN, 'col':constants.CDRK},{'fig':constants.FKING, 'col':constants.CDRK}],
        [{'fig':constants.FBSHP, 'col':constants.CLGT},{'fig':constants.FPAWN, 'col':constants.CLGT},{'fig':None, 'col':None},{'fig':None, 'col':None},{'fig':None, 'col':None},{'fig':None, 'col':None},{'fig':constants.FPAWN, 'col':constants.CDRK},{'fig':constants.FBSHP, 'col':constants.CDRK}],
        [{'fig':constants.FKNGT, 'col':constants.CLGT},{'fig':constants.FPAWN, 'col':constants.CLGT},{'fig':None, 'col':None},{'fig':None, 'col':None},{'fig':None, 'col':None},{'fig':None, 'col':None},{'fig':constants.FPAWN, 'col':constants.CDRK},{'fig':constants.FKNGT, 'col':constants.CDRK}],
        [{'fig':constants.FROOK, 'col':constants.CLGT},{'fig':constants.FPAWN, 'col':constants.CLGT},{'fig':None, 'col':None},{'fig':None, 'col':None},{'fig':None, 'col':None},{'fig':None, 'col':None},{'fig':constants.FPAWN, 'col':constants.CDRK},{'fig':constants.FROOK, 'col':constants.CDRK}]
    ]

"""
Új, üres tábla létrehozása.
"""
def new_empty_table():
    return [
        [{'fig':None, 'col':None},{'fig':None, 'col':None},{'fig':None, 'col':None},{'fig':None, 'col':None},{'fig':None, 'col':None},{'fig':None, 'col':None},{'fig':None, 'col':None},{'fig':None, 'col':None}],
        [{'fig':None, 'col':None},{'fig':None, 'col':None},{'fig':None, 'col':None},{'fig':None, 'col':None},{'fig':None, 'col':None},{'fig':None, 'col':None},{'fig':None, 'col':None},{'fig':None, 'col':None}],
        [{'fig':None, 'col':None},{'fig':None, 'col':None},{'fig':None, 'col':None},{'fig':None, 'col':None},{'fig':None, 'col':None},{'fig':None, 'col':None},{'fig':None, 'col':None},{'fig':None, 'col':None}],
        [{'fig':None, 'col':None},{'fig':None, 'col':None},{'fig':None, 'col':None},{'fig':None, 'col':None},{'fig':None, 'col':None},{'fig':None, 'col':None},{'fig':None, 'col':None},{'fig':None, 'col':None}],
        [{'fig':None, 'col':None},{'fig':None, 'col':None},{'fig':None, 'col':None},{'fig':None, 'col':None},{'fig':None, 'col':None},{'fig':None, 'col':None},{'fig':None, 'col':None},{'fig':None, 'col':None}],
        [{'fig':None, 'col':None},{'fig':None, 'col':None},{'fig':None, 'col':None},{'fig':None, 'col':None},{'fig':None, 'col':None},{'fig':None, 'col':None},{'fig':None, 'col':None},{'fig':None, 'col':None}],
        [{'fig':None, 'col':None},{'fig':None, 'col':None},{'fig':None, 'col':None},{'fig':None, 'col':None},{'fig':None, 'col':None},{'fig':None, 'col':None},{'fig':None, 'col':None},{'fig':None, 'col':None}],
        [{'fig':None, 'col':None},{'fig':None, 'col':None},{'fig':None, 'col':None},{'fig':None, 'col':None},{'fig':None, 'col':None},{'fig':None, 'col':None},{'fig':None, 'col':None},{'fig':None, 'col':None}]
    ]

"""
A kapott tábla és a rajta lévő állás kirajzolása a konzolra.
"""
def print_board(board, con=Console()):
    con.print("   A B C D E F G H  ", style="bold cyan on black")
    for r in range(7, -1, -1):
        con.print(f"{r+1} ", style="bold cyan on black", end='')
        for c in range(0, 8):
            black = (r + c) % 2
            samec = board[c][r]['col'] == (constants.CDRK if black else constants.CLGT)
            cc = 'black' if black else 'white'
            fc = 'white' if black else 'black'
            match board[c][r]['fig']:
                case constants.FPAWN:
                    fg = f"{constants.CSPAWN if samec else constants.CIPAWN} "
                case constants.FKNGT:
                    fg = f"{constants.CSKNGT if samec else constants.CIKNGT} "
                case constants.FBSHP:
                    fg = f"{constants.CSBSHP if samec else constants.CIBSHP} "
                case constants.FROOK:
                    fg = f"{constants.CSROOK if samec else constants.CIROOK} "
                case constants.FQUEN:
                    fg = f"{constants.CSQUEN if samec else constants.CIQUEN} "
                case constants.FKING:
                    fg = f"{constants.CSKING if samec else constants.CIKING} "
                case _:
                    fg = '  '
            con.print(f"{fg}", style=f"{fc} on {cc}", end='')
        con.print(f" {r+1}", style="bold cyan on black")
    con.print("  A B C D E F G H", style="bold cyan on black")
chess/constants.py
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
"""
Szoftverfesztelési folyamatok példaprogram
SZTE TTIK, Informatikai Intézet, Szoftverfejlesztés Tanszék
cc-by-nc-nd

A chess package contants modulja.

A sakk megvalósításában használt konstansok:

F....  : A táblán egy figura
C...   : A táblán egy figura színe
CS.... : A konzolra kirajzolandó karakter, ha a mező és a figura színe egyezik
CI.... : A konzolra kirajzolandó karakter, ha a mező és a figura színe eltér
"""

FPAWN = 1
FKNGT = 2
FBSHP = 3
FROOK = 4
FQUEN = 5
FKING = 6

CLGT = 11
CDRK = 12

CSKING = '♔'
CSQUEN = '♕'
CSROOK = '♖'
CSBSHP = '♗'
CSKNGT = '♘'
CSPAWN = '♙'
CIKING = '♚'
CIQUEN = '♛'
CIROOK = '♜'
CIBSHP = '♝'
CIKNGT = '♞'
CIPAWN = '♟'
chess/figures.py
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
"""
Szoftverfesztelési folyamatok példaprogram
SZTE TTIK, Informatikai Intézet, Szoftverfejlesztés Tanszék
cc-by-nc-nd

A chess package figures modulja.

A modul legfőbb feladata (egyelőre) az egyes bábukhoz tartozó helyes lépések ellenőrzése.
"""

from . import constants

"""
Az aktuális ellenfél színe.
"""
def opponent(ply):
    constants.CDRK if ply == constants.CLGT else constants.CLGT

"""
Egy mező fenyegetve van-e a ply játékos valamely bábuja által.
TODO
"""
def threatened_by(pos, ply):
    return False

"""
Sakktábla pozíció (pl. 'c6') koordinátákká konvertálása (pl. (2,5)).
"""
def p2c(pos):
    c, r = pos
    if 'a' <= c <= 'h':
        c = ord(c) - ord('a')
    else:
        raise ValueError(f"Wrong column: {c}")
    if '1' <= r <= '8':
        r = ord(r) - ord('1')
    else:
        raise ValueError(f"Wrong row: {r}")
    return c, r

"""
Koordináták (pl. 2, 5) sakktábla pozícióvá (pl. 'c6') konvertálása.
"""
def c2p(c, r):
    return f"{chr(c+ord('a'))}{chr(r+ord('1'))}"

"""
Segédfüggvény, egy szám előjele.
"""
def sign(val):
    return 1 if val > 0 else -1 if val < 0 else 0

"""
Gyalog mozgása helyes-e?
A világos gyalog 2->8 irányban, a sötét gyalog 7->1 irányban tud mozogni.
- A gyalog egyet léphet előre szabad mezőre.
- A kezdősorból (2. a világosnak és 7. a sötétnek) kettőt is előreléphet szabad mezőre, ilyenkor
  az ellenfélnek en-passant-ra van lehetősége az "átugrott", szintén üres mezőn, így ezt a mezőt kell visszaadni.
- A gyalog átlósan előre egyet lépve ütheti az ellenfél ott álló bábuját.
- En-passant lehetőség esetén a gyalog egyet átlósan előre lépve a megadott üres mezőre érkezhet.
"""
def valid_move_pawn(board, spos, epos, *, enpassant=None):
    sc, sr = p2c(spos)
    ec, er = p2c(epos)
    if board[sc][sr]['fig'] != constants.FPAWN:
        return False
    if sc == ec:
        if board[sc][sr]['col'] == constants.CLGT:
            if board[sc][sr+1]['fig'] is None:
                if er == sr+1:
                    return True
                if sr == 2 and er == 4 and board[sc][er]['fig'] is None:
                    return c2p(sc, 3)
        else:
            if board[sc][sr-1]['fig'] is None:
                if er == sr-1:
                    return True
                elif er == 7 and er == 5 and board[sc][er]['fig'] is None:
                    return c2p(sc, 6)
        return False
    if ec != sc-1 and ec != sc+1:
        return False
    if board[sc][sr]['col'] == constants.CLGT:
        if er == sr+1 and board[ec][er]['fig'] is not None and board[sc][sr]['col'] == constants.CDRK:
            return True
        return epos == enpassant
    else:
        if er == sr-1 and board[ec][er]['fig'] is not None and board[sc][sr]['col'] == constants.CLGT:
            return True
        return epos == enpassant
    return False

"""
Huszár mozgása helyes-e?
A huszár egyik irányba kettőt, másik irányba egyet mozdulva léphet vagy üthet, függetlenül attól, hogy
volt-e az útjában másik bábu.
"""
def valid_move_knight(board, spos, epos):
    sc, sr = p2c(spos)
    ec, er = p2c(epos)
    if board[sc][sr]['fig'] != constants.FKNGT:
        return False
    return ((abs(sc-ec) == 1 and abs(sr-er) == 2) or (abs(sc-ec) == 2 and abs(sr-er) == 1))

"""
A futó átlósan (mindig azonos színű mezőn) mozogva léphet vagy üthet, de bábut nem ugorhat át.
"""
def valid_move_bishop(board, spos, epos):
    sc, sr = p2c(spos)
    ec, er = p2c(epos)
    if board[sc][sr]['fig'] != constants.FBSHP:
        return False
    if abs(sc-ec) != abs(sr-er):
        return False
    dc, dr = sign(ec-sc), sign(er-sr)
    for i in range(1, abs(max(ec-sc, er-sr))):
        if board[sc + dc * i][sr + dr * i]['fig'] is not None:
            return False
    return True

"""
A bástya sorban vagy oszlopban egyenesen mozogva léphet vagy üthet, de bábut nem ugorhat át.
"""
def valid_move_rook(board, spos, epos):
    sc, sr = p2c(spos)
    ec, er = p2c(epos)
    if board[sc][sr]['fig'] != constants.FROOK:
        return False
    if sc != ec and sr != er:
        return False
    dc, dr = sign(ec-sc), sign(er-sr)
    for i in range(1, max(abs(ec-sc), abs(er-sr))):
        if board[sc + dc * i][sr + dr * i]['fig'] is not None:
            return False
    return True

"""
A vezér futóként vagy bástyaként, azaz átlósan, sorban vagy oszlopban mozoghat vagy üthet,
de bábut nem ugorhat át.
"""
def valid_move_queen(board, spos, epos):
    sc, sr = p2c(spos)
    ec, er = p2c(epos)
    if board[sc][sr]['fig'] != constants.FQUEN:
        return False
    if sc != ec and sr != er and abs(sc-ec) != abs(sr-er):
        return False
    dc, dr = sign(ec-sc), sign(er-sr)
    for i in range(1, abs(max(ec-sc, er-sr))):
        if board[sc + dc * i][sr + dr * i]['fig'] is not None:
            return False
    return True

"""
A kirány a 8 szomszédos mező valamelyikére léphet, ha azt nem fenyegeti az ellenfél egyetlen bábuja sem.
"""
def valid_move_king(board, spos, epos):
    sc, sr = p2c(spos)
    ec, er = p2c(epos)
    if board[sc][sr]['fig'] != constants.FKING:
        return False
    if abs(sc-ec) > 1 or abs(sr-er) > 1 or (sc == ec and sr == er):
        return False
    if threatened_by(epos, opponent(board[sc][sr]['col'])):
        return False
    return True

"""
A sáncoláskor, ha sem a király, sem a sáncoláshoz használt bástya nem mozdult még el
a kiinduló helyéről a játék során, és a kettő között minden mező üres, és sem a királyt,
sem a mellette az adott bástya irányában lévő két mezőt nem fenyegeti az ellenfél, akkor
A királyt két mezővel a bástya felé mozgathatjuk, a bástya pedig a királyt átugorva a
király által "átlépett" mezőre kerül.
"""
def valid_move_castling(board, spos, epos, *, king_moved=True, rook_a_moved=True, rook_h_moved=True):
    sc, sr = p2c(spos)
    ec, er = p2c(epos)
    if king_moved or rook_a_moved or rook_h_moved or sc != 5 or sr != 1 or sr != 8 or sr != er or board[sc][sr]['fig'] != constants.FKING or board[ec][sr]['fig'] is not None or threatened_by(c2p(ec, er), opponent(board[sc][sr]['col'])):
        return False
    if ec == 7:
        return board[6][sr]['fig'] is None and not threatened_by(c2p(6, sr), opponent(board[sc][sr]['col'])) and board[8][sr]['col'] == board[sc][sr]['col'] and board[8][sr]['fig'] == constants.FROOK
    elif ec == 3:
        return board[4][sr]['fig'] is None and not threatened_by(c2p(4, sr), opponent(board[sc][sr]['col'])) and board[1][sr]['col'] == board[sc][sr]['col'] and board[1][sr]['fig'] == constants.FROOK
    return False

Adott továbbá a csomaghoz pár kezdeti teszt:

test/test_figures.py
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
"""
Szoftverfesztelési folyamatok példaprogram
SZTE TTIK, Informatikai Intézet, Szoftverfejlesztés Tanszék
cc-by-nc-nd

A chess package figures moduljának egységtesztjei.
"""

import chess

def test_c2p():
    assert chess.figures.c2p(0, 0) == "a1"
    assert chess.figures.c2p(7, 7) == "h8"

def test_p2c():
    assert chess.figures.p2c("a8") == (0,7)
    assert chess.figures.p2c("h1") == (7,0)

def test_valid_move_rook_valid_free_col():
    table = chess.board.new_empty_table()
    table[3][3]= {'fig': chess.constants.FROOK, 'col': chess.constants.CLGT}
    assert chess.figures.valid_move_rook(table, 'd4', 'd6')

def test_valid_move_rook_valid_free_row():
    table = chess.board.new_empty_table()
    table[3][3]= {'fig': chess.constants.FROOK, 'col': chess.constants.CLGT}
    assert chess.figures.valid_move_rook(table, 'd4', 'b4')

def test_valid_move_rook_invalid_free():
    table = chess.board.new_empty_table()
    table[3][3]= {'fig': chess.constants.FROOK, 'col': chess.constants.CLGT}
    assert chess.figures.valid_move_rook(table, 'd4', 'g6') is False

def test_valid_move_rook_valid_capture():
    table = chess.board.new_empty_table()
    table[3][3]= {'fig': chess.constants.FROOK, 'col': chess.constants.CLGT}
    table[3][6]= {'fig': chess.constants.FROOK, 'col': chess.constants.CDRK}
    assert chess.figures.valid_move_rook(table, 'd4', 'd7')

def test_valid_move_rook_invalid_cannot_capture_self():
    table = chess.board.new_empty_table()
    table[3][3]= {'fig': chess.constants.FROOK, 'col': chess.constants.CLGT}
    table[3][6]= {'fig': chess.constants.FROOK, 'col': chess.constants.CLGT}
    assert chess.figures.valid_move_rook(table, 'd4', 'd7') is False
def test_valid_move_rook_invalid_blocked_path():
    table = chess.board.new_empty_table()
    table[3][3]= {'fig': chess.constants.FROOK, 'col': chess.constants.CLGT}
    table[3][6]= {'fig': chess.constants.FROOK, 'col': chess.constants.CLGT}
    assert chess.figures.valid_move_rook(table, 'd4', 'd8') is False

Először futtasd a teszteket a python -m pytest paranccsal! Milyen eredménnyel futottak a tesztek?

Készíts további teszteket a chess.figures modul függvényeinek tesztelésére! Próbáld meg kijavítani a modult, ha a tesztek alapján hibás!