konaneAgent / game_rules.py
game_rules.py
Raw
from copy import deepcopy
import math

def makeBoard(rows, cols):
    return [['x' if (r+c)%2 == 0 else 'o' for c in range(cols)] for r in range(rows)]

def makeMove(board, move):
    return makePlayerMove(board, pieceAt(board, move[0]), move)

def makePlayerMove(board, player, move):
    if isLegalMove(board, player, move):
        newBoard = deepcopy(board)
        for jump in interpolateMove(move):
            _makeJump(newBoard, jump)
        return newBoard
    else:
        return board

def _makeJump(board, jump):
    mid = midPoint(jump)
    board[mid[0]][mid[1]] = " "
    board[jump[1][0]][jump[1][1]] = board[jump[0][0]][jump[0][1]]
    board[jump[0][0]][jump[0][1]] = " "

def moveLength(move):
    return abs(move[0][0] - move[1][0]) if verticalMove(move) else abs(move[0][1] - move[1][1])

def isLegalMove(board, player, move, loud=True):
    if not onBoard(len(board), len(board[0]), move[1]):
        if loud:
            print("Pieces must stay on the board")
        return False
    if pieceAt(board, move[0]) != player:
        if loud:
            print("You can only move your own pieces")
        return False
    length = moveLength(move)
    if length % 2 == 1:
        if loud:
            print("Cannot move an odd number of squares")
        return False
    if length == 0:
        if loud:
            print("Cannot stay put")
        return False
    other = 'o' if player == 'x' else 'x'
    hasJumped = False
    for jump in interpolateMove(move):
        if not isLegalJump(board, player, other, jump):
            if loud:
                print("Illegal move")
            return False
        board = deepcopy(board)
        _makeJump(board, jump)
        hasJumped = True
    return hasJumped

def isLegalJump(board, player, other, jump):
    return pieceAt(board, jump[0]) == player and pieceAt(board, midPoint(jump)) == other and pieceAt(board, jump[1]) == " "

def isInitialMove(board):
    return countPieces(board, ' ') < 2

def countPieces(board, piece):
    return sum([sum([1 if c == piece else 0 for c in row]) for row in board])

def interpolateMove(move):
    points = []
    if horizontalMove(move):
        step = 2 if move[0][1] < move[1][1] else -2
        points = [(move[0][0], c) for c in range(move[0][1], move[1][1] + step, step)]
    elif verticalMove(move):
        step = 2 if move[0][0] < move[1][0] else -2
        points = [(r, move[0][1]) for r in range(move[0][0], move[1][0] + step, step)]
    else: return []
    
    return zip(points, points[1:])

def midPoint(move):
    if horizontalMove(move): return (move[0][0], int((move[0][1] + move[1][1])/2))
    elif verticalMove(move): return (int((move[0][0] + move[1][0])/2), move[0][1])
    else: print("Cannot move diagonally")

def horizontalMove(move):
    return move[0][0] == move[1][0]

def verticalMove(move):
    return move[0][1] == move[1][1]

def pieceAt(board, point):
    return board[point[0]][point[1]]

def onBoard(rows, cols, point):
    return 0 <= point[0] and point[0] < rows and 0 <= point[1] and point[1] < cols

def getNeighbors(board, point):
    rows = len(board)
    cols = len(board[0])
    return set(filter(lambda pt: onBoard(rows, cols, pt), [(point[0]-1, point[1])
            , (point[0]+1, point[1])
            , (point[0], point[1]-1)
            , (point[0], point[1]+1)]))

def getCorners(board):
    return set([(0, 0), (len(board)-1, 0), (0, len(board[0])-1), (len(board)-1, len(board[0])-1)])

def getMiddles(board):
    rm = (len(board) - 1) / 2.
    rowMid = [math.floor(rm), math.ceil(rm)]
    cm = (len(board[0]) - 1) / 2.
    colMid = [math.floor(cm), math.ceil(cm)]
    return set([(int(r), int(c)) for r in rowMid for c in colMid])

def getEmptySquares(board):
    return set((r, c) for r in range(len(board)) for c in range(len(board[0])) if board[r][c] == " ")

def getFirstMovesForX(board):
    return set(filter(lambda pt: pieceAt(board, pt) == 'x', getCorners(board).union(getMiddles(board))))

def getFirstMovesForO(board):
    return getNeighbors(board, getEmptySquares(board).pop())

def getLegalMoves(board, symbol):
    empties = getEmptySquares(board)
    if len(empties) == 0: return getFirstMovesForX(board)
    elif len(empties) == 1: return getFirstMovesForO(board)
    else:
        mine = [(r, c) for r in range(len(board)) for c in range(len(board[0])) if pieceAt(board, (r, c)) == symbol]
        allMoves = [(o, d) for o in mine for d in empties]
        return [move for move in allMoves if isLegalMove(board, symbol, move, False)]

def linearizeBoard(board):
    return "".join(["".join(row) for row in board])

def delinearizeBoard(rawBoard, rows, cols):
    board = [list(rawBoard[i:i+cols]) for i in range(0, len(rawBoard), cols)]
    assert len(board) == rows, print("Problem parsing board! Expected {} rows, got {}.".format(rows, len(board)))
    return board

def printBoard(board):
    for row in board: print("".join(row))
    print()