Skip to content

Commit

Permalink
Add parsing of coordinate and ambiguous notation moves
Browse files Browse the repository at this point in the history
  • Loading branch information
ddugovic committed Dec 31, 2017
1 parent 46b4af5 commit 5d7a931
Show file tree
Hide file tree
Showing 4 changed files with 117 additions and 44 deletions.
67 changes: 50 additions & 17 deletions src/Board.py
Original file line number Diff line number Diff line change
Expand Up @@ -197,7 +197,37 @@ def fileOfPiece(self, piece):
transTable = str.maketrans('01234567', 'abcdefgh')
return str(piece.position[0]).translate(transTable)

def getShortNotationOfMove(self, move):
def getCoordinateNotationOfMove(self, move):
notation = ""
notation += self.positionToHumanCoord(move.oldPos)
notation += self.positionToHumanCoord(move.newPos)

if move.promotion:
notation += str(move.specialMovePiece.stringRep)

return notation

def getCaptureNotation(self, move, short=False):
notation = ""
pieceToMove = move.piece
pieceToTake = move.pieceToCapture

if type(pieceToMove) is Pawn:
notation += self.fileOfPiece(pieceToMove)
else:
notation += pieceToMove.stringRep
notation += 'x'
if short:
notation += pieceToTake.stringRep
else:
notation += self.positionToHumanCoord(move.newPos)

if move.promotion:
notation += str(move.specialMovePiece.stringRep)

return notation

def getAlgebraicNotationOfMove(self, move, short=True):
notation = ""
pieceToMove = move.piece
pieceToTake = move.pieceToCapture
Expand All @@ -208,11 +238,11 @@ def getShortNotationOfMove(self, move):
if move.kingsideCastle:
return "O-O"

if pieceToMove.stringRep != 'p':
if not short or type(pieceToMove) is not Pawn:
notation += pieceToMove.stringRep

if pieceToTake is not None:
if pieceToMove.stringRep == 'p':
if short and type(pieceToMove) is Pawn:
notation += self.fileOfPiece(pieceToMove)
notation += 'x'

Expand All @@ -223,55 +253,58 @@ def getShortNotationOfMove(self, move):

return notation

def getShortNotationOfMoveWithFile(self, move):
# TODO: Use self.getShortNotationOfMove instead of repeating code
def getAlgebraicNotationOfMoveWithFile(self, move, short=True):
# TODO: Use self.getAlgebraicNotationOfMove instead of repeating code
notation = ""
pieceToMove = self.pieceAtPosition(move.oldPos)
pieceToTake = self.pieceAtPosition(move.newPos)

if pieceToMove.stringRep != 'p':
if not short or type(pieceToMove) is not Pawn:
notation += pieceToMove.stringRep
notation += self.fileOfPiece(pieceToMove)
notation += self.fileOfPiece(pieceToMove)

if pieceToTake is not None:
notation += 'x'

notation += self.positionToHumanCoord(move.newPos)
return notation

def getShortNotationOfMoveWithRank(self, move):
# TODO: Use self.getShortNotationOfMove instead of repeating code
def getAlgebraicNotationOfMoveWithRank(self, move, short=True):
# TODO: Use self.getAlgebraicNotationOfMove instead of repeating code
notation = ""
pieceToMove = self.pieceAtPosition(move.oldPos)
pieceToTake = self.pieceAtPosition(move.newPos)

if pieceToMove.stringRep != 'p':
if not short or type(pieceToMove) is not Pawn:
notation += pieceToMove.stringRep
notation += self.rankOfPiece(pieceToMove)

notation += self.rankOfPiece(pieceToMove)

if pieceToTake is not None:
if short and type(pieceToMove) is Pawn:
notation += self.fileOfPiece(pieceToMove)
notation += 'x'

notation += self.positionToHumanCoord(move.newPos)
return notation

def getShortNotationOfMoveWithFileAndRank(self, move):
# TODO: Use self.getShortNotationOfMove instead of repeating code
def getAlgebraicNotationOfMoveWithFileAndRank(self, move, short=True):
# TODO: Use self.getAlgebraicNotationOfMove instead of repeating code
notation = ""
pieceToMove = self.pieceAtPosition(move.oldPos)
pieceToTake = self.pieceAtPosition(move.newPos)

if pieceToMove.stringRep != 'p':
if not short or type(pieceToMove) is not Pawn:
notation += pieceToMove.stringRep
notation += self.fileOfPiece(pieceToMove)
notation += self.rankOfPiece(pieceToMove)

notation += self.fileOfPiece(pieceToMove)
notation += self.rankOfPiece(pieceToMove)

if pieceToTake is not None:
notation += 'x'

notation += self.positionToHumanCoord(move.newPos)
return notation
return

def humanCoordToPosition(self, coord):
transTable = str.maketrans('abcdefgh', '12345678')
Expand Down
66 changes: 53 additions & 13 deletions src/InputParser.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import re
from Pawn import Pawn


class InputParser:
Expand All @@ -8,44 +9,83 @@ def __init__(self, board, side):
self.side = side

def parse(self, humanInput):
humanInput = humanInput.lower()
regexShortNotation = re.compile('[rnbkqp][a-z][1-8]')
if regexShortNotation.match(humanInput):
return self.moveForShortNotation(humanInput)
regexCoordinateNotation = re.compile('[a-h][1-8][a-h][1-8][qrbn]?')
if regexCoordinateNotation.match(humanInput):
return self.moveForCoordinateNotation(humanInput)
regexAlgebraicNotation = re.compile('(?i)O-O|O-O-O|(?:[KQRBNP]?[a-h]?[1-8]?x?[a-h][1-8]|(?:[Pa-h]x?|x)[a-h])(?:=?[QRBN])?')
if regexAlgebraicNotation.match(humanInput):
return self.moveForShortAlgebraicNotation(humanInput)
raise ValueError("Invalid input: %s" % humanInput)

def moveForShortNotation(self, notation):
moves = self.getLegalMovesWithShortNotation(self.side)
def moveForCoordinateNotation(self, notation):
for move in self.board.getAllMovesLegal(self.side):
if self.board.getCoordinateNotationOfMove(move) == notation:
move.notation = self.notationForMove(move)
return move
raise ValueError("Invalid move: %s" % notation)

# Only handles SAN, not long-algebraic or descriptive
def moveForShortAlgebraicNotation(self, notation):
shortNotation = notation.replace("x","")
moves = self.getLegalMovesWithNotation(self.side, False)
for move in moves:
if move.notation.replace("x","") == shortNotation: # Bxc3 versus bxc3
return move
for move in moves:
if move.notation.replace("x","").lower() == shortNotation.lower():
return move
moves = self.getLegalMovesWithNotation(self.side, True)
for move in moves:
if move.notation.replace("x","") == shortNotation: # Bxc3 versus bxc3
return move
for move in moves:
if move.notation.lower() == notation.lower():
if move.notation.replace("x","").lower() == shortNotation.lower():
return move
shortNotation = notation.lower().replace("p","").replace("=","")
if re.compile('[a-h][1-8]?[qrbn]?').match(shortNotation):
for move in moves:
if type(move.piece) is Pawn and not move.pieceToCapture and self.board.getCoordinateNotationOfMove(move).replace("=","").endswith(shortNotation):
return move
for move in moves:
if type(move.piece) is Pawn and not move.pieceToCapture and re.sub("[1-8]", "", self.board.getCoordinateNotationOfMove(move)).replace("=","").endswith(shortNotation):
return move # ASSUME lazy pawn move (P)c is unambiguous
shortNotation = shortNotation.lower().replace("x","")
if re.compile('[a-h]?[a-h][1-8]?[qrbn]?').match(shortNotation):
for move in moves:
if type(move.piece) is Pawn and move.pieceToCapture and self.board.getCaptureNotation(move).replace("x","").endswith(shortNotation):
return move # ASSUME lazier pawn capture (P)(b)(x)c3 is unambiguous
for move in moves:
if type(move.piece) is Pawn and move.pieceToCapture and re.sub("[1-8]", "", self.board.getCaptureNotation(move).replace("x","")).endswith(shortNotation):
return move # ASSUME laziest pawn capture (P)(b)(x)c is unambiguous
raise ValueError("Invalid SAN move: %s" % notation)

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

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

duplicateNotationMoves = self.duplicateMovesFromMoves(moves)
for duplicateMove in duplicateNotationMoves:
duplicateMove.notation = \
self.board.getShortNotationOfMoveWithFile(duplicateMove)
self.board.getAlgebraicNotationOfMoveWithFile(duplicateMove, short)

duplicateNotationMoves = self.duplicateMovesFromMoves(moves)
for duplicateMove in duplicateNotationMoves:
duplicateMove.notation = \
self.board.getShortNotationOfMoveWithRank(duplicateMove)
self.board.getAlgebraicNotationOfMoveWithRank(duplicateMove, short)

duplicateNotationMoves = self.duplicateMovesFromMoves(moves)
for duplicateMove in duplicateNotationMoves:
duplicateMove.notation = \
self.board.getShortNotationOfMoveWithFileAndRank(duplicateMove)
self.board.getAlgebraicNotationOfMoveWithFileAndRank(duplicateMove, short)

return moves

Expand Down
2 changes: 1 addition & 1 deletion src/Pawn.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@

class Pawn(Piece):

stringRep = 'p'
stringRep = 'P'
value = 1

def __init__(self, board, side, position, movesMade=0):
Expand Down
26 changes: 13 additions & 13 deletions src/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ def printCommandOptions():


def printAllLegalMoves(board, parser):
for move in parser.getLegalMovesWithShortNotation(board.currentSide):
for move in parser.getLegalMovesWithNotation(board.currentSide, short=True):
print(move.notation)


Expand Down Expand Up @@ -93,26 +93,26 @@ def startGame(board, playerSide, ai):
# printPointAdvantage(board)
move = None
command = input("It's your move."
" Type '?' for options. ? ").lower()
if command == 'u':
" Type '?' for options. ? ")
if command.lower() == 'u':
undoLastTwoMoves(board)
continue
elif command == '?':
elif command.lower() == '?':
printCommandOptions()
continue
elif command == 'l':
elif command.lower() == 'l':
printAllLegalMoves(board, parser)
continue
elif command == 'r':
elif command.lower() == 'r':
move = getRandomMove(board, parser)
elif command == 'quit':
elif command.lower() == 'exit' or command.lower() == 'quit':
return
else:
move = parser.moveForShortNotation(command)
if move:
makeMove(move, board)
else:
print("Couldn't parse input, enter a valid command or move.")
try:
move = parser.parse(command)
except ValueError as error:
print("%s" % error)
continue
makeMove(move, board)

else:
print("AI thinking...")
Expand Down

0 comments on commit 5d7a931

Please sign in to comment.