Skip to content

Commit

Permalink
Implemented logic for checkmate and stalemate moves. Changed how gett…
Browse files Browse the repository at this point in the history
…ing the current side of the board is implemented to be more efficient. Added functionality to InputParser to get the notation of a move. Added a depth attribute to MoveNode. Changed pawn logic to fix bug with pawns skipping the piece in front of them.
  • Loading branch information
marcusbuffett committed Oct 22, 2014
1 parent f9f9afa commit 9e225a8
Show file tree
Hide file tree
Showing 7 changed files with 177 additions and 105 deletions.
42 changes: 30 additions & 12 deletions AI.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
from Piece import Piece
from Board import Board
from MoveNode import MoveNode
from InputParser import InputParser
import copy
import random
from multiprocessing import Queue, Pool, Process
Expand All @@ -18,11 +19,13 @@ class AI :
board = None
side = None
movesAnalyzed = 0


def __init__(self, board, side, depth) :
self.board = board
self.side = side
self.depth = depth
self.parser = InputParser(self.board, self.side)



Expand Down Expand Up @@ -118,28 +121,43 @@ def generateMoveTree(self) :
##self.board.undoLastMove()

def populateNodeChildren(self, node) :
#if self.board.isCheckmate() :
#node.pointAdvantage = 100
#return
node.pointAdvantage = self.board.getPointAdvantageOfSide(self.side)
if node.getDepth() == self.depth :
node.depth = node.getDepth()
if node.depth == self.depth :
return
side = self.board.getCurrentSide()
for move in self.board.getAllMovesLegal(not side) :

side = self.board.currentSide

legalMoves = self.board.getAllMovesLegal(side)
if not legalMoves :
if self.board.isCheckmate() :
node.move.checkmate = True
node.pointAdvantage = 100
return
else :
node.move.stalemate = True
return

for move in legalMoves :
self.movesAnalyzed += 1
node.children.append(MoveNode(move, [], node))
self.board.makeMove(move)
self.populateNodeChildren(node.children[-1])
self.board.undoLastMove()

def getOptimalPointAdvantageForNode(self, node) :
#print("GETTING OPTIMAL VALUE OF NODE : " + str(node))
if node.children:
for child in node.children :
child.pointAdvantage = self.getOptimalPointAdvantageForNode(child)
#print("RETURNING : " + str(max(self.getOptimalPointAdvantageForNode(child))))
return(max(node.children).pointAdvantage)
#optimalNodes = self.maxChildrenOfNode(node)
#for node in optimalNodes :
#return node.pointAdvantage

#If the depth is divisible by 2, it's a move for the AI's side, so return max
if node.children[0].depth % 2 == 1 :
return(max(node.children).pointAdvantage)
else :
return(min(node.children).pointAdvantage)
else :

return node.pointAdvantage
Expand All @@ -151,11 +169,11 @@ def getBestMove(self) :
moveTree = self.generateMoveTree()
bestMoves = self.bestMovesWithMoveTree(moveTree)
randomBestMove = random.choice(bestMoves)
randomBestMove.notation = self.parser.notationForMove(randomBestMove)
return randomBestMove

def makeBestMove(self) :
self.board.makeMove(self.getBestMove())


def bestMovesWithMoveTree(self, moveTree) :
bestMoveNodes = []
Expand Down Expand Up @@ -206,7 +224,7 @@ def makeRandomMove(self) :

if __name__ == "__main__" :
mainBoard = Board()
ai = AI(mainBoard, True, 3)
ai = AI(mainBoard, True, 2)
print(mainBoard)
ai.makeBestMove()
print(mainBoard)
Expand Down
104 changes: 63 additions & 41 deletions Board.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,11 @@
class Board :

movesMade = 0
boardArray = []
checkmate = False

def __init__(self, simple = False) :
if not simple :
def __init__(self, simple = False, mateInOne = False) :
if not simple and not mateInOne:
backRowBlack = [Rook(self, BLACK), Knight(self, BLACK), Bishop(self, BLACK), King(self, BLACK), Queen(self, BLACK), Bishop(self, BLACK), Knight(self, BLACK), Rook(self, BLACK)]
frontRowBlack = []
for _ in range(8) :
Expand All @@ -43,29 +45,49 @@ def __init__(self, simple = False) :
piece.updatePosition()

self.points = 0
elif simple :
backRowBlack = [None, None, None, King(self, BLACK), None, None, None, None]
frontRowBlack = [None, None, None, None, None, None, None, None]
self.currentSide = WHITE
#elif simple :
#backRowBlack = [None, None, King(self, BLACK), None, Queen(self, BLACK), None, None, None]
#frontRowBlack = [None, None, None, None, None, None, None, None]

#frontRowWhite = [None, None, None, None, None, None, None, None]

#backRowWhite = [None, None, None, King(self, WHITE), Rook(self, WHITE), None, None, None]
#self.boardArray = []
#self.boardArray.append(backRowBlack)
#self.boardArray.append(frontRowBlack)
#for _ in range(4) :
#self.boardArray.append([None] * 8)
#self.boardArray.append(frontRowWhite)
#self.boardArray.append(backRowWhite)


frontRowWhite = [None, None, None, None, None, None, None, None]
#self.history = []
#self.pieces = list(filter(None, [piece for sublist in self.boardArray for piece in sublist]))
#for piece in self.pieces :
#piece.updatePosition()

backRowWhite = [None, None, None, King(self, WHITE), None, None, None, None]
self.boardArray = []
self.boardArray.append(backRowBlack)
self.boardArray.append(frontRowBlack)
for _ in range(4) :
self.boardArray.append([None] * 8)
self.boardArray.append(frontRowWhite)
self.boardArray.append(backRowWhite)

#self.points = 0

#elif mateInOne :
#self.boardArray.append([None, None, None, None, None, None, None, None])
#self.boardArray.append([None, None, None, None, None, None, None, None])
#self.boardArray.append([None, None, None, None, None, None, None, None])
#self.boardArray.append([None, None, None, None, None, None, None, None])
#self.boardArray.append([None, None, None, None, None, None, None, None])
#self.boardArray.append([None, None, None, King(self, BLACK), None, None, None, None])
#self.boardArray.append([None, None, None, None, None, None, None, Queen(self, BLACK)])
#self.boardArray.append([None, None, None, King(self, WHITE), None, None, None, None])

#self.history = []
#self.pieces = list(filter(None, [piece for sublist in self.boardArray for piece in sublist]))
#for piece in self.pieces :
#piece.updatePosition()
#self.currentSide = WHITE

#self.points = 0

self.history = []
self.pieces = list(filter(None, [piece for sublist in self.boardArray for piece in sublist]))
for piece in self.pieces :
piece.updatePosition()
print(self.pieces)

self.points = 0



Expand All @@ -85,7 +107,22 @@ def undoLastMove(self) :
self.addPieceToPosition(pieceTaken, lastMove.newPos)
self.pieces.append(pieceTaken)
pieceTaken.updatePosition()
self.currentSide = not self.currentSide

def isCheckmate(self) :
#if self.getLastMove().newPos == C(3, 1) :
#print(legalMove)
if len(self.getAllMovesLegal(self.currentSide)) == 0 :
for move in self.getAllMovesUnfiltered(not self.currentSide) :
pieceToTake = self.pieceAtPosition(move.newPos)
if pieceToTake and pieceToTake.stringRep == "K" :
return True
return False

def getLastMove(self) :
return self.history[-1][0]


def addMoveToHistory(self, move) :
#self.history.append([move, copy.deepcopy(self.pieceAtPosition(move.newPos))])

Expand All @@ -97,39 +134,23 @@ def addMoveToHistory(self, move) :
self.history.append([move, None])

def getCurrentSide(self) :
return self.pieceAtPosition(self.history[-1][0].newPos).side
return self.currentSide

def makeStringRep(self, boardArray) :
stringRep = ''
for x in range(8) :
for y in range(8) :
piece = boardArray[x][y]
pieceRep = ''
if piece is not None :
side = piece.side
color = 'blue' if side == WHITE else 'red'
pieceRep = ''
if isinstance(piece, Pawn) :
pieceRep = colored('P', color)

elif isinstance(piece, Rook) :
pieceRep = colored('R', color)

elif isinstance(piece, Knight) :
pieceRep = colored('N', color)

elif isinstance(piece, Bishop) :
pieceRep = colored('B', color)

elif isinstance(piece, King) :
pieceRep = colored('K', color)

elif isinstance(piece, Queen) :
pieceRep = colored('Q', color)

pieceRep = colored(piece.stringRep, color)
else :
pieceRep = 'x'
stringRep += pieceRep + ' '
stringRep += '\n'
stringRep = stringRep.strip()
return stringRep

def rankOfPiece(self, piece) :
Expand Down Expand Up @@ -276,6 +297,7 @@ def makeMove(self, move) :
self.points += pieceToTake.value

self.movePieceToPosition(pieceToMove, move.newPos)
self.currentSide = not self.currentSide

def getPointValueOfSide(self, side) :
points = 0
Expand Down
17 changes: 11 additions & 6 deletions InputParser.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,16 +27,24 @@ def moveForLongNotation(self, notation) :
return Move(oldPos, newPos)

def moveForShortNotation(self, notation) :
moves = self.getLegalMovesWithShortNotation()
moves = self.getLegalMovesWithShortNotation(self.side)
for move in moves :
if move.notation == notation :
return move
else :
return 'No match'

def getLegalMovesWithShortNotation(self) :
def notationForMove(self, move) :
side = self.board.getSideOfMove(move)
moves = self.getLegalMovesWithShortNotation(side)
for m in moves :
if m == move :
return m.notation


def getLegalMovesWithShortNotation(self, side) :
moves = []
for legalMove in self.board.getAllMovesLegal(self.side) :
for legalMove in self.board.getAllMovesLegal(side) :
moves.append(legalMove)
legalMove.notation = self.board.getShortNotationOfMove(legalMove)

Expand All @@ -52,9 +60,6 @@ def getLegalMovesWithShortNotation(self) :
for duplicateMove in duplicateNotationMoves :
duplicateMove.notation = self.board.getShortNotationOfMoveWithFileAndRank(duplicateMove)

for move in moves :
print(move)

return moves

def duplicateMovesFromMoves(self, moves) :
Expand Down
7 changes: 6 additions & 1 deletion Move.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,11 @@
class Move :

notation = None
check = False
checkmate = False
castle = False
pessant = False
stalemate = False

def __init__(self, oldPos, newPos) :
self.oldPos = oldPos
Expand All @@ -22,7 +27,7 @@ def __eq__(self, other) :
return False

def __hash__(self):
return hash((self.oldPos, self.newPos))
return hash((self.oldPos, self.newPos))



Expand Down
18 changes: 17 additions & 1 deletion MoveNode.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,17 @@ class MoveNode :
move = []
pointAdvantage = None
children = []
depth = 1

def __init__(self, move, children, parent) :
self.move = move
self.children = children
self.parent = parent

def __str__(self) :
stringRep = "Move : " + str(self.move) + " Point advantage : " + str(self.pointAdvantage)
stringRep = "Move : " + str(self.move) + " Point advantage : " + str(self.pointAdvantage) + " Checkmate : " + str(self.move.checkmate)
stringRep += "\n"

#stringRep = ""
for child in self.children :
stringRep += " " * self.getDepth() * 4
Expand All @@ -24,12 +26,26 @@ def __str__(self) :
#return "Move : " + str(self.move) + " Children : " + str(self.children)

def __gt__(self, other) :
if self.move.checkmate and not other.move.checkmate :
return True
if not self.move.checkmate and other.move.checkmate :
return False
if self.move.checkmate and other.move.checkmate :
return False
return self.pointAdvantage > other.pointAdvantage

def __lt__(self, other) :
if self.move.checkmate and not other.move.checkmate :
return False
if not self.move.checkmate and other.move.checkmate :
return True
if self.move.checkmate and other.move.checkmate :
return False
return self.pointAdvantage < other.pointAdvantage

def __eq__(self, other) :
if self.move.checkmate and other.move.checkmate :
return True
return self.pointAdvantage == other.pointAdvantage

def getHighestNode(self) :
Expand Down
12 changes: 4 additions & 8 deletions Pawn.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,26 +24,22 @@ def getPossibleMoves(self) :
self.hasMoved = False

# Pawn moves one up
movement = C(0, 1) if self.side is WHITE else C(0, -1)
movement = C(0, 1) if self.side == WHITE else C(0, -1)
advanceOnePosition = currentPosition + movement
if self.board.isValidPos(advanceOnePosition) :
if self.board.pieceAtPosition(advanceOnePosition) is None :
yield Move(currentPosition, advanceOnePosition)

#Pawn moves two up
if not self.hasMoved :
movement = C(0, 2) if self.side is WHITE else C(0, -2)
movement = C(0, 2) if self.side == WHITE else C(0, -2)
advanceTwoPosition = currentPosition + movement
if self.board.isValidPos(advanceTwoPosition) :
if self.board.pieceAtPosition(advanceTwoPosition) is None :
if self.board.pieceAtPosition(advanceTwoPosition) is None and self.board.pieceAtPosition(advanceOnePosition) is None:
yield Move(currentPosition, advanceTwoPosition)

#Pawn takes
movements = []
if self.side == WHITE :
movements = [C(1,1), C(-1,1)]
else :
movements = [C(1,-1), C(-1,-1)]
movements = [C(1,1), C(-1,1)] if self.side == WHITE else [C(1,-1), C(-1,-1)]

for movement in movements :
newPosition = self.position + movement
Expand Down
Loading

0 comments on commit 9e225a8

Please sign in to comment.