Skip to content

Commit 30f6f90

Browse files
Added Chess Game
## Related Issue - Added Chess Game - [x] LGM-SOC'21 Participant - [ ] Contributor Closes: #[307] ### Describe the changes you've made It is a CLI based memory efficient chess game which uses only a single library 'itertools'. It is a two player game, where both the players get their turns iteratively. ## Type of change What sort of change have you made: <!-- Example how to mark a checkbox:- - [x] My code follows the code style of this project. --> - [ ] Bug fix (non-breaking change which fixes an issue) - [x] New feature (non-breaking change which adds functionality) - [ ] Code style update (formatting, local variables) - [ ] Breaking change (fix or feature that would cause existing functionality to not work as expected) - [ ] This change requires a documentation update ## How Has This Been Tested? I have played this game many times and tested all possible corner cases where the code could break. ## Checklist: <!-- Example how to mark a checkbox:- - [x] My code follows the code style of this project. --> - [x] My code follows the guidelines of this project. - [x] I have performed a self-review of my own code. - [x] I have commented my code, particularly whereever it was hard to understand. - [x] I have made corresponding changes to the documentation. - [ ] My changes generate no new warnings. - [ ] I have added tests that prove my fix is effective or that my feature works. - [ ] Any dependent changes have been merged and published in downstream modules. ## Screenshots <img align="center" alt="output" src="Images/img.jpg" />
1 parent 9392c1b commit 30f6f90

File tree

3 files changed

+260
-0
lines changed

3 files changed

+260
-0
lines changed
398 KB
Loading

PyGamesScripts/Chess Game/README.md

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
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+
General Chess Rules
10+
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.
11+
12+
#### Setup instructions
13+
1. Install 3.x (recommended).
14+
15+
2. Download this repository as zip and extract.
16+
17+
4. Open cmd prompt and adjust the directory to 'Chess Game' folder.
18+
19+
5. Type this command to run the code
20+
21+
chessGame.py
22+
23+
Have fun!!
24+
25+
## Output
26+
<img align="center" alt="output" src="Images/img.jpg"/>
27+
Lines changed: 233 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,233 @@
1+
import itertools
2+
WHITE = "white"
3+
BLACK = "black"
4+
5+
6+
class Game:
7+
def __init__(self):
8+
self.playersturn = BLACK
9+
self.message = "This is where prompts will go"
10+
self.gameboard = {}
11+
self.placePieces()
12+
print("Chess program. Enter moves in algebraic notation separated by space")
13+
self.main()
14+
15+
def placePieces(self):
16+
17+
for i in range(0, 8):
18+
self.gameboard[(i, 1)] = Pawn(WHITE, uniDict[WHITE][Pawn], 1)
19+
self.gameboard[(i, 6)] = Pawn(BLACK, uniDict[BLACK][Pawn], -1)
20+
21+
placers = [Rook, Knight, Bishop, Queen, King, Bishop, Knight, Rook]
22+
23+
for i in range(0, 8):
24+
self.gameboard[(i, 0)] = placers[i](
25+
WHITE, uniDict[WHITE][placers[i]])
26+
self.gameboard[((7-i), 7)] = placers[i](BLACK,
27+
uniDict[BLACK][placers[i]])
28+
placers.reverse()
29+
30+
def main(self):
31+
32+
while True:
33+
self.printBoard()
34+
print(self.message)
35+
self.message = ""
36+
startpos, endpos = self.parseInput()
37+
try:
38+
target = self.gameboard[startpos]
39+
except:
40+
self.message = "Could not find piece!!! Index probably out of range"
41+
target = None
42+
43+
if target:
44+
print("Found "+str(target))
45+
if target.Color != self.playersturn:
46+
self.message = "You aren't allowed to move that piece this turn"
47+
continue
48+
if target.isValid(startpos, endpos, target.Color, self.gameboard):
49+
self.message = "Valid move"
50+
self.gameboard[endpos] = self.gameboard[startpos]
51+
del self.gameboard[startpos]
52+
self.isCheck()
53+
if self.playersturn == BLACK:
54+
self.playersturn = WHITE
55+
else:
56+
self.playersturn = BLACK
57+
else:
58+
self.message = "Invalid move" + \
59+
str(target.availableMoves(
60+
startpos[0], startpos[1], self.gameboard))
61+
print(target.availableMoves(
62+
startpos[0], startpos[1], self.gameboard))
63+
else:
64+
self.message = "There is no piece in that space"
65+
66+
def isCheck(self):
67+
# ascertain where the kings are, check all pieces of opposing color against those kings, then if either get hit, check if its checkmate
68+
king = King
69+
kingDict = {}
70+
pieceDict = {BLACK: [], WHITE: []}
71+
for position, piece in self.gameboard.items():
72+
if type(piece) == King:
73+
kingDict[piece.Color] = position
74+
print(piece)
75+
pieceDict[piece.Color].append((piece, position))
76+
# white
77+
if self.canSeeKing(kingDict[WHITE], pieceDict[BLACK]):
78+
self.message = "White player is in check"
79+
if self.canSeeKing(kingDict[BLACK], pieceDict[WHITE]):
80+
self.message = "Black player is in check"
81+
82+
def canSeeKing(self, kingpos, piecelist):
83+
# checks if any pieces in piece list (which is an array of (piece,position) tuples) can see the king in kingpos
84+
for piece, position in piecelist:
85+
if piece.isValid(position, kingpos, piece.Color, self.gameboard):
86+
return True
87+
88+
def parseInput(self):
89+
try:
90+
a, b = input().split()
91+
a = ((ord(a[0])-97), int(a[1])-1)
92+
b = (ord(b[0])-97, int(b[1])-1)
93+
print(a, b)
94+
return (a, b)
95+
except:
96+
print("Error Decoding Input!!! Please Try Again")
97+
return((-1, -1), (-1, -1))
98+
99+
def printBoard(self):
100+
print(" 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |")
101+
for i in range(0, 8):
102+
print("-"*32)
103+
print(chr(i+97), end="|")
104+
for j in range(0, 8):
105+
item = self.gameboard.get((i, j), " ")
106+
print(str(item)+' |', end=" ")
107+
print()
108+
print("-"*32)
109+
110+
111+
class Piece:
112+
113+
def __init__(self, color, name):
114+
self.name = name
115+
self.position = None
116+
self.Color = color
117+
118+
def isValid(self, startpos, endpos, Color, gameboard):
119+
if endpos in self.availableMoves(startpos[0], startpos[1], gameboard, Color=Color):
120+
return True
121+
return False
122+
123+
def __repr__(self):
124+
return self.name
125+
126+
def __str__(self):
127+
return self.name
128+
129+
def availableMoves(self, x, y, gameboard):
130+
print("ERROR: No movement for base class")
131+
132+
def AdNauseum(self, x, y, gameboard, Color, intervals):
133+
answers = []
134+
for xint, yint in intervals:
135+
xtemp, ytemp = x+xint, y+yint
136+
while self.isInBounds(xtemp, ytemp):
137+
#print(str((xtemp,ytemp))+"is in bounds")
138+
139+
target = gameboard.get((xtemp, ytemp), None)
140+
if target is None:
141+
answers.append((xtemp, ytemp))
142+
elif target.Color != Color:
143+
answers.append((xtemp, ytemp))
144+
break
145+
else:
146+
break
147+
148+
xtemp, ytemp = xtemp + xint, ytemp + yint
149+
return answers
150+
151+
def isInBounds(self, x, y):
152+
if x >= 0 and x < 8 and y >= 0 and y < 8:
153+
return True
154+
return False
155+
156+
def noConflict(self, gameboard, initialColor, x, y):
157+
if self.isInBounds(x, y) and (((x, y) not in gameboard) or gameboard[(x, y)].Color != initialColor):
158+
return True
159+
return False
160+
161+
162+
chessCardinals = [(1, 0), (0, 1), (-1, 0), (0, -1)]
163+
chessDiagonals = [(1, 1), (-1, 1), (1, -1), (-1, -1)]
164+
165+
166+
def knightList(x, y, int1, int2):
167+
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)]
168+
169+
170+
def kingList(x, y):
171+
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)]
172+
173+
174+
class Knight(Piece):
175+
def availableMoves(self, x, y, gameboard, Color=None):
176+
if Color is None:
177+
Color = self.Color
178+
return [(xx, yy) for xx, yy in knightList(x, y, 2, 1) if self.noConflict(gameboard, Color, xx, yy)]
179+
180+
181+
class Rook(Piece):
182+
def availableMoves(self, x, y, gameboard, Color=None):
183+
if Color is None:
184+
Color = self.Color
185+
return self.AdNauseum(x, y, gameboard, Color, chessCardinals)
186+
187+
188+
class Bishop(Piece):
189+
def availableMoves(self, x, y, gameboard, Color=None):
190+
if Color is None:
191+
Color = self.Color
192+
return self.AdNauseum(x, y, gameboard, Color, chessDiagonals)
193+
194+
195+
class Queen(Piece):
196+
def availableMoves(self, x, y, gameboard, Color=None):
197+
if Color is None:
198+
Color = self.Color
199+
return self.AdNauseum(x, y, gameboard, Color, chessCardinals+chessDiagonals)
200+
201+
202+
class King(Piece):
203+
def availableMoves(self, x, y, gameboard, Color=None):
204+
if Color is None:
205+
Color = self.Color
206+
return [(xx, yy) for xx, yy in kingList(x, y) if self.noConflict(gameboard, Color, xx, yy)]
207+
208+
209+
class Pawn(Piece):
210+
def __init__(self, color, name, direction):
211+
self.name = name
212+
self.Color = color
213+
# of course, the smallest piece is the hardest to code. direction should be either 1 or -1, should be -1 if the pawn is traveling "backwards"
214+
self.direction = direction
215+
216+
def availableMoves(self, x, y, gameboard, Color=None):
217+
if Color is None:
218+
Color = self.Color
219+
answers = []
220+
if (x+1, y+self.direction) in gameboard and self.noConflict(gameboard, Color, x+1, y+self.direction):
221+
answers.append((x+1, y+self.direction))
222+
if (x-1, y+self.direction) in gameboard and self.noConflict(gameboard, Color, x-1, y+self.direction):
223+
answers.append((x-1, y+self.direction))
224+
if (x, y+self.direction) not in gameboard and Color == self.Color:
225+
# 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
226+
answers.append((x, y+self.direction))
227+
return answers
228+
229+
230+
uniDict = {WHITE: {Pawn: "♙", Rook: "♖", Knight: "♘", Bishop: "♗", King: "♔", Queen: "♕"},
231+
BLACK: {Pawn: "♟", Rook: "♜", Knight: "♞", Bishop: "♝", King: "♚", Queen: "♛"}}
232+
233+
Game()

0 commit comments

Comments
 (0)