<commit_before>""" This module contains the AI search algorithm """

# pylint: disable=import-error
from res import types
from src import coordinate
from src import historynode
from src import rules

class AI(object):
    """ Class that stores the AI algorithm """
    def __init__(self, a, b):
        self.arbiter = rules.Rules()
        self.weightA = a
        self.weightB = b

    def getMovesForFoxPiece(self, theGame, foxLocation):
        """ Returns a GameNode for every legal move of a given fox. It must
        know the current board position. """
        x_board = foxLocation.get_x_board()
        y_board = foxLocation.get_y_board()
        moveList = self.getAllFoxCaptures(theGame, foxLocation)

        # Direction 3
        foxDestination = coordinate.Coordinate(x_board + 1, y_board)
        if self.arbiter.legalMoveP(theGame, foxLocation, foxDestination):
            moveState = transferNode(theGame)
            moveState.setState(foxDestination, types.FOX)
            moveState.setState(foxLocation, types.EMPTY)
            singleMove = transferNode(moveState)
            singleMove.score = self.evaluationFunction(moveState)
            singleMove.leafP = True
            singleMove.rootP = False
            moveList.append(singleMove)
        ##############################################################
        # if ([arbiter legalMoveP:theGame :x+1 :y+1 :x+2 :y])
        #    HistoryNode *singleMove = [HistoryNode new];
        #     [self transferNode: theGame: moveState];
        #     [moveState setState:x+1 :y-1 :2];
        #     [moveState setState:x :y :0];
        #     [singleMove initialize];
        #     [self transferNode:moveState :singleMove];
        #     [singleMove setScore:[self evaluationFunction:moveState]];
        #     [singleMove setLeafP: TRUE];
        #     [singleMove setRootP: FALSE];
        #     [moveList addObject: singleMove];
        # if ([arbiter legalMoveP:theGame :x+1 :y+1 :x+1 :y])
        #    HistoryNode *singleMove = [HistoryNode new];
        #     [self transferNode: theGame: moveState];
        #    [moveState setState:x :y-1 :2];
        #    [moveState setState:x :y :0];
        #     [singleMove initialize];
        #     [self transferNode:moveState :singleMove];
        #     [singleMove setScore:[self evaluationFunction:moveState]];
        #     [singleMove setLeafP: TRUE];
        #     [singleMove setRootP: FALSE];
        #     [moveList addObject: singleMove]; 
        # if ([arbiter legalMoveP:theGame :x+1 :y+1 :x :y])
        #    HistoryNode *singleMove = [HistoryNode new];
        #     [self transferNode: theGame: moveState];
        #    [moveState setState:x-1 :y-1 :2];
        #    [moveState setState:x :y :0];
        #     [singleMove initialize];
        #     [self transferNode:moveState :singleMove];
        #     [singleMove setScore:[self evaluationFunction:moveState]];
        #     [singleMove setLeafP: TRUE];
        #     [singleMove setRootP: FALSE];
        #     [moveList addObject: singleMove]; 
        # if ([arbiter legalMoveP:theGame :x+1 :y+1 :x :y+1])
        #     HistoryNode *singleMove = [HistoryNode new];
        #     [self transferNode: theGame: moveState];
        #     [moveState setState:x-1 :y :2];
        #     [moveState setState:x :y :0];
        #     [singleMove initialize];
        #     [self transferNode:moveState :singleMove];
        #     [singleMove setScore:[self evaluationFunction:moveState]];
        #     [singleMove setLeafP: TRUE];
        #     [singleMove setRootP: FALSE];
        #     [moveList addObject: singleMove]; 
        # if ([arbiter legalMoveP:theGame :x+1 :y+1 :x :y+2])
        #    HistoryNode *singleMove = [HistoryNode new];
        #     [self transferNode: theGame: moveState];
        #     [moveState setState:x-1 :y+1 :2];
        #     [moveState setState:x :y :0];
        #     [singleMove initialize];
        #     [self transferNode:moveState :singleMove];
        #     [singleMove setScore:[self evaluationFunction:moveState]];
        #     [singleMove setLeafP: TRUE];
        #     [singleMove setRootP: FALSE];
        #     [moveList addObject: singleMove];
        # if ([arbiter legalMoveP:theGame :x+1 :y+1 :x+1 :y+2])
        #    HistoryNode *singleMove = [HistoryNode new];
        #     [self transferNode: theGame: moveState];
        #    [moveState setState:x :y+1 :2];
        #    [moveState setState:x :y :0];
        #     [singleMove initialize];
        #     [self transferNode:moveState :singleMove];
        #     [singleMove setScore:[self evaluationFunction:moveState]];
        #     [singleMove setLeafP: TRUE];
        #     [singleMove setRootP: FALSE];
        #     [moveList addObject: singleMove]; 
        # if ([arbiter legalMoveP:theGame :x+1 :y+1 :x+2 :y+2])
        #     HistoryNode *singleMove = [HistoryNode new];
        #     [self transferNode: theGame: moveState];
        #     [moveState setState:x+1 :y+1 :2];
        #     [moveState setState:x :y :0];
        #     [singleMove initialize];
        #     [self transferNode:moveState :singleMove];
        #     [singleMove setScore:[self evaluationFunction:moveState]];
        #     [singleMove setLeafP: TRUE];
        #     [singleMove setRootP: FALSE];
        #     [moveList addObject: singleMove];
        return moveList

    def getAllFoxCaptures(self, theGame, location):
        """ This recursively finds all available captures for a single fox and
        returns the list of captures"""
        captureList = []
        x_board = location.get_x_board()
        y_board = location.get_y_board()
        for direction in range(1, 9):
            if self.arbiter.isACaptureP(theGame, location, direction):
                deltaX = rules.findXCoordinateFromDirection(direction)
                deltaY = rules.findYCoordinateFromDirection(direction)
                moveState = transferNode(theGame)
                destination = coordinate.Coordinate(x_board + deltaX,
                                                    y_board + deltaY)
                rules.makeCapture(moveState, location, destination)
                singleMove = transferNode(moveState)
                singleMove.score = self.evaluationFunction(moveState)
                singleMove.leafP = True
                singleMove.rootP = False
                captureList.append(singleMove)
                nextCapture = self.getAllFoxCaptures(moveState, destination)
                if nextCapture:
                    captureList.extend(nextCapture)
        return captureList

    def evaluationFunction(self, theGame):
        """ This function takes a game state and returns a score for the
        position. A positive score favors the geese, and a negative score
        favors the foxes. """
        valueA = 0.0
        valueB = 0.0
        victoryPoints = 0
        totalScore = 0.0

        for x in range(1, 8):
            for y in range(1, 8):
                try:
                    location = coordinate.Coordinate(x, y)
                except ValueError:
                    continue
                if theGame.getState(location) == types.GOOSE:
                    valueA += 1
                elif theGame.getState(location) == types.SUPERGOOSE:
                    valueA += 2
                    if 3 <= x <= 5 and 1 <= y <= 3:
                        valueB += 4 - y
                        victoryPoints += 1

        valueA -= 20
        valueB *= victoryPoints
        totalScore += self.weightA * valueA + self.weightB * valueB
        #self.evaluated += 1
        if theGame.geeseWinP():
            totalScore += 1000
        elif theGame.foxesWinP():
            totalScore -= 1000

        return totalScore

def transferNode(startNode):
    """ Copies input historynode to a new one and returns that """
    endNode = historynode.HistoryNode()
    for x in range(1, 8):
        for y in range(1, 8):
            try:
                location = coordinate.Coordinate(x, y)
            except ValueError:
                continue
            state = startNode.getState(location)
            endNode.setState(location, state)
    return endNode
<commit_msg>Implement getMovesForFoxPiece() and helper function<commit_after>""" This module contains the AI search algorithm """

# pylint: disable=import-error
from res import types
from src import coordinate
from src import historynode
from src import rules

class AI(object):
    """ Class that stores the AI algorithm """
    def __init__(self, a, b):
        self.arbiter = rules.Rules()
        self.weightA = a
        self.weightB = b

    def getMovesForFoxPiece(self, theGame, foxLocation):
        """ Returns a GameNode for every legal move of a given fox. theGame
        is the current board position. """
        x_board = foxLocation.get_x_board()
        y_board = foxLocation.get_y_board()
        moveList = self.getAllFoxCaptures(theGame, foxLocation)

        # Direction 1
        foxDestination = coordinate.Coordinate(x_board, y_board + 1)
        if self.arbiter.legalMoveP(theGame, foxLocation, foxDestination):
            moveList.append(self.getMovesForFoxPieceHelper(theGame,
                                                           foxLocation,
                                                           foxDestination))
        # Direction 2
        foxDestination = coordinate.Coordinate(x_board + 1, y_board + 1)
        if self.arbiter.legalMoveP(theGame, foxLocation, foxDestination):
            moveList.append(self.getMovesForFoxPieceHelper(theGame,
                                                           foxLocation,
                                                           foxDestination))
        # Direction 3
        foxDestination = coordinate.Coordinate(x_board + 1, y_board)
        if self.arbiter.legalMoveP(theGame, foxLocation, foxDestination):
            moveList.append(self.getMovesForFoxPieceHelper(theGame,
                                                           foxLocation,
                                                           foxDestination))
        # Direction 4
        foxDestination = coordinate.Coordinate(x_board + 1, y_board - 1)
        if self.arbiter.legalMoveP(theGame, foxLocation, foxDestination):
            moveList.append(self.getMovesForFoxPieceHelper(theGame,
                                                           foxLocation,
                                                           foxDestination))
        # Direction 5
        foxDestination = coordinate.Coordinate(x_board, y_board - 1)
        if self.arbiter.legalMoveP(theGame, foxLocation, foxDestination):
            moveList.append(self.getMovesForFoxPieceHelper(theGame,
                                                           foxLocation,
                                                           foxDestination))
        # Direction 6
        foxDestination = coordinate.Coordinate(x_board - 1, y_board - 1)
        if self.arbiter.legalMoveP(theGame, foxLocation, foxDestination):
            moveList.append(self.getMovesForFoxPieceHelper(theGame,
                                                           foxLocation,
                                                           foxDestination))
        # Direction 7
        foxDestination = coordinate.Coordinate(x_board - 1, y_board)
        if self.arbiter.legalMoveP(theGame, foxLocation, foxDestination):
            moveList.append(self.getMovesForFoxPieceHelper(theGame,
                                                           foxLocation,
                                                           foxDestination))
        # Direction 8
        foxDestination = coordinate.Coordinate(x_board - 1, y_board + 1)
        if self.arbiter.legalMoveP(theGame, foxLocation, foxDestination):
            moveList.append(self.getMovesForFoxPieceHelper(theGame,
                                                           foxLocation,
                                                           foxDestination))
        return moveList

    def getMovesForFoxPieceHelper(self, theGame, foxLocation, foxDestination):
        """ Return the new GameNode based on the fox's move """
        moveState = transferNode(theGame)
        moveState.setState(foxDestination, types.FOX)
        moveState.setState(foxLocation, types.EMPTY)
        singleMove = transferNode(moveState)
        singleMove.score = self.evaluationFunction(moveState)
        singleMove.leafP = True
        singleMove.rootP = False
        return singleMove

    def getAllFoxCaptures(self, theGame, location):
        """ This recursively finds all available captures for a single fox and
        returns the list of captures"""
        captureList = []
        x_board = location.get_x_board()
        y_board = location.get_y_board()
        for direction in range(1, 9):
            if self.arbiter.isACaptureP(theGame, location, direction):
                deltaX = rules.findXCoordinateFromDirection(direction)
                deltaY = rules.findYCoordinateFromDirection(direction)
                moveState = transferNode(theGame)
                destination = coordinate.Coordinate(x_board + deltaX,
                                                    y_board + deltaY)
                rules.makeCapture(moveState, location, destination)
                singleMove = transferNode(moveState)
                singleMove.score = self.evaluationFunction(moveState)
                singleMove.leafP = True
                singleMove.rootP = False
                captureList.append(singleMove)
                nextCapture = self.getAllFoxCaptures(moveState, destination)
                if nextCapture:
                    captureList.extend(nextCapture)
        return captureList

    def evaluationFunction(self, theGame):
        """ This function takes a game state and returns a score for the
        position. A positive score favors the geese, and a negative score
        favors the foxes. """
        valueA = 0.0
        valueB = 0.0
        victoryPoints = 0
        totalScore = 0.0

        for x in range(1, 8):
            for y in range(1, 8):
                try:
                    location = coordinate.Coordinate(x, y)
                except ValueError:
                    continue
                if theGame.getState(location) == types.GOOSE:
                    valueA += 1
                elif theGame.getState(location) == types.SUPERGOOSE:
                    valueA += 2
                    if 3 <= x <= 5 and 1 <= y <= 3:
                        valueB += 4 - y
                        victoryPoints += 1

        valueA -= 20
        valueB *= victoryPoints
        totalScore += self.weightA * valueA + self.weightB * valueB
        #self.evaluated += 1
        if theGame.geeseWinP():
            totalScore += 1000
        elif theGame.foxesWinP():
            totalScore -= 1000

        return totalScore

def transferNode(startNode):
    """ Copies input historynode to a new one and returns that """
    endNode = historynode.HistoryNode()
    for x in range(1, 8):
        for y in range(1, 8):
            try:
                location = coordinate.Coordinate(x, y)
            except ValueError:
                continue
            state = startNode.getState(location)
            endNode.setState(location, state)
    return endNode

{'fraction_non_alphanumeric': 0.09015699302977005, 'fraction_numerical': 0.009185069376587845, 'mean_word_length': 1.7666246170481168, 'pattern_counts': {'":': 0, '<': 11, '<?xml version=': 0, '>': 3, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 36, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1481548', 'n_tokens_mistral': 4152, 'n_tokens_neox': 3940, 'n_words': 996}