def getAllPossibleGrid(grid: Grid, dir) -> List[Grid]: ''' :param grid: A grid :param dir: A move :return: a list of all possible result of move ''' if grid.isTerminal(): # return the original grid if the game is terminal return [grid.clone()] ret = grid.clone() ret.move(dir) if not grid.canMove([dir]): raise ValueError('Invalid Move') cells = ret.getAvailableCells() grids = [] for cell in cells: ret2 = ret.clone() ret2.setCellValue(cell, 2) grids.append(ret2) return grids
class GameManager: def __init__(self, size=4): self.grid = Grid(size) self.possibleNewTiles = [2, 4] self.probability = defaultProbability self.initTiles = defaultInitialTiles self.computerAI = None self.playerAI = None self.displayer = None self.over = False def setComputerAI(self, computerAI): self.computerAI = computerAI def setPlayerAI(self, playerAI): self.playerAI = playerAI def setDisplayer(self, displayer): self.displayer = displayer def updateAlarm(self, currTime): if currTime - self.prevTime > timeLimit + allowance: self.over = True else: while time.clock() - self.prevTime < timeLimit + allowance: pass self.prevTime = time.clock() def start(self): for i in range(self.initTiles): self.insertRandonTile() self.displayer.display(self.grid) # Player AI Goes First turn = PLAYER_TURN maxTile = 0 self.prevTime = time.clock() while not self.isGameOver() and not self.over: # Copy to Ensure AI Cannot Change the Real Grid to Cheat gridCopy = self.grid.clone() move = None if turn == PLAYER_TURN: print("Player's Turn:") move = self.playerAI.getMove(gridCopy) print(actionDic[move]) # Validate Move if move != None and move >= 0 and move < 4: if self.grid.canMove([move]): self.grid.move(move) # Update maxTile maxTile = self.grid.getMaxTile() else: print("Invalid PlayerAI Move") self.over = True else: print("Invalid PlayerAI Move - 1") self.over = True else: print("Computer's turn:") move = self.computerAI.getMove(gridCopy) # Validate Move if move and self.grid.canInsert(move): self.grid.setCellValue(move, self.getNewTileValue()) else: print("Invalid Computer AI Move") self.over = True if not self.over: self.displayer.display(self.grid) # Exceeding the Time Allotted for Any Turn Terminates the Game self.updateAlarm(time.clock()) turn = 1 - turn print(maxTile) def isGameOver(self): return not self.grid.canMove() def getNewTileValue(self): if randint(0, 99) < 100 * self.probability: return self.possibleNewTiles[0] else: return self.possibleNewTiles[1] def insertRandonTile(self): tileValue = self.getNewTileValue() cells = self.grid.getAvailableCells() cell = cells[randint(0, len(cells) - 1)] self.grid.setCellValue(cell, tileValue)
class GameManager: def __init__(self, size=4, intelligentAgent=None, computerAI=None, displayer=None): self.grid = Grid(size) self.possibleNewTiles = [2, 4] self.probability = defaultProbability self.initTiles = defaultInitialTiles self.over = False # Initialize the AI players self.computerAI = computerAI or ComputerAI() self.intelligentAgent = intelligentAgent or IntelligentAgent() self.displayer = displayer or Displayer() def updateAlarm(self) -> None: """ Checks if move exceeded the time limit and updates the alarm """ if time.process_time() - self.prevTime > maxTime: raise Exception( f'Too much time of {time.process_time() - self.prevTime}') self.over = True self.prevTime = time.process_time() def getNewTileValue(self) -> int: """ Returns 2 with probability 0.95 and 4 with 0.05 """ return self.possibleNewTiles[random.random() > self.probability] def insertRandomTiles(self, numTiles: int): """ Insert numTiles number of random tiles. For initialization """ for i in range(numTiles): tileValue = self.getNewTileValue() cells = self.grid.getAvailableCells() cell = random.choice(cells) if cells else None self.grid.setCellValue(cell, tileValue) def start(self) -> int: """ Main method that handles running the game of 2048 """ # Initialize the game self.insertRandomTiles(self.initTiles) self.displayer.display(self.grid) turn = PLAYER_TURN # Player AI Goes First self.prevTime = time.process_time() while self.grid.canMove() and not self.over: # Copy to Ensure AI Cannot Change the Real Grid to Cheat gridCopy = self.grid.clone() move = None if turn == PLAYER_TURN: print("Player's Turn: ", end="") move = self.intelligentAgent.getMove(gridCopy) print("Trying to do player turn") print(actionDic[move]) # If move is valid, attempt to move the grid if move != None and 0 <= move < 4: if self.grid.canMove([move]): self.grid.move(move) else: print("Invalid intelligentAgent Move - Cannot move") self.over = True else: print("Invalid intelligentAgent Move - Invalid input") self.over = True else: print("Computer's turn: ") move = self.computerAI.getMove(gridCopy) # Validate Move print("Trying to do computer") if move and self.grid.canInsert(move): self.grid.setCellValue(move, self.getNewTileValue()) else: print("Invalid Computer AI Move") self.over = True # Comment out during heuristing optimizations to increase runtimes. # Printing slows down computation time. self.displayer.display(self.grid) # Exceeding the Time Allotted for Any Turn Terminates the Game self.updateAlarm() turn = 1 - turn print(f'This means it can move {self.over}') return self.grid.getMaxTile()
class GameManager: def __init__(self, size = 4): # init some variables self.grid = Grid(size) self.possibleNewTileValue = [2, 4] self.possibility = defaultPossibility self.initTiles = defaultInitialTiles self.computerAI = None self.playerAI = None self.displayer = None self.over = False def setComputerAI(self, compAI): self.computerAI = compAI def setPlayerAI(self, playerAI): self.playerAI = playerAI def setDisplayer(self, displayer): self.displayer = displayer def updateAlarm(self, curTime): # 0.1 sec for the running time outside the AI module if curTime - self.lastTime > timeLimit + 0.1: self.over = True else: self.lastTime = curTime def start(self): #insert 2 random tiles for i in xrange(self.initTiles): self.insertRandonTile() # show the initial grid state self.displayer.display(self.grid) #player plays first turn = PLAYER_TURN maxTile = 0 # set init alarm self.lastTime = time.clock()#time.time() # check game over conditions while not self.isGameOver() and not self.over: # make a copy make sure AI cannot change the real grid and cheat gridCopy = self.grid.clone() move = None if turn == PLAYER_TURN: print "Player's Turn" move = self.playerAI.getMove(gridCopy) print actionDic[move] #validate move if move != None and move >= 0 and move < 4: if self.grid.canMove([move]): self.grid.move(move) #update maxTile maxTile = self.grid.getMaxTile() else: print "Invalid PlayerAI Move" self.over = True else: print "Invalid PlayerAI Move - 1" self.over = True else: # computer turn print "Computer's turn" move = self.computerAI.getMove(gridCopy) # move should be (x, y) format #validate move if self.grid.canInsert(move): self.grid.setCellValue(move, self.getNewTileValue()) else: print "Invalid Computer AI Move" self.over = True if not self.over: self.displayer.display(self.grid) # once you exceeds the time limit, previous action will be your last action self.updateAlarm(time.clock()) #time.time() turn = 1 - turn print maxTile def isGameOver(self): return not self.grid.canMove() def getNewTileValue(self): if randint(0,99) < 100 * self.possibility: return self.possibleNewTileValue[0] else: return self.possibleNewTileValue[1] def insertRandonTile(self): tileValue = self.getNewTileValue() cells = self.grid.getAvailableCells() cell = cells[randint(0, len(cells) - 1)] self.grid.setCellValue(cell, tileValue)
class GameManager: def __init__(self, size = 4): self.grid = Grid(size) self.possibleNewTiles = [2, 4] self.probability = defaultProbability self.initTiles = defaultInitialTiles self.computerAI = None self.playerAI = None self.displayer = None self.over = False def setComputerAI(self, computerAI): self.computerAI = computerAI def setPlayerAI(self, playerAI): self.playerAI = playerAI def setDisplayer(self, displayer): self.displayer = displayer def updateAlarm(self, currTime): # print "time elapsed = ", currTime - self.prevTime # st = raw_input() if currTime - self.prevTime > timeLimit + allowance: self.over = True else: while time.clock() - self.prevTime < timeLimit + allowance: pass self.prevTime = time.clock() def start(self): for i in xrange(self.initTiles): self.insertRandonTile() #self.displayer.display(self.grid) # Player AI Goes First turn = PLAYER_TURN maxTile = 0 self.prevTime = time.clock() while not self.isGameOver() and not self.over: # Copy to Ensure AI Cannot Change the Real Grid to Cheat gridCopy = self.grid.clone() move = None if turn == PLAYER_TURN: print "Player's Turn:", move = self.playerAI.getMove(gridCopy) print actionDic[move] # Validate Move if move != None and move >= 0 and move < 4: if self.grid.canMove([move]): self.grid.move(move) # Update maxTile maxTile = self.grid.getMaxTile() else: print "Invalid PlayerAI Move" self.over = True else: print "Invalid PlayerAI Move - 1" self.over = True else: print "Computer's turn:" move = self.computerAI.getMove(gridCopy) # Validate Move if move and self.grid.canInsert(move): self.grid.setCellValue(move, self.getNewTileValue()) else: print "Invalid Computer AI Move" self.over = True if not self.over: self.displayer.display(self.grid) # Exceeding the Time Allotted for Any Turn Terminates the Game self.updateAlarm(time.clock()) turn = 1 - turn print maxTile def isGameOver(self): return not self.grid.canMove() def getNewTileValue(self): if randint(0,99) < 100 * self.probability: return self.possibleNewTiles[0] else: return self.possibleNewTiles[1]; def insertRandonTile(self): tileValue = self.getNewTileValue() cells = self.grid.getAvailableCells() cell = cells[randint(0, len(cells) - 1)] self.grid.setCellValue(cell, tileValue)
class GameManager: def __init__(self, size = 4): self.grid = Grid(size) self.possibleNewTiles = [2, 4] self.probability = defaultProbability self.initTiles = defaultInitialTiles self.computerAI = None self.playerAI = None self.displayer = None self.over = False def setComputerAI(self, computerAI): self.computerAI = computerAI def setPlayerAI(self, playerAI): self.playerAI = playerAI def setDisplayer(self, displayer): self.displayer = displayer def updateAlarm(self, currTime): if currTime - self.prevTime > timeLimit + allowance: self.over = True print ("time over") pass else: while time.clock() - self.prevTime < timeLimit + allowance: pass self.prevTime = time.clock() def start(self): for i in xrange(self.initTiles): self.insertRandonTile() self.displayer.display(self.grid) # Player AI Goes First turn = PLAYER_TURN maxTile = 0 self.prevTime = time.clock() while not self.isGameOver() and not self.over: # Copy to Ensure AI Cannot Change the Real Grid to Cheat gridCopy = self.grid.clone() move = None if turn == PLAYER_TURN: # print "Player's Turn:", move = self.playerAI.getMove(gridCopy) print actionDic[move] # Validate Move if move != None and move >= 0 and move < 4: if self.grid.canMove([move]): self.grid.move(move) # Update maxTile maxTile = self.grid.getMaxTile() print ("max: %d, free: %d, " %(maxTile,len(self.grid.getAvailableCells()))) else: print "Invalid PlayerAI Move" self.over = True else: print "Invalid PlayerAI Move - 1" self.over = True self.displayer.display(self.grid) # s = Node(self.grid) # print(" eval: " + str(s.eval(True))+"\n") # v = raw_input() print("stopped @ depth %d" %self.playerAI.IDSDepth) s = 0 for count in self.playerAI.exploredNodes: l = len(self.playerAI.exploredNodes[count]) print("%d: %d" %(count,l)) s += l print("total :%s" %s) else: # print "Computer's turn:" move = self.computerAI.getMove(gridCopy) # Validate Move if move and self.grid.canInsert(move): self.grid.setCellValue(move, self.getNewTileValue()) else: print "Invalid Computer AI Move" self.over = True # s = Node(self.grid) # print(" eval: " + str(s.eval(True))+"\n") if not self.over: # self.displayer.display(self.grid) pass # Exceeding the Time Allotted for Any Turn Terminates the Game self.updateAlarm(time.clock()) turn = 1 - turn print maxTile def isGameOver(self): return not self.grid.canMove() def getNewTileValue(self): if randint(0,99) < 100 * self.probability: return self.possibleNewTiles[0] else: return self.possibleNewTiles[1]; def insertRandonTile(self): tileValue = self.getNewTileValue() cells = self.grid.getAvailableCells() cell = cells[randint(0, len(cells) - 1)] self.grid.setCellValue(cell, tileValue)
class MyGame: def __init__(self, size=4): self.grid = Grid(size) self.possibleNewTiles = [2, 4] self.probability = 0.9 self.initTiles = 2 self.displayer = Displayer() self.timer = 0 self.turns = 2 def get_move(self, gridCopy): # all the rest code is demo. here is the important code: my_tree = BuildTree(gridCopy) my_tree.build_it(0) return my_tree.get_best_move() # print('AvailableCells:') # print(self.grid.getAvailableCells()) # [(0, 1), (0, 2), (0, 3), (1, 0) ...] # print('AvailableMoves:') # print(self.grid.getAvailableMoves()) # [1, 2, 3] or [0, 1, 2, 3] ... # if self.grid.canMove([move]): # self.grid.move(move) # self.grid.getAvailableCells() # self.grid.getAvailableMoves() # self.grid.insertTile(pos, value) -> maybe redundant and 'move' is enough # self.grid.clone() # maxTile = self.grid.getMaxTile() # ACTIONS = { # 0: "UP", # 1: "DOWN", # 2: "LEFT", # 3: "RIGHT" # } # return randint(0, 3) def getNewTileValue(self): if randint(0, 99) < 100 * self.probability: return self.possibleNewTiles[0] else: return self.possibleNewTiles[1] def insertRandonTile(self): tileValue = self.getNewTileValue() cells = self.grid.getAvailableCells() cell = cells[randint(0, len(cells) - 1)] self.grid.setCellValue(cell, tileValue) def start(self): for i in range(self.initTiles): self.insertRandonTile() self.displayer.display(self.grid) maxTile = 0 while self.timer < self.turns: gridCopy = self.grid.clone() move = self.get_move(gridCopy) print('move: ', str(move)) if self.grid.canMove([move]): self.grid.move(move) maxTile = self.grid.getMaxTile() self.timer += 1 else: print("Invalid Move") self.displayer.display(self.grid) print('max tile:', str(maxTile))
class GameManager: def __init__(self, size = 4): #self.grid = Grid(size) self.possibleNewTiles = [2, 4] self.probability = defaultProbability self.initTiles = defaultInitialTiles self.computerAI = None self.playerAI = None self.over = False self.grid = Grid(size) def setComputerAI(self, computerAI): self.computerAI = computerAI def setPlayerAI(self, playerAI): self.playerAI = playerAI def updateAlarm(self, currTime): if currTime - self.prevTime > timeLimit + allowance: print 'Out of time' self.over = True else: while time.clock() - self.prevTime < timeLimit + allowance: pass self.prevTime = time.clock() def start(self): #for i in xrange(self.initTiles): # self.insertRandonTile() sel_board = randint(0, 4) if sel_board == 0: self.board1(self.grid) elif sel_board == 1: self.board2(self.grid) elif sel_board == 2: self.board3(self.grid) elif sel_board == 3: self.board4(self.grid) else: self.board5(self.grid) # Player AI Goes First turn = PLAYER_TURN maxTile = 0 self.prevTime = time.clock() while not self.isGameOver() and not self.over: # Copy to Ensure AI Cannot Change the Real Grid to Cheat gridCopy = self.grid.clone() move = None if turn == PLAYER_TURN: #print "Player's Turn:", move = self.playerAI.getMove(gridCopy) #print actionDic[move] # Validate Move if move != None and move >= 0 and move < 4: if self.grid.canMove([move]): self.grid.move(move) #self.playerAI.utility(self.grid, True) # Update maxTile maxTile = self.grid.getMaxTile() else: #print "Invalid PlayerAI Move" self.over = True else: #print "Invalid PlayerAI Move - 1" self.over = True else: #print "Computer's turn:" move = self.computerAI.getMove(gridCopy) # Validate Move if move and self.grid.canInsert(move): self.grid.setCellValue(move, self.getNewTileValue()) else: print "Invalid Computer AI Move" self.over = True # Exceeding the Time Allotted for Any Turn Terminates the Game self.updateAlarm(time.clock()) turn = 1 - turn def isGameOver(self): return not self.grid.canMove() def getNewTileValue(self): if randint(0,99) < 100 * self.probability: return self.possibleNewTiles[0] else: return self.possibleNewTiles[1]; def insertRandonTile(self): tileValue = self.getNewTileValue() cells = self.grid.getAvailableCells() cell = cells[randint(0, len(cells) - 1)] self.grid.setCellValue(cell, tileValue) # Have predefined board conditions to explore games from an advanced state. def board1(self, grid): grid.map = [[2, 0, 2, 0], [4, 32, 16, 4], [2, 4, 128, 16], [128, 1024, 4, 2]] def board2(self, grid): grid.map = [[8, 8, 4, 2], [1024, 16, 64, 4], [4, 128, 16, 2], [256, 4, 0, 0]] def board3(self, grid): grid.map = [[0, 0, 4, 32], [0, 0, 0, 512], [2, 4, 8, 64], [0, 8, 32, 16]] def board4(self, grid): grid.map = [[2, 2, 4, 0], [1024, 32, 16, 0], [64, 512, 8, 8], [8, 2, 4, 2]] def board5(self, grid): grid.map = [[32, 16, 8, 0], [1024, 8, 16, 0], [8, 0, 0, 0], [4, 2, 2, 0]]
class GameManager: def __init__(self, size = 4): # init some variables self.grid = Grid(size) self.possibleNewTileValue = [2, 4] self.possibility = defaultPossibility self.initTiles = defaultInitialTiles self.computerAI = None self.playerAI = None self.displayer = None self.over = False def setComputerAI(self, compAI): self.computerAI = compAI def setPlayerAI(self, playerAI): self.playerAI = playerAI def setDisplayer(self, displayer): self.displayer = displayer def updateAlarm(self, curTime): # 0.1 sec for the running time outside the AI module if curTime - self.lastTime > timeLimit + 0.1: self.over = True else: self.lastTime = curTime def start(self): #insert 2 random tiles for i in xrange(self.initTiles): self.insertRandonTile() # show the initial grid state self.displayer.display(self.grid) #player plays first turn = PLAYER_TURN maxTile = 0 # set init alarm self.lastTime = time.clock() # check game over conditions while not self.isGameOver() and not self.over: # make a copy make sure AI cannot change the real grid and cheat gridCopy = self.grid.clone() move = None if turn == PLAYER_TURN: print "Player's Turn" move = self.playerAI.getMove(gridCopy) print actionDic[move] #validate move if move != None and move >= 0 and move < 4: if self.grid.canMove([move]): self.grid.move(move) #update maxTile maxTile = self.grid.getMaxTile() else: print "Invalid PlayerAI Move" self.over = True else: print "Invalid PlayerAI Move - 1" self.over = True else: print "Computer's turn" move = self.computerAI.getMove(gridCopy) #validate move if move and self.grid.canInsert(move): self.grid.setCellValue(move, self.getNewTileValue()) else: print "Invalid Computer AI Move" self.over = True if not self.over: self.displayer.display(self.grid) # once you exceeds the time limit, previous action will be your last action self.updateAlarm(time.clock()) turn = 1 - turn print maxTile def isGameOver(self): return not self.grid.canMove() def getNewTileValue(self): if randint(0,99) < 100 * self.possibility: return self.possibleNewTileValue[0] else: return self.possibleNewTileValue[1]; def insertRandonTile(self): tileValue = self.getNewTileValue() cells = self.grid.getAvailableCells() cell = cells[randint(0, len(cells) - 1)] self.grid.setCellValue(cell, tileValue)
class GameManager: def __init__(self, size=4): self.grid = Grid(size) self.possibleNewTiles = [2, 4] self.probability = defaultProbability self.initTiles = defaultInitialTiles self.computerAI = None self.playerAI = None self.displayer = None self.over = False def setComputerAI(self, computerAI): self.computerAI = computerAI def setPlayerAI(self, playerAI): self.playerAI = playerAI def setDisplayer(self, displayer): self.displayer = displayer def updateAlarm(self, currTime): if currTime - self.prevTime > timeLimit + allowance: self.over = True else: while time.perf_counter() - self.prevTime < timeLimit + allowance: pass self.prevTime = time.perf_counter() def start(self): for i in range(self.initTiles): self.insertRandomTile() self.displayer.display(self.grid) # Player AI Goes First turn = PLAYER_TURN maxTile = 0 self.prevTime = time.perf_counter() timecount = 0 while not self.isGameOver() and not self.over: timecount += 1 print(timecount, "th TURN:") # Copy to Ensure AI Cannot Change the Real Grid to Cheat gridCopy = self.grid.clone() move = None if turn == PLAYER_TURN: print("Player's Turn:", end="") move = self.playerAI.getMove(gridCopy) print(actionDic[move]) # Validate Move if move != None and move >= 0 and move < 4: if self.grid.canMove([move]): self.grid.move(move) # Update maxTile maxTile = self.grid.getMaxTile() else: print("Invalid PlayerAI Move") self.over = True else: print("Invalid PlayerAI Move - 1") self.over = True print(self.evaluator(self.top5())) else: print("Computer's turn:") move = self.computerAI.getMove(gridCopy) # Validate Move if move and self.grid.canInsert(move): self.grid.setCellValue(move, self.getNewTileValue()) else: print("Invalid Computer AI Move") self.over = True if not self.over: self.displayer.display(self.grid) # Exceeding the Time Allotted for Any Turn Terminates the Game self.updateAlarm(time.perf_counter()) turn = 1 - turn print(maxTile) def isGameOver(self): return not self.grid.canMove() def getNewTileValue(self): random.seed(218) if random.randint(0, 99) < 100 * self.probability: return self.possibleNewTiles[0] else: return self.possibleNewTiles[1] def insertRandomTile(self): tileValue = self.getNewTileValue() cells = self.grid.getAvailableCells() random.seed(218) cell = cells[random.randint(0, len(cells) - 1)] self.grid.setCellValue(cell, tileValue) def sumOfScore(self): sum = 0 for i in range(4): for j in range(4): sum += self.grid.map[i][j] return sum #Modified part for evaluation: def top5(self): flatten_list = list(chain.from_iterable(self.grid.map)) flatten_list.sort(reverse=True) return flatten_list[0:5] def evaluator(self, res): score = 10 std = [2048, 2048, 1024, 1024, 1024] for i in range(5): if res[i] == 0: score -= 10 elif res[i] > std[i]: score += 2 * math.log2(std[i] / res[i]) else: score -= 0.5 * math.log2(std[i] / res[i]) return score
class Game: def __init__(self, size=4): self.grid = Grid(size) self.possibleNewTiles = [2] self.probability = defaultProbability self.initTiles = defaultInitialTiles self.agent = GreedyAgent() self.displayer = BeatifulDisplay() self.displayStep = defaultDisplayStep self._debugFlag = False self._failMess = None def setAgent(self, agent: Agent): self.agent = agent def setDisplay(self, displayer: Display, displayStep: int): self.displayer = displayer self.displayStep = displayStep def isLose(self): return not self.grid.canMove() def isWin(self): return self.grid.getMaxTile() == 2048 def getNewTileValue(self): return self.possibleNewTiles[randint(0, len(self.possibleNewTiles) - 1)] def insertRandonTile(self): tileValue = self.getNewTileValue() cells = self.grid.getAvailableCells() cell = cells[randint(0, len(cells) - 1)] if not cell: self._debugFlag = True self._failMess = "No available empty cell" raise ValueError(self._failMess) self.grid.setCellValue(cell, tileValue) def display(self): self.displayer.display(self.grid) def getScore(self): return self.grid.getMaxTile() def main(self): for i in range(self.initTiles): self.insertRandonTile() if self.displayStep > 0: self.display() step = 1 while not self.isWin() and not self.isLose() and not self._debugFlag: gridCopy = self.grid.clone() move = self.agent.getMove(gridCopy) #print(actionDic[move]) if move is not None and 0 <= move < 4: if self.grid.canMove([move]): self.grid.move(move) else: self._debugFlag = True self._failMess = "Invalid Agent Move: the grid would not change" break else: self._debugFlag = True self._failMess = "Invalid Agent Move: Value Error: " + str( move) break self.insertRandonTile() if self.displayStep > 0 and step % self.displayStep == 0: #sleep(0.1) print('step: ', step) self.display() #print(self.getScore()) step += 1 if self._debugFlag: raise ValueError(self._failMess) if self.displayStep > 0: self.display() print('Ends in step', step) if self.isWin(): print("Agent wins!!") if self.isLose(): print("Agent Loses!!") return self.isWin(), self.getScore()
class GameManager: """ Game Manager class Agrs: size: Puzzle grid side size ComputerAI: ComputerAI class object running the computer's moves PlayerAI: PlayerAI class object running the player's moves optimizing the implemented heuristics displayer: Displayer class object allowing the Game Manager to display the current state of the game currTime: time.clock object indicating the current time at each move Methods: setComputerAI(): Set ComputerAI object setPlayerAI(): Set PlayerAI object setDisplayer(): Set Displayer object updateAlarm(): Check time consumed in the decision-making process doesn't exceed time limit start(): Start running the game isGameOver(): Check if the game is over, not allowing the player to perform any further moves getNewTileValue(): Get the value of the computer's new tile to be inserted insertRandomTile(): Insert the computer's new tile in a random available cell """ def __init__(self, size=4): self.grid = Grid(size) self.possibleNewTiles = [2, 4] self.probability = defaultProbability self.initTiles = defaultInitialTiles self.computerAI = None self.playerAI = None self.displayer = None self.over = False def setComputerAI(self, computerAI): """ Set ComputerAI object """ self.computerAI = computerAI def setPlayerAI(self, playerAI): """ Set PlayerAI object """ self.playerAI = playerAI def setDisplayer(self, displayer): """ Set Displayer object """ self.displayer = displayer def updateAlarm(self, currTime): """ Check time consumed in the decision-making process doesn't exceed time limit Args: currTime: time.clock object indicating the current time at each move """ if currTime - self.prevTime > timeLimit + allowance: self.over = True else: while time.clock() - self.prevTime < timeLimit + allowance: pass self.prevTime = time.clock() def start(self): """ Start running the game """ for i in range(self.initTiles): self.insertRandomTile() self.displayer.display(self.grid) # Player AI Goes First turn = PLAYER_TURN maxTile = 0 self.prevTime = time.clock() while not self.isGameOver() and not self.over: # Copy to Ensure AI Cannot Change the Real Grid to Cheat gridCopy = self.grid.clone() move = None if turn == PLAYER_TURN: print("Player's Turn:", end="") move = self.playerAI.getMove(gridCopy) print(actionDic[move]) # Validate Move if move != None and move >= 0 and move < 4: if self.grid.canMove([move]): self.grid.move(move) # Update maxTile maxTile = self.grid.getMaxTile() else: print("Invalid PlayerAI Move") self.over = True else: print("Invalid PlayerAI Move - 1") self.over = True else: print("Computer's turn:") move = self.computerAI.getMove(gridCopy) # Validate Move if move and self.grid.canInsert(move): self.grid.setCellValue(move, self.getNewTileValue()) else: print("Invalid Computer AI Move") self.over = True if not self.over: self.displayer.display(self.grid) print(self.over) # Exceeding the Time Allotted for Any Turn Terminates the Game self.updateAlarm(time.clock()) turn = 1 - turn print(self.over) print(maxTile) def isGameOver(self): """ Check if the game is over, not allowing the player to perform any further moves Returns: Boolean whether the game is over or not """ return not self.grid.canMove() def getNewTileValue(self): """ Get the value of the computer's new tile to be inserted Returns: Value of the computer's new tile to be inserted """ if randint(0, 99) < 100 * self.probability: return self.possibleNewTiles[0] else: return self.possibleNewTiles[1] def insertRandomTile(self): """ Insert the computer's new tile in a random available cell """ tileValue = self.getNewTileValue() cells = self.grid.getAvailableCells() cell = cells[randint(0, len(cells) - 1)] self.grid.setCellValue(cell, tileValue)