Skip to content

new chess game project added and remaining projects have been added to project list #4

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 5 commits into from
May 4, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
222 changes: 222 additions & 0 deletions 0x24-Chess_Game/ChessEngine.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,222 @@

class GameState:

def __init__(self):
self.board = [
["bR", "bN", "bB", "bQ", "bK", "bB", "bN", "bR"],
["bp", "bp", "bp", "bp", "bp", "bp", "bp", "bp"],
["--", "--", "--", "--", "--", "--", "--", "--"],
["--", "--", "--", "--", "--", "--", "--", "--"],
["--", "--", "--", "--", "--", "--", "--", "--"],
["--", "--", "--", "--", "--", "--", "--", "--"],
["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

def makeMove(self, move):
self.board[move.startRow][move.startCol] = "--"
self.board[move.endRow][move.endCol] = move.pieceMoved
self.moveLog.append(move)
self.whiteToMove = not self.whiteToMove
if move.pieceMoved == "wK":
self.whiteKingLocation = (move.endRow, move.endCol)
elif move.pieceMoved == "bK":
self.blackKingLocation = (move.endRow, move.endCol)

if move.isPawnPromotion:
self.board[move.endRow][move.endCol] = move.pieceMoved[0] + "Q"


def undoMove(self):
if len(self.moveLog) != 0:
move = self.moveLog.pop()
self.board[move.startRow][move.startCol] = move.pieceMoved
self.board[move.endRow][move.endCol] = move.pieceCaptured
self.whiteToMove = not self.whiteToMove
if move.pieceMoved == "wK":
self.whiteKingLocation = (move.startRow, move.startCol)
if move.pieceMoved == "bK":
self.blackKingLocation = (move.startRow, move.startCol)
"""
All move considering checks
"""
def getValidMoves(self):
moves = self.getAllPossibleMoves()
for i in range(len(moves)-1, -1, -1):
self.makeMove(moves[i])
self.whiteToMove = not self.whiteToMove
if self.inCheck():
moves.remove(moves[i])
self.whiteToMove = not self.whiteToMove
self.undoMove()
if len(moves) == 0:
if self.inCheck():
self.checkMate = True
else:
self.staleMate = True
else:
self.checkMate = False
self.staleMate = False

return moves

def inCheck(self):
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):
self.whiteToMove = not self.whiteToMove
oppMoves = self.getAllPossibleMoves()
self.whiteToMove = not self.whiteToMove
for move in oppMoves:
if move.endRow == r and move.endCol == c:
return True
return False




"""
All move without considering checks
"""
def getAllPossibleMoves(self):
moves = []
for r in range(len(self.board)):
for c in range(len(self.board[r])):
turn = self.board[r][c][0] # b or w based on turn
if(turn == 'w' and self.whiteToMove) or (turn == 'b' and not self.whiteToMove):
piece = self.board[r][c][1]
self.moveFunctions[piece](r,c, moves)
return moves


def getPawnMoves(self, r, c, moves):
if self.whiteToMove:
if self.board[r-1][c] == "--":
moves.append(Move((r, c),(r-1, c), self.board))
if r == 6 and self.board[r-2][c] == "--":
moves.append(Move((r, c),(r-2, c), self.board))
if c-1 >= 0:
if self.board[r-1][c-1][0] == 'b':
moves.append(Move((r, c),(r-1, c-1), self.board))
if c+1 <= 7:
if self.board[r-1][c+1][0] == 'b':
moves.append(Move((r, c),(r-1, c+1), self.board))

else:
if self.board[r+1][c] == "--":
moves.append(Move((r, c),(r+1, c), self.board))
if r == 1 and self.board[r+2][c] == "--":
moves.append(Move((r, c),(r+2, c), self.board))
if c-1 >= 0:
if self.board[r+1][c-1][0] == 'w':
moves.append(Move((r, c),(r+1, c-1), self.board))
if c+1 <= 7:
if self.board[r+1][c+1][0] == 'w':
moves.append(Move((r, c),(r+1, c+1), self.board))

def getRookMoves(self, r, c, moves):
directions = ((-1, 0), (0, -1), (1, 0), (0, 1))
enemyColor = "b" if self.whiteToMove else "w"
for d in directions:
for i in range(1, 8):
endRow = r + d[0] * i
endCol = c + d[1] * i
if 0 <= endRow < 8 and 0 <= endCol < 8:
endPiece = self.board[endRow][endCol]
if endPiece == "--":
moves.append(Move((r,c), (endRow, endCol), self.board))
elif endPiece[0] == enemyColor:
moves.append(Move((r,c), (endRow, endCol), self.board))
break
else:
break
else:
break

def getKnightMoves(self, r,c,moves):
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:
endRow = r + m[0]
endCol = c + m[1]
if 0 <= endRow < 8 and 0 <= endCol < 8:
endPiece = self.board[endRow][endCol]
if endPiece[0] != allyColor:
moves.append(Move((r,c), (endRow, endCol), self.board))

def getBishopMoves(self, r,c,moves):
directions = ((-1, -1), (-1, 1), (1, -1), (1, 1))
enemyColor = "b" if self.whiteToMove else "w"
for d in directions:
for i in range(1, 8):
endRow = r + d[0] * i
endCol = c + d[1] * i
if 0 <= endRow < 8 and 0 <= endCol < 8:
endPiece = self.board[endRow][endCol]
if endPiece == "--":
moves.append(Move((r,c), (endRow, endCol), self.board))
elif endPiece[0] == enemyColor:
moves.append(Move((r,c), (endRow, endCol), self.board))
break
else:
break
else:
break

def getQueenMoves(self, r,c,moves):
self.getRookMoves(r, c, moves)
self.getBishopMoves(r, c, moves)

def getKingMoves(self, r,c,moves):
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):
endRow = r + kingMoves[i][0]
endCol = c + kingMoves[i][1]
if 0 <= endRow < 8 and 0 <= endCol < 8:
endPiece = self.board[endRow][endCol]
if endPiece[0] != allyColor:
moves.append(Move((r,c), (endRow, endCol), self.board))
class Move():

ranksToRow = {"1": 7, "2": 6, "3": 5, "4": 4,
"5": 3, "6": 2, "7": 1, "8": 0}
rowsToRanks = {v: k for k, v in ranksToRow.items()}
filesToCols = {"a": 0, "b": 1, "c": 2, "d": 3,
"e": 4, "f": 5, "g": 6, "h": 7}
colsToFiles = {v: k for k, v in filesToCols.items()}

def __init__(self, startSq, endSq, board):
self.startRow = startSq[0]
self.startCol = startSq[1]
self.endRow = endSq[0]
self.endCol = endSq[1]
self.pieceMoved = board[self.startRow][self.startCol]
self.pieceCaptured = board[self.endRow][self.endCol]
self.isPawnPromotion = False
if (self.pieceMoved == 'wp' and self.endRow == 0) or (self.pieceMoved == 'bp' and self.endRow == 7):
self.isPawnPromotion = True
self.moveID = self.startRow * 1000 + self.startCol * 100 + self.endRow * 10 + self.endCol

def __eq__(self, other):
if isinstance(other, Move):
return self.moveID == other.moveID
return False


def getChessNotation(self):
return self.getRankFile(self.startRow, self.startCol) + self.getRankFile(self.endRow, self.endCol)

def getRankFile(self, r, c):
return self.colsToFiles[c] + self.rowsToRanks[r]

152 changes: 152 additions & 0 deletions 0x24-Chess_Game/ChessGame.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,152 @@
import pygame as p
import ChessEngine

WIDTH = HEIGHT = 512
DIMENSIONS = 8
SQ_SIZE = HEIGHT// DIMENSIONS
MAX_FPS = 15
IMAGES = {}

def loadImages():
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():
p.init()
screen = p.display.set_mode((WIDTH, HEIGHT))
clock = p.time.Clock()
screen.fill(p.Color("white"))
gs = ChessEngine.GameState()
validMoves = gs.getValidMoves()
moveMade = False
animate = False
loadImages()
running = True
sqSelected = ()
playerClicks = []
gameOver = False
while running:
for e in p.event.get():
if e.type == p.QUIT:
running = False
elif e.type == p.MOUSEBUTTONDOWN:
if not gameOver:
location = p.mouse.get_pos()
col = location[0]//SQ_SIZE
row = location[1]//SQ_SIZE
if sqSelected == (row, col):
sqSelected = ()
playerClicks = []
else:
sqSelected = (row, col)
playerClicks.append(sqSelected)
if len(playerClicks) == 1 and (gs.board[row][col] == "--"):
sqSelected = ()
playerClicks = []
if len(playerClicks) == 2:
move = ChessEngine.Move(playerClicks[0], playerClicks[1], gs.board)
for i in range(len(validMoves)):
if move == validMoves[i]:
gs.makeMove(move)
moveMade = True
animate = True
sqSelected = ()
playerClicks = []
if not moveMade:
playerClicks = [sqSelected]
elif e.type == p.KEYDOWN:
if e.key == p.K_z:
gs.undoMove()
moveMade = True
animate = False
if e.key == p.K_r:
gs = ChessEngine.GameState()
validMoves = gs.getValidMoves()
sqSelected = ()
playerClicks = []
moveMade = False
animate = False
if moveMade:
if animate:
animatedMoves(gs.moveLog[-1], screen, gs.board,clock)
validMoves = gs.getValidMoves()
moveMade = False
animate = False
drawGameState(screen, gs, validMoves, sqSelected)
if gs.checkMate:
gameOver = True
if gs.whiteToMove:
drawText(screen, 'Black wins by checkmate')
else:
drawText(screen, 'White wins by checkmate')
elif gs.staleMate:
gameOver =True
drawText(screen, 'Stalemate');
clock.tick(MAX_FPS)
p.display.flip()

def highlightSquares(screen, gs, validMoves, sqSelected):
if sqSelected != ():
r, c = sqSelected
if gs.board[r][c][0] == ('w' if gs.whiteToMove else 'b'):
s = p.Surface((SQ_SIZE, SQ_SIZE))
s.set_alpha(100)
s.fill(p.Color('blue'))
screen.blit(s, (c*SQ_SIZE, r*SQ_SIZE))
s.fill(p.Color("yellow"))
for moves in validMoves:
if moves.startRow == r and moves.startCol == c:
screen.blit(s, (SQ_SIZE*moves.endCol, SQ_SIZE*moves.endRow))

def drawGameState(screen, gs, validMoves, sqSelected):
drawBoard(screen)
highlightSquares(screen, gs, validMoves, sqSelected)
drawPieces(screen, gs.board)

def drawBoard(screen):
global colors
colors = [p.Color("white"), p.Color("grey")]
for r in range(DIMENSIONS):
for c in range(DIMENSIONS):
color = colors[(r+c) % 2]
p.draw.rect(screen, color, p.Rect(c*SQ_SIZE, r*SQ_SIZE, SQ_SIZE, SQ_SIZE))

def drawPieces(screen, board):
for r in range(DIMENSIONS):
for c in range(DIMENSIONS):
piece = board[r][c]
if piece != "--":
screen.blit(IMAGES[piece], p.Rect(c*SQ_SIZE, r*SQ_SIZE, SQ_SIZE, SQ_SIZE))

def animatedMoves(move, screen,board, clock):
global colors
dR = move.endRow - move.startRow
dC = move.endCol - move.startCol
framesPerSquare = 5
frameCount = (abs(dR) + abs(dC)) * framesPerSquare
for frame in range(frameCount + 1):
r,c =((move.startRow + dR*frame/frameCount, move.startCol + dC*frame/frameCount))
drawBoard(screen)
drawPieces(screen, board)
color = colors[(move.endRow + move.endCol)%2]
endSquare = p.Rect(move.endCol*SQ_SIZE, move.endRow*SQ_SIZE, SQ_SIZE, SQ_SIZE)
p.draw.rect(screen, color, endSquare)
if move.pieceCaptured != "--":
screen.blit(IMAGES[move.pieceCaptured], endSquare)

screen.blit(IMAGES[move.pieceMoved], p.Rect(c*SQ_SIZE, r*SQ_SIZE, SQ_SIZE, SQ_SIZE))
p.display.flip()
clock.tick(60)

def drawText(screen, text):
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)
screen.blit(textObject, textLocation)
textObject = font.render(text, True, p.Color("Black"))
screen.blit(textObject, textLocation.move(2,2))


if __name__ == "__main__":
main()
Loading