From a23d78a6351b30a56fca05a9aad3c8cd727be944 Mon Sep 17 00:00:00 2001 From: Gabriela20103967 <20103967@tafe.wa.edu.au> Date: Wed, 29 May 2024 13:34:40 +0800 Subject: [PATCH 1/6] feat:add the two new files where will be the modularization of the game --- Caterpillar_Game/caterpillarGame.py | 0 Caterpillar_Game/gameDesign.py | 0 2 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 Caterpillar_Game/caterpillarGame.py create mode 100644 Caterpillar_Game/gameDesign.py diff --git a/Caterpillar_Game/caterpillarGame.py b/Caterpillar_Game/caterpillarGame.py new file mode 100644 index 00000000..e69de29b diff --git a/Caterpillar_Game/gameDesign.py b/Caterpillar_Game/gameDesign.py new file mode 100644 index 00000000..e69de29b From a293550cca8f0cf19787630e33f9a8368ecad6ff Mon Sep 17 00:00:00 2001 From: Gabriela20103967 <20103967@tafe.wa.edu.au> Date: Wed, 29 May 2024 15:08:49 +0800 Subject: [PATCH 2/6] feat:modularize the file game Caterpillar into the two files caterpillarGame and gameDesign --- Caterpillar_Game/Caterpillar.py | 113 ------------------ .../__pycache__/gameDesign.cpython-39.pyc | Bin 0 -> 1819 bytes Caterpillar_Game/caterpillarGame.py | 84 +++++++++++++ Caterpillar_Game/gameDesign.py | 48 ++++++++ 4 files changed, 132 insertions(+), 113 deletions(-) delete mode 100644 Caterpillar_Game/Caterpillar.py create mode 100644 Caterpillar_Game/__pycache__/gameDesign.cpython-39.pyc diff --git a/Caterpillar_Game/Caterpillar.py b/Caterpillar_Game/Caterpillar.py deleted file mode 100644 index 4afc8538..00000000 --- a/Caterpillar_Game/Caterpillar.py +++ /dev/null @@ -1,113 +0,0 @@ -import turtle as t -import random as rd - -t.bgcolor('yellow') - -caterpillar = t.Turtle() -caterpillar.shape('square') -caterpillar.speed(0) -caterpillar.penup() -caterpillar.hideturtle() - -leaf = t.Turtle() -leaf_shape = ((0,0),(14,2),(18,6),(20,20),(6,18),(2,14)) -t.register_shape('leaf', leaf_shape) -leaf.shape('leaf') -leaf.color('green') -leaf.penup() -leaf.hideturtle() -leaf.speed() - -game_started = False -text_turtle = False -text_turtle = t.Turtle() -text_turtle.write('Press SPACE to start', align='center', font=('Arial', 18, 'bold')) -text_turtle.hideturtle() - -score_turtle = t.Turtle() -score_turtle.hideturtle() -score_turtle.speed(0) - -def outside_window(): - left_wall = -t.window_width()/2 - right_Wall = t.window_width()/2 - top_wall = t.window_height()/2 - bottom_wall = -t.window_height()/2 - (x,y) = caterpillar.pos() - outside = x < left_wall or x > right_Wall or y > top_wall or y < bottom_wall - return outside - -def game_over(): - caterpillar.color('yellow') - leaf.color('yellow') - t.penup() - t.hideturtle() - t.write('GAME OVER !', align='center', font=('Arial', 30, 'normal') ) - t.onkey(start_game,'space') - -def display_score(current_score): - score_turtle.clear() - score_turtle.penup() - x = (t.window_width()/2) - 70 - y = (t.window_height()/2) - 70 - score_turtle.setpos(x,y) - score_turtle.write(str(current_score), align='right', font=('Arial', 40, 'bold')) - -def place_leaf(): - leaf.hideturtle() - leaf.setx(rd.randint(-200,200)) - leaf.sety(rd.randint(-200,200)) - leaf.showturtle() - -def start_game(): - global game_started - if game_started: - return - game_started = True - - score = 0 - text_turtle.clear() - - caterpillar_speed = 2 - caterpillar_length = 3 - caterpillar.shapesize(1,caterpillar_length,1) - caterpillar.showturtle() - display_score(score) - place_leaf() - - while True: - caterpillar.forward(caterpillar_speed) - if caterpillar.distance(leaf) < 20: - place_leaf() - caterpillar_length = caterpillar_length + 1 - caterpillar.shapesize(1,caterpillar_length,1) - caterpillar_speed = caterpillar_speed + 1 - score = score + 10 - display_score(score) - if outside_window(): - game_over() - break - -def move_up(): - caterpillar.setheading(90) - -def move_down(): - caterpillar.setheading(270) - -def move_left(): - caterpillar.setheading(180) - -def move_right(): - caterpillar.setheading(0) - -def restart_game(): - start_game() - -t.onkey(start_game,'space') -t.onkey(restart_game,'Up') -t.onkey(move_up,'Up') -t.onkey(move_right,'Right') -t.onkey(move_down,'Down') -t.onkey(move_left,'Left') -t.listen() -t.mainloop() diff --git a/Caterpillar_Game/__pycache__/gameDesign.cpython-39.pyc b/Caterpillar_Game/__pycache__/gameDesign.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..bbb701d231433d27b793d00c6729e1601b390f90 GIT binary patch literal 1819 zcmZuxUvJ|?5a0FxI%zqM9`pc#4k2`w=t)Qj5JIS^h%jexD?m4!Z-6&0! zd%An&J0y?yO%SiV?JH0D3cQq=b>gPgt>xL7*_p9t_BWI5@5c<+JOBKCem`LBUlMkg zi^2)M>N6yQ30|@Rx4ScNpEBVH_caslD`(&d{wqtoHQKSWoapXyP&mO?eThWc7z0Oe z;k;%8SGdB%-4nhDaQ8(hBHRP9hY@2FKg}lcXQ_%&m2-68E{f^ldy2368;NF1F8GRb z;+z#*u+&|!3wP-WhqRXWh1>DLifyzZah+Eryq6rMJ>f6-%CR;PM)5bE(J~f6$8V!V zOB)5h5-m4h=_2+}+iTA|T_1J*&Zoci5e%~q&rC3vWm(Tmp#GR>@} zRIaHIiL<^>JYFL4hq%F>(5lC4j`-W>1J|E?ES%V3Fn}RN- z>E)T0&=h5vf$`NiYb0)sl*0Iptfq~L$AysES_1*e9Dp1Z3cb>ec^k2(<)uzrL(^Az z4RRwTj`5T%&j&I6PwVxD!4U@g@7d}1!)Ho@8cu4+${}Llg|3@njUPW&^%QbBZ034g zSI3j0DvledFJ!KVr#HWy5_X284nR+uxrx#gt#z7G9n=>{7>}Kp_wk7>=ULuLypJbz z8uP37Zh-h?8zUzKZWr+s)FSd5WblR&lN*#-Oj<0lrMuW7l3jQUMD4;A&Yv#F9>d#r z@%D3BVHw{z#?MMbzVXiMN+&)%z_7;8v04D{67P*_T^oM}g_em2ACNAbNTsroG*MHl zLKk%fpP=5BwIvV9EVfQ5T@D>9LJHObpFY2Ou#@eLT~1)zu3PyIQTw)hHTK^MC&x!P zEsoer2W5XprVeGxVBsv>O{cMoP)7^?iql*Wepi*?3<$pKUyv9diqTjnuJM0@A}iOA zN$EYWO93Avo9w~+xWT7Hs7%m9V*0b967?*d6+(~A{ze*0iiM3PHI@q=k)^9NY^&*8 zz#4vO`221O_eG(aGMlH?=5usaeI#ua@9}&5fL|T$RPvVjt#L;EP5D{yoFH?zm{dp_ znX3*uOaCo8JB~ImD!#kEzFz-@!IIE6DA16gj?uVpW~EWyLFSMj-iFML-B}V+&sErjX=>s$oz!Al65mf#oNZ-$0v}>LpbElQ zM7||Lb6|%MYGFI~?YAQyJ&b}Vvf9Kq!DbrKbq@l{uAacxTeqE1HnQ!4=!f=)exw^v JglP=w{11Qzuk-)_ literal 0 HcmV?d00001 diff --git a/Caterpillar_Game/caterpillarGame.py b/Caterpillar_Game/caterpillarGame.py index e69de29b..3a06b51a 100644 --- a/Caterpillar_Game/caterpillarGame.py +++ b/Caterpillar_Game/caterpillarGame.py @@ -0,0 +1,84 @@ +import turtle as t +from gameDesign import GameDesign + +class CaterpillarGame: + def __init__(self): + self.design = GameDesign() + self.game_started = False + self.score = 0 + self.caterpillar_speed = 2 + self.caterpillar_length = 3 + + self.design.write_text('Press Space to start', (0, 0), ('Arial', 18, 'bold')) + + def start_game(self): + if self.game_started: + return + self.game_started = True + + self.score = 0 + self.design.text_turtle.clear() + + self.caterpillar_speed = 2 + self.caterpillar_length = 3 + self.design.caterpillar.shapesize(1, self.caterpillar_length, 1) + self.design.caterpillar.showturtle() + + self.design.display_score(self.score) + self.design.place_leaf() + + self.run_game_loop() + + def run_game_loop(self): + while True: + self.design.caterpillar.forward(self.caterpillar_speed) + if self.design.caterpillar.distance(self.design.leaf) < 20: + self.design.place_leaf() + self.caterpillar_length += 1 + self.design.caterpillar.shapesize(1, self.caterpillar_length, 1) + self.caterpillar_speed += 1 + self.score += 10 + self.design.display_score(self.score) + if self.outside_window(): + self.game_over() + break + + def outside_window(self): + left_wall = -t.window_width() / 2 + right_wall = t.window_width() / 2 + top_wall = t.window_height() / 2 + bottom_wall = -t.window_height() / 2 + (x, y) = self.design.caterpillar.pos() + outside = x < left_wall or x > right_wall or y > top_wall or y < bottom_wall + return outside + + def game_over(self): + self.design.caterpillar.color('yellow') + self.design.leaf.color('yellow') + t.penup() + t.hideturtle() + t.write('Game Over!', align='center', font=('Arial', 30, 'normal')) + t.onkey(self.start_game, 'space') + + def move_up(self): + self.design.caterpillar.setheading(90) + + def move_down(self): + self.design.caterpillar.setheading(270) + + def move_left(self): + self.design.caterpillar.setheading(180) + + def move_right(self): + self.design.caterpillar.setheading(0) + +game = CaterpillarGame() + +t.onkey(game.start_game, 'space') +t.onkey(game.move_up, 'Up') +t.onkey(game.move_right, 'Right') +t.onkey(game.move_down, 'Down') +t.onkey(game.move_left, 'Left') +t.listen() +t.mainloop() + diff --git a/Caterpillar_Game/gameDesign.py b/Caterpillar_Game/gameDesign.py index e69de29b..2ba6b2c3 100644 --- a/Caterpillar_Game/gameDesign.py +++ b/Caterpillar_Game/gameDesign.py @@ -0,0 +1,48 @@ +import turtle as t +import random as rd + +class GameDesign: + def __init__(self): + t.bgcolor('yellow') + + self.caterpillar = t.Turtle() + self.caterpillar.shape('square') + self.caterpillar.speed(0) + self.caterpillar.penup() + self.caterpillar.hideturtle() + + self.leaf = t.Turtle() + leaf_shape = ((0, 0), (14, 2), (18, 6), (20, 20), (6, 18), (2, 14)) + t.register_shape('leaf', leaf_shape) + self.leaf.shape('leaf') + self.leaf.color('green') + self.leaf.penup() + self.leaf.hideturtle() + self.leaf.speed(0) + + self.text_turtle = t.Turtle() + self.text_turtle.hideturtle() + + self.score_turtle = t.Turtle() + self.score_turtle.hideturtle() + self.score_turtle.speed(0) + + def write_text(self, message, position, font): + self.text_turtle.clear() + self.text_turtle.penup() + self.text_turtle.goto(position) + self.text_turtle.write(message, align='center', font=font) + + def display_score(self, score): + self.score_turtle.clear() + self.score_turtle.penup() + x = (t.window_width() / 2) - 70 + y = (t.window_height() / 2) - 70 + self.score_turtle.setpos(x, y) + self.score_turtle.write(str(score), align='right', font=('Arial', 40, 'bold')) + + def place_leaf(self): + self.leaf.hideturtle() + self.leaf.setx(rd.randint(-200, 200)) + self.leaf.sety(rd.randint(-200, 200)) + self.leaf.showturtle() From 8e5cd6a1d37ad3c2250942b10355911063c59b1a Mon Sep 17 00:00:00 2001 From: Gabriela20103967 <20103967@tafe.wa.edu.au> Date: Wed, 29 May 2024 15:32:12 +0800 Subject: [PATCH 3/6] feat:improve the modularization of the game --- .../__pycache__/gameDesign.cpython-39.pyc | Bin 1819 -> 2614 bytes Caterpillar_Game/caterpillarGame.py | 20 +++++++++++------- Caterpillar_Game/gameDesign.py | 12 +++++++++++ 3 files changed, 24 insertions(+), 8 deletions(-) diff --git a/Caterpillar_Game/__pycache__/gameDesign.cpython-39.pyc b/Caterpillar_Game/__pycache__/gameDesign.cpython-39.pyc index bbb701d231433d27b793d00c6729e1601b390f90..193d881c584f5723dddd28cbb6d95509e0fb0ad9 100644 GIT binary patch literal 2614 zcmZ`*&2HO95a#kvG%Y!f<1}uQ07?H)qIG&}gR}@-xM*&=#K}PrKrr03M3*Aj-4$dR z$|>{`%+j=}F5l{>4G_ zv0!inulO7UH7H4q9?{zDSuYG~QtQ1zt#@Y6rsSm&*mGECbYqmw$ArNVyy64|(>{78 zCDeRx^ek#o8?;Rw>VkG?i+Z44xYANjGp*TQE5;LJ@Pu zGIhHg#gSyZNYXUo$}gu<7M<2VOLi_pIp#8DYOnr2=d7B$Cdw8pJ-s&gHpKMbtK(<= zSAucTALTqs`;f@*GB5gh!Lmb~NH1$zj3sGZxGK@iK}K0q74FC_E{q z$_qnSEyK{k>~*n;SN&bwSt9nNUbhAvQb0qu1BL|1D7hjfIDy$!?v$lzJ_$@kq-wnx z#Ce)?z6EP_UZrT`&<25qz+xEW;$CC-8Xv^>;}JZA?=XTZC|zjIj5G7nDx=Z1O-+nU z+fG?XSmD;C3@nIN{4tI=7s?+d6o`N& z-IyU_j4msjebRZGh|Gpjn! z##u{xGxCn$jYypZDsGqKX`BBBLODDc3}s*`=NFzt>HHgJxMZ}Pr^w;RdV-=G^+&LZ?rje)#ZV z{x>*-Hjgbx^B=EVd9F-Odo3PiG|8l%n!*J>%qJgj?aGH#V-{j7`4PM=2(wT2R|&IR z*A3cu{bq0@QpIo6V%r5Efonemom&@>w%w zN3-IN^VEvO>|6W7#*%~2V|1?Jg4CU|g>8C#ba7Woe=bsfQ3Y!oe{O7W8GpW7rn0PKw!W-axe#+XQZA>Kz+Jx6smJ!WJyVTNvgTZXy<9g{ngRVJ-EDkN21bGOj**oz^baq5!T@^K}Apg}VCXMGyCp z>RM3(854KSWSX68Ho5HINJqsuOD3`D>8L0E2Tn%@o9efJ`ygV*;<8Ghq%UJSn Date: Sun, 9 Jun 2024 16:20:45 +0800 Subject: [PATCH 4/6] docs:update the docstring in Caesar Cipher code --- Caesar_Cipher/Caesar_cipher.py | 37 ++++++++++++++++++++++++++++++++-- 1 file changed, 35 insertions(+), 2 deletions(-) diff --git a/Caesar_Cipher/Caesar_cipher.py b/Caesar_Cipher/Caesar_cipher.py index ac514ef3..1b29839b 100644 --- a/Caesar_Cipher/Caesar_cipher.py +++ b/Caesar_Cipher/Caesar_cipher.py @@ -1,8 +1,26 @@ -class main: +class main: + """ + The Main class provides functionality for encrypting and decrypting strings using a simple substitution cipher. + + Attributes: + key (dict): A dictionary mapping each letter of the alphabet to its corresponding encrypted letter. + blank_string (str): The string input by the user to be encrypted. + decrypted_string (str): The string that results from the encryption of the blank_string. + """ def __init__(self,key:dict) -> None: + """ + Initializes the Main class with the given key for the substitution cipher. + + Parameters: + key (dict): A dictionary mapping each letter of the alphabet to its corresponding encrypted letter. + """ self.key = key - def get_input(self) -> None: + def get_input(self) -> None: + """ + Prompts the user to enter a string to be encrypted, validates the input, and converts it to lowercase. + Only alphabetical input is accepted, if the input is invalid, the user is prompted to try again. + """ while True: blank_string = str(input("Enter string to decrypt: ")) if blank_string.isalpha(): @@ -14,6 +32,12 @@ def get_input(self) -> None: continue def encrypt_string(self) -> str: + """ + Encrypts the user-provided string using the substitution cipher defined by the key. + + Returns: + str:The encrypted string. + """ output = "" for c in self.blank_string: for k,v in self.key.items(): @@ -25,6 +49,15 @@ def encrypt_string(self) -> str: return(output) def decrypt_string(self, string: str) -> str: + """ + Decrypts a given string using the substitution cipher defined by the key. + + Parameters: + string (str): The string to be decrypted. + + Returns: + str: The decrypted string, or the original blank_string if the input string is empty. + """ output = "" string = string.lower() string = string.strip() From de4536ffd348f806d8d197933becdc2ab7ccf7e3 Mon Sep 17 00:00:00 2001 From: Gabriela20103967 <20103967@tafe.wa.edu.au> Date: Sun, 9 Jun 2024 17:39:25 +0800 Subject: [PATCH 5/6] feat: implement test cases for caterpillar project --- Caterpillar_Game/caterpillar_test.py | 34 ++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) create mode 100644 Caterpillar_Game/caterpillar_test.py diff --git a/Caterpillar_Game/caterpillar_test.py b/Caterpillar_Game/caterpillar_test.py new file mode 100644 index 00000000..b9c01673 --- /dev/null +++ b/Caterpillar_Game/caterpillar_test.py @@ -0,0 +1,34 @@ +import unittest +from caterpillarGame import CaterpillarGame + + +class TestCaterpillarGame(unittest.TestCase): + + def setUp(self): + self.game = CaterpillarGame() + + def test_initial_state(self): + self.assertFalse(self.game.game_started) + self.assertEqual(self.game.score, 0) + self.assertEqual(self.game.caterpillar_speed, 2) + self.assertEqual(self.game.caterpillar_length, 3) + + def test_move_up(self): + self.game.move_up() + self.assertEqual(self.game.design.caterpillar.heading(), 90) + + def test_move_down(self): + self.game.move_down() + self.assertEqual(self.game.design.caterpillar.heading(), 270) + + def test_move_left(self): + self.game.move_left() + self.assertEqual(self.game.design.caterpillar.heading(), 180) + + def test_move_right(self): + self.game.move_right() + self.assertEqual(self.game.design.caterpillar.heading(), 0) + + +if __name__ == '__main__': + unittest.main() From 0d985ff8f6f2a2e0b0c428a470b8226e3c3f7245 Mon Sep 17 00:00:00 2001 From: Gabriela20103967 <20103967@tafe.wa.edu.au> Date: Mon, 10 Jun 2024 11:00:25 +0800 Subject: [PATCH 6/6] docs:update the docstring in the Chess Game, and the README file --- Chess_Game/ChessEngine.py | 175 +++++++++++++++++++++++++++++++++----- Chess_Game/ChessGame.py | 56 ++++++++++++ Chess_Game/README.md | 47 ++++++++++ 3 files changed, 258 insertions(+), 20 deletions(-) diff --git a/Chess_Game/ChessEngine.py b/Chess_Game/ChessEngine.py index 3355cc86..1ec6917e 100644 --- a/Chess_Game/ChessEngine.py +++ b/Chess_Game/ChessEngine.py @@ -1,8 +1,15 @@ +class GameState: + """ + Represents the state of a chess game, including the board, move history, + and current player turn. + """ -class GameState: - def __init__(self): - self.board = [ + """ + Initializes the game state with the starting board setup, move functions, + and game status indicators. + """ + self.board = [ ["bR", "bN", "bB", "bQ", "bK", "bB", "bN", "bR"], ["bp", "bp", "bp", "bp", "bp", "bp", "bp", "bp"], ["--", "--", "--", "--", "--", "--", "--", "--"], @@ -11,16 +18,22 @@ def __init__(self): ["--", "--", "--", "--", "--", "--", "--", "--"], ["wp", "wp", "wp", "wp", "wp", "wp", "wp", "wp"], ["wR", "wN", "wB", "wQ", "wK", "wB", "wN", "wR"]] - self.moveFunctions = {'p': self.getPawnMoves, 'R': self.getRookMoves, 'N': self.getKnightMoves, - 'B': self.getBishopMoves, 'Q': self.getQueenMoves, 'K': self.getKingMoves} - self.whiteToMove = True, - self.moveLog = [] - self.whiteKingLocation = (7, 4) - self.blackKingLocation = (0, 4) - self.checkMate = False - self.staleMate = False + self.moveFunctions = {'p': self.getPawnMoves, 'R': self.getRookMoves, 'N': self.getKnightMoves, + 'B': self.getBishopMoves, 'Q': self.getQueenMoves, 'K': self.getKingMoves} + self.whiteToMove = True, + self.moveLog = [] + self.whiteKingLocation = (7, 4) + self.blackKingLocation = (0, 4) + self.checkMate = False + self.staleMate = False def makeMove(self, move): + """ + Executes a given move on the board, updates move log, and switches player turn. + + Args: + move (move): The move to be made,an instance of the move class. + """ self.board[move.startRow][move.startCol] = "--" self.board[move.endRow][move.endCol] = move.pieceMoved self.moveLog.append(move) @@ -35,6 +48,10 @@ def makeMove(self, move): def undoMove(self): + """ + Undoes the last move made,reverting the board to the previous state + and switching the player turn. + """ if len(self.moveLog) != 0: move = self.moveLog.pop() self.board[move.startRow][move.startCol] = move.pieceMoved @@ -44,10 +61,14 @@ def undoMove(self): self.whiteKingLocation = (move.startRow, move.startCol) if move.pieceMoved == "bK": self.blackKingLocation = (move.startRow, move.startCol) - """ - All move considering checks - """ + def getValidMoves(self): + """ + Returns a list of all valid moves, considering checks. + + Returns: + list: A list of valid moves. + """ moves = self.getAllPossibleMoves() for i in range(len(moves)-1, -1, -1): self.makeMove(moves[i]) @@ -68,12 +89,28 @@ def getValidMoves(self): return moves def inCheck(self): + """ + Checks if the current player is in checks. + + Returns: + bool: True if the current player is in check, False otherwise. + """ if self.whiteToMove: return self.squareUnderAttack(self.whiteKingLocation[0], self.whiteKingLocation[1]) else: return self.squareUnderAttack(self.blackKingLocation[0], self.blackKingLocation[1]) def squareUnderAttack(self, r, c): + """ + Determines if a specific square is under attack. + + Args: + r (int): The row of the square. + c (int): The column of the square. + + Returns: + bool: True if the square is under attack, False otherwise. + """ self.whiteToMove = not self.whiteToMove oppMoves = self.getAllPossibleMoves() self.whiteToMove = not self.whiteToMove @@ -82,13 +119,13 @@ def squareUnderAttack(self, r, c): return True return False - - - - """ - All move without considering checks - """ def getAllPossibleMoves(self): + """ + Returns a list of all possible moves without considering checks. + + Returns: + list: A list of all possible moves. + """ moves = [] for r in range(len(self.board)): for c in range(len(self.board[r])): @@ -100,6 +137,14 @@ def getAllPossibleMoves(self): def getPawnMoves(self, r, c, moves): + """ + Adds all possible pawn moves to the list of moves. + + Args: + r (int); The row of the pawn. + c (int): The column of the pawn. + moves (list): The list of moves to append to. + """ if self.whiteToMove: if self.board[r-1][c] == "--": moves.append(Move((r, c),(r-1, c), self.board)) @@ -125,6 +170,14 @@ def getPawnMoves(self, r, c, moves): moves.append(Move((r, c),(r+1, c+1), self.board)) def getRookMoves(self, r, c, moves): + """ + Adds all possible rook moves to the list of moves. + + Args: + r (int): The row of the rook. + c (int): The column of the rook. + moves (list): The list of moves to append to. + """ directions = ((-1, 0), (0, -1), (1, 0), (0, 1)) enemyColor = "b" if self.whiteToMove else "w" for d in directions: @@ -144,6 +197,14 @@ def getRookMoves(self, r, c, moves): break def getKnightMoves(self, r,c,moves): + """ + Adds all posible knight moves to the list of moves. + + Args: + r (int): The row of the knight. + c (int): The column of the knight. + moves (list): The list of moves to append to. + """ knightMoves = ((-2, -1), (-2, 1), (-1, -2), (-1, 2), (1, -2), (1, 2), (2, -1), (2,1)) allyColor = "w" if self.whiteToMove else "b" for m in knightMoves: @@ -155,6 +216,17 @@ def getKnightMoves(self, r,c,moves): moves.append(Move((r,c), (endRow, endCol), self.board)) def getBishopMoves(self, r,c,moves): + """ + Adds all possible bishop moves to the list moves. + + Args: + r (int): The row index of the bishop's starting position. + c (int): The column index of the bishop's starting position. + moves (list): A list to which the valid moves will be appended. + + Returns: + None + """ directions = ((-1, -1), (-1, 1), (1, -1), (1, 1)) enemyColor = "b" if self.whiteToMove else "w" for d in directions: @@ -174,10 +246,30 @@ def getBishopMoves(self, r,c,moves): break def getQueenMoves(self, r,c,moves): + """ + Adds all possible queen moves from the given position (r,c) on the board. + + This method combines the generation logic of rooks and bishops adding all + valid moves to the 'moves' list. + + Args: + r (int): The row index of the queen's starting position. + c (int): The column index of the queen's starting position. + moves (list): A list to witch the valid moves will be appended. + """ self.getRookMoves(r, c, moves) self.getBishopMoves(r, c, moves) def getKingMoves(self, r,c,moves): + """ + This method checks each possible move for the king and adds valid moves + to the 'moves' list. + + Args: + r (int): The row index of the king's starting position. + c (int): The column index of the king's starting position. + moves (int): A list to which the valid moves will be appended. + """ kingMoves = ((-1, -1), (-1, 0), (-1, 1), (0, -1), (0, 1), (1, -1), (1, 0), (1,1) ) allyColor = "w" if self.whiteToMove else "b" for i in range(8): @@ -188,6 +280,19 @@ def getKingMoves(self, r,c,moves): if endPiece[0] != allyColor: moves.append(Move((r,c), (endRow, endCol), self.board)) class Move(): + """ + This class represent a chess move. + + Attributes: + startRow (int): The starting row index of the move. + startCol (int): The starting column index of the move. + endRow (int): The ending row index of the move. + endCol (int): The ending column index of the move. + pieceMoved (str): The piece being moved. + pieceCaptured (str): The piece being captured (if any). + isPawnPromotion (bool): Whether the move is a pawn promotion. + moveID (int): A unique identifier for the move. + """ ranksToRow = {"1": 7, "2": 6, "3": 5, "4": 4, "5": 3, "6": 2, "7": 1, "8": 0} @@ -197,6 +302,14 @@ class Move(): colsToFiles = {v: k for k, v in filesToCols.items()} def __init__(self, startSq, endSq, board): + """ + Initializes a move object. + + Parameters: + startSq (tuple): A tuple (row, col) representing the starting square of the move. + endSq (tuple): A tuple (row, col) representing the ending square of the move. + board (list): The current state of the chess board. + """ self.startRow = startSq[0] self.startCol = startSq[1] self.endRow = endSq[0] @@ -209,14 +322,36 @@ def __init__(self, startSq, endSq, board): self.moveID = self.startRow * 1000 + self.startCol * 100 + self.endRow * 10 + self.endCol def __eq__(self, other): + """ + checks if two move objects are equal based on their moveID. + + Args: + other (move): Another move object to compare with. + """ if isinstance(other, Move): return self.moveID == other.moveID return False def getChessNotation(self): + """ + Returns the move in standard chess notation. + + Returns: + str: The move in chess notation + """ return self.getRankFile(self.startRow, self.startCol) + self.getRankFile(self.endRow, self.endCol) def getRankFile(self, r, c): + """ + Converts row and column indices to chess rank and file notation. + + Args: + r (int): The row index. + c (int): The column index. + + Returns: + str: The corresponding chess rank and file + """ return self.colsToFiles[c] + self.rowsToRanks[r] diff --git a/Chess_Game/ChessGame.py b/Chess_Game/ChessGame.py index 5a361913..2014120c 100644 --- a/Chess_Game/ChessGame.py +++ b/Chess_Game/ChessGame.py @@ -8,11 +8,20 @@ IMAGES = {} def loadImages(): + """ + Load chess piece images and scale them to the appropriate size. + """ pieces = ['wp', 'wR', 'wN', 'wB', 'wQ', 'wK', 'bp', 'bR', 'bN', 'bB', 'bQ', 'bK' ] for piece in pieces: IMAGES[piece] = p.transform.scale(p.image.load("images/" + piece + ".png"), (SQ_SIZE, SQ_SIZE)) def main(): + """ + Main function to run the chess game. + + This function initializes the game window, sets up the game state, handles user input, + updates the game state based on user actions, and renders the game state on the screen. + """ p.init() screen = p.display.set_mode((WIDTH, HEIGHT)) clock = p.time.Clock() @@ -87,6 +96,15 @@ def main(): p.display.flip() def highlightSquares(screen, gs, validMoves, sqSelected): + """ + Highlight the squares on the chessboard based on the selected piece and its valid moves. + + Args: + screen: The game screen surface. + gs (ChessEngine.GameState): The current game state. + validMoves (list): List of valid moves for the selected piece. + sqSelected (tuple): Tuple containing the coordinates of the selected square. + """ if sqSelected != (): r, c = sqSelected if gs.board[r][c][0] == ('w' if gs.whiteToMove else 'b'): @@ -100,11 +118,26 @@ def highlightSquares(screen, gs, validMoves, sqSelected): screen.blit(s, (SQ_SIZE*moves.endCol, SQ_SIZE*moves.endRow)) def drawGameState(screen, gs, validMoves, sqSelected): + """ + Draw the current state of the chess game on the screen. + + Args: + screen: The game screen surface. + gs (ChessEngine.GameState): The current game state. + validMoves (list): List of valid moves for the selected piece. + sqSelected (tuple): Tuple containing the coordinates of the selected square. + """ drawBoard(screen) highlightSquares(screen, gs, validMoves, sqSelected) drawPieces(screen, gs.board) def drawBoard(screen): + """ + Draw the chessboard on the screen. + + Args: + screen: The game screen surface. + """ global colors colors = [p.Color("white"), p.Color("grey")] for r in range(DIMENSIONS): @@ -113,6 +146,13 @@ def drawBoard(screen): p.draw.rect(screen, color, p.Rect(c*SQ_SIZE, r*SQ_SIZE, SQ_SIZE, SQ_SIZE)) def drawPieces(screen, board): + """ + Draw the chess pieces on the screen based on the current board state. + + Args: + screen: The game screen surface. + board (list): 2D list representing the class board state. + """ for r in range(DIMENSIONS): for c in range(DIMENSIONS): piece = board[r][c] @@ -120,6 +160,15 @@ def drawPieces(screen, board): screen.blit(IMAGES[piece], p.Rect(c*SQ_SIZE, r*SQ_SIZE, SQ_SIZE, SQ_SIZE)) def animatedMoves(move, screen,board, clock): + """ + Animate the movement of a chess piece on the screen. + + Args: + move (ChessEngine.Move): The move to animate. + screen: The game screen surface. + board (list): 2D list representing the chess board state. + clock: Pygame clock objects. + """ global colors dR = move.endRow - move.startRow dC = move.endCol - move.startCol @@ -140,6 +189,13 @@ def animatedMoves(move, screen,board, clock): clock.tick(60) def drawText(screen, text): + """ + Draw text on the screen + + Args: + screen: The game screen surface. + text (str): The text to be displayed. + """ font = p.font.SysFont("Helvitca", 32, True, False) textObject = font.render(text, True, p.Color('Gray')) textLocation = p.Rect(0, 0, WIDTH, HEIGHT).move(WIDTH/2 - textObject.get_width()/2, HEIGHT/2 - textObject.get_height()/2) diff --git a/Chess_Game/README.md b/Chess_Game/README.md index 9a91ca05..88989d7a 100644 --- a/Chess_Game/README.md +++ b/Chess_Game/README.md @@ -22,5 +22,52 @@ python ChessGame.py

![alt text] +## 🕹️ Game Instruction + - Move Pieces: Click on a piece to select it and then click on the target square to move. + - Undo Moves: Press the 'z' key to undo the last move. + - Restart Game: Press the 'r' key to restart the game. + +## 🎮 Gameplay Features + - Two-Player Mode: Play with a friend locally. + - Valid Moves Highlighting: Highlight valid moves for the selected piece. + - Check and Checkmate Detection: The game detects check and checkmate situations. + - Stalemate Detection: The game detects stalemate situations. + +## 🧩 Classes and Methods + `GameState` + - Attributes: + - board: The current state of the chess board. + - moveFunctions: A dictionary of piece types and their respective move functions. + - whiteToMove: Boolean indicating if it's white's turn to move. + - moveLog: A log of all moves made during the game. + - whiteKingLocation, blackKingLocation: The current positions of the white and black kings. + - checkMate, staleMate: Booleans indicating if the game is in checkmate or stalemate. + + `Methods` + - __init__(): Initializes the game state with the starting board setup. + - makeMove(move): Executes a given move on the board. + - undoMove(): Undoes the last move made. + - getValidMoves(): Returns a list of all valid moves, considering checks. + - inCheck(): Checks if the current player is in check. + - squareUnderAttack(r, c); Determines if a specific square is under attack. + - getAllPossibleMoves(): Returns a list of all possible moves without considering checks. + - getPawnMoves(r, c, moves), getRookMoves(r, c, moves), getKnightMoves(r, c, moves), + getBishopMoves(r, c, moves), getQueenMoves(r, c, moves), getKingMoves(r, c, moves): Add all + possible moves for the respective pieces to the list of moves. + + `Move` + - Attributes: + - startRow, startCol: The starting position of the move. + - endRow, andCol: The ending position of the move. + - pieceMoved, pieceCaptured: The piece being moved and the piece being captured. + - isPawnPromotion: Whether the move is a pawn promotion. + - moveID: A unique identifier for the move. + + - Methods: + - __init__(startSq, endSq, board): Initializes a move object. + - __eq__(other): Checks if two move objects are equal based on their moveID. + - getChessNotation(): Returns the move in standard chess notation. + - getRankFile(r, c,): Converts row and column indicates to chess rank and file notation. + ## *Author Name* [Abhi Bhullar](https://github.com/userabhibhullar) \ No newline at end of file