Skip to content

Commit c7a899d

Browse files
Merge pull request prathimacode-hub#440 from sahilsingh2402/final
Added Chess Game
2 parents 13ad844 + 2940195 commit c7a899d

File tree

4 files changed

+286
-0
lines changed

4 files changed

+286
-0
lines changed
398 KB
Loading

PyGamesScripts/Chess Game/README.md

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
# Chess Game
2+
### This repo contains program for a Chess Game in python.
3+
4+
#### In this game, the whole board can be controlled using simple algebraic commands,
5+
For example:
6+
>>>e4 e7
7+
This will move the pawn present on the e4 position to the e7 position. The program will evaluate constantly, whether its a valid move or not.
8+
9+
CONVENTIONS: Positions are row-column based, both are numbers from the bottom left. This corresponds to the alpha-number system in traditional chess while being computationally useful. They are specified as tuples
10+
11+
Game class contains the following members and methods:
12+
> Two arrays of pieces for each player.
13+
> 8x8 piece array with references to these pieces.
14+
> A parse function, which turns the input from the user into a list of two tuples denoting start and end points.
15+
> A checkmateExists function which checks if either players are in checkmate.
16+
> A checkExists function which checks if either players are in check.
17+
> A main loop, which takes input, runs it through the parser, asks the piece if the move is valid, and moves the piece if it is. If the move conflicts with another piece, that piece is removed. ischeck(mate) is run, and if there is a checkmate, the game prints a message as to who wins.
18+
19+
General Chess Rules
20+
White is always first to move and players take turns alternately moving one piece at a time. A piece may be moved to another position or may capture an opponent´s piece, replacing on its square. With the exception of the knight, a piece may not move over or through any of the other pieces. When a king is threatened with capture (but can protect himself or escape), it´s called check. If a king is in check, then the player must make a move that eliminates the threat of capture and cannot leave the king in check. Checkmate happens when a king is placed in check and there is no legal/valid move to escape. Checkmate ends the game and the side whose king was checkmated looses.
21+
22+
#### Setup instructions
23+
1. Install 3.x (recommended).
24+
25+
2. Download this repository as zip and extract.
26+
27+
4. Open cmd prompt and adjust the directory to 'Chess Game' folder.
28+
29+
5. Type this command to run the code
30+
31+
chess_game.py
32+
33+
Have fun!!
34+
35+
## Output
36+
<img align="center" alt="output" src="Images/img.jpg"/>
37+
38+
Creator: [Sahil Singh](https://github.com/sahilsingh2402)
Lines changed: 247 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,247 @@
1+
import itertools
2+
WHITE = "white"
3+
BLACK = "black"
4+
5+
"""
6+
CONVENTIONS: Positions are row-column based, both are numbers from the bottom left. This corresponds to the alpha-number system in traditional chess while being computationally useful. They are specified as tuples
7+
8+
Game class contains the following members and methods:
9+
> Two arrays of pieces for each player.
10+
> 8x8 piece array with references to these pieces.
11+
> A parse function, which turns the input from the user into a list of two tuples denoting start and end points.
12+
> A checkmateExists function which checks if either players are in checkmate.
13+
> A checkExists function which checks if either players are in check.
14+
> A main loop, which takes input, runs it through the parser, asks the piece if the move is valid, and moves the piece if it is. If the move conflicts with another piece, that piece is removed. ischeck(mate) is run, and if there is a checkmate, the game prints a message as to who wins.
15+
"""
16+
17+
18+
class Game:
19+
# I've decided since the number of pieces is capped but the type of pieces is not (pawn transformations), I've already coded much of the modularity to support just using a dictionary of pieces.
20+
def __init__(self):
21+
self.playersturn = BLACK
22+
self.message = "This is where prompts will go"
23+
self.gameboard = {}
24+
self.placePieces()
25+
print("Chess program. Enter moves in algebraic notation separated by space")
26+
self.main()
27+
28+
def placePieces(self):
29+
30+
for i in range(0, 8):
31+
self.gameboard[(i, 1)] = Pawn(WHITE, uniDict[WHITE][Pawn], 1)
32+
self.gameboard[(i, 6)] = Pawn(BLACK, uniDict[BLACK][Pawn], -1)
33+
34+
placers = [Rook, Knight, Bishop, Queen, King, Bishop, Knight, Rook]
35+
36+
for i in range(0, 8):
37+
self.gameboard[(i, 0)] = placers[i](
38+
WHITE, uniDict[WHITE][placers[i]])
39+
self.gameboard[((7-i), 7)] = placers[i](BLACK,
40+
uniDict[BLACK][placers[i]])
41+
placers.reverse()
42+
43+
def main(self):
44+
45+
while True:
46+
self.printBoard()
47+
print(self.message)
48+
self.message = ""
49+
startpos, endpos = self.parseInput()
50+
try:
51+
target = self.gameboard[startpos]
52+
except:
53+
self.message = "Could not find piece!!! Index probably out of range"
54+
target = None
55+
56+
if target:
57+
print("Found "+str(target))
58+
if target.Color != self.playersturn:
59+
self.message = "You aren't allowed to move that piece this turn"
60+
continue
61+
if target.isValid(startpos, endpos, target.Color, self.gameboard):
62+
self.message = "Valid move"
63+
self.gameboard[endpos] = self.gameboard[startpos]
64+
del self.gameboard[startpos]
65+
self.isCheck()
66+
if self.playersturn == BLACK:
67+
self.playersturn = WHITE
68+
else:
69+
self.playersturn = BLACK
70+
else:
71+
self.message = "Invalid move" + \
72+
str(target.availableMoves(
73+
startpos[0], startpos[1], self.gameboard))
74+
print(target.availableMoves(
75+
startpos[0], startpos[1], self.gameboard))
76+
else:
77+
self.message = "There is no piece in that space"
78+
79+
def isCheck(self):
80+
# As certain where the kings are, check all pieces of opposing color against those kings, then if either get hit, check if its checkmate
81+
king = King
82+
kingDict = {}
83+
pieceDict = {BLACK: [], WHITE: []}
84+
for position, piece in self.gameboard.items():
85+
if type(piece) == King:
86+
kingDict[piece.Color] = position
87+
print(piece)
88+
pieceDict[piece.Color].append((piece, position))
89+
# white
90+
if self.canSeeKing(kingDict[WHITE], pieceDict[BLACK]):
91+
self.message = "White player is in check"
92+
if self.canSeeKing(kingDict[BLACK], pieceDict[WHITE]):
93+
self.message = "Black player is in check"
94+
95+
def canSeeKing(self, kingpos, piecelist):
96+
# Checks if any pieces in piece list (which is an array of (piece,position) tuples) can see the king in kingpos.
97+
for piece, position in piecelist:
98+
if piece.isValid(position, kingpos, piece.Color, self.gameboard):
99+
return True
100+
101+
def parseInput(self):
102+
try:
103+
a, b = input().split()
104+
a = ((ord(a[0])-97), int(a[1])-1)
105+
b = (ord(b[0])-97, int(b[1])-1)
106+
print(a, b)
107+
return (a, b)
108+
except:
109+
print("Error Decoding Input!!! Please Try Again")
110+
return((-1, -1), (-1, -1))
111+
112+
def printBoard(self):
113+
print(" 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |")
114+
for i in range(0, 8):
115+
print("-"*32)
116+
print(chr(i+97), end="|")
117+
for j in range(0, 8):
118+
item = self.gameboard.get((i, j), " ")
119+
print(str(item)+' |', end=" ")
120+
print()
121+
print("-"*32)
122+
123+
124+
class Piece:
125+
126+
def __init__(self, color, name):
127+
self.name = name
128+
self.position = None
129+
self.Color = color
130+
131+
def isValid(self, startpos, endpos, Color, gameboard):
132+
if endpos in self.availableMoves(startpos[0], startpos[1], gameboard, Color=Color):
133+
return True
134+
return False
135+
136+
def __repr__(self):
137+
return self.name
138+
139+
def __str__(self):
140+
return self.name
141+
142+
def availableMoves(self, x, y, gameboard):
143+
print("ERROR: No movement for base class")
144+
145+
def AdNauseum(self, x, y, gameboard, Color, intervals):
146+
answers = []
147+
for xint, yint in intervals:
148+
xtemp, ytemp = x+xint, y+yint
149+
while self.isInBounds(xtemp, ytemp):
150+
#print(str((xtemp,ytemp))+"is in bounds")
151+
152+
target = gameboard.get((xtemp, ytemp), None)
153+
if target is None:
154+
answers.append((xtemp, ytemp))
155+
elif target.Color != Color:
156+
answers.append((xtemp, ytemp))
157+
break
158+
else:
159+
break
160+
161+
xtemp, ytemp = xtemp + xint, ytemp + yint
162+
return answers
163+
164+
def isInBounds(self, x, y):
165+
if x >= 0 and x < 8 and y >= 0 and y < 8:
166+
return True
167+
return False
168+
169+
def noConflict(self, gameboard, initialColor, x, y):
170+
if self.isInBounds(x, y) and (((x, y) not in gameboard) or gameboard[(x, y)].Color != initialColor):
171+
return True
172+
return False
173+
174+
175+
chessCardinals = [(1, 0), (0, 1), (-1, 0), (0, -1)]
176+
chessDiagonals = [(1, 1), (-1, 1), (1, -1), (-1, -1)]
177+
178+
179+
def knightList(x, y, int1, int2):
180+
return [(x+int1, y+int2), (x-int1, y+int2), (x+int1, y-int2), (x-int1, y-int2), (x+int2, y+int1), (x-int2, y+int1), (x+int2, y-int1), (x-int2, y-int1)]
181+
182+
183+
def kingList(x, y):
184+
return [(x+1, y), (x+1, y+1), (x+1, y-1), (x, y+1), (x, y-1), (x-1, y), (x-1, y+1), (x-1, y-1)]
185+
186+
187+
class Knight(Piece):
188+
def availableMoves(self, x, y, gameboard, Color=None):
189+
if Color is None:
190+
Color = self.Color
191+
return [(xx, yy) for xx, yy in knightList(x, y, 2, 1) if self.noConflict(gameboard, Color, xx, yy)]
192+
193+
194+
class Rook(Piece):
195+
def availableMoves(self, x, y, gameboard, Color=None):
196+
if Color is None:
197+
Color = self.Color
198+
return self.AdNauseum(x, y, gameboard, Color, chessCardinals)
199+
200+
201+
class Bishop(Piece):
202+
def availableMoves(self, x, y, gameboard, Color=None):
203+
if Color is None:
204+
Color = self.Color
205+
return self.AdNauseum(x, y, gameboard, Color, chessDiagonals)
206+
207+
208+
class Queen(Piece):
209+
def availableMoves(self, x, y, gameboard, Color=None):
210+
if Color is None:
211+
Color = self.Color
212+
return self.AdNauseum(x, y, gameboard, Color, chessCardinals+chessDiagonals)
213+
214+
215+
class King(Piece):
216+
def availableMoves(self, x, y, gameboard, Color=None):
217+
if Color is None:
218+
Color = self.Color
219+
return [(xx, yy) for xx, yy in kingList(x, y) if self.noConflict(gameboard, Color, xx, yy)]
220+
221+
222+
class Pawn(Piece):
223+
def __init__(self, color, name, direction):
224+
self.name = name
225+
self.Color = color
226+
# Direction should be either 1 or -1, should be -1 if the pawn is traveling "backwards"
227+
self.direction = direction
228+
229+
def availableMoves(self, x, y, gameboard, Color=None):
230+
if Color is None:
231+
Color = self.Color
232+
answers = []
233+
if (x+1, y+self.direction) in gameboard and self.noConflict(gameboard, Color, x+1, y+self.direction):
234+
answers.append((x+1, y+self.direction))
235+
if (x-1, y+self.direction) in gameboard and self.noConflict(gameboard, Color, x-1, y+self.direction):
236+
answers.append((x-1, y+self.direction))
237+
if (x, y+self.direction) not in gameboard and Color == self.Color:
238+
# the condition after the and is to make sure the non-capturing movement (the only fucking one in the game) is not used in the calculation of checkmate
239+
answers.append((x, y+self.direction))
240+
return answers
241+
242+
243+
uniDict = {WHITE: {Pawn: "♙", Rook: "♖", Knight: "♘", Bishop: "♗", King: "♔", Queen: "♕"},
244+
BLACK: {Pawn: "♟", Rook: "♜", Knight: "♞", Bishop: "♝", King: "♚", Queen: "♛"}}
245+
246+
if __name__ == "__main__":
247+
Game()
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
itertools==8.8.0

0 commit comments

Comments
 (0)