def randomRandom(board, player, opponent, **info): ''' Purely random ''' tileList = np.where(player.used == False)[0] used = np.zeros(21, dtype=bool) cnt = 0 while cnt < tileList.size: t = np.random.choice(tileList) while used[t]: t = np.random.choice(tileList) direction = np.random.permutation(shape.tileMaxRotation[t]) for d in direction: f = 0 tile = Tiles(t, d, f) possiblePos = board.canDropPos(player, tile) if possiblePos[0].size != 0: i = np.random.choice(possiblePos[0].size) x, y = possiblePos[0][i], possiblePos[1][i] return [t, d, f, x, y] if shape.tileMaxFlip[t]: f = 1 tile = Tiles(t, d, f) possiblePos = board.canDropPos(player, tile) if possiblePos[0].size != 0: i = np.random.choice(possiblePos[0].size) x, y = possiblePos[0][i], possiblePos[1][i] return [t, d, f, x, y] used[t] = True cnt += 1 return [-1, 0, 0, 0, 0]
def randomGreedy(board, player, opponent, **info): ''' Randomly choose one of the biggest tile which can be dropped and drop it on a random legal position. ''' remain = [] nowSize = 0 for i in range(21): if not player.used[i]: if nowSize == shape.tileSizes[i]: remain[nowSize - 1].append(i) else: remain.append([]) nowSize = nowSize + 1 remain[nowSize - 1].append(i) for size in range(5, 0, -1): if size > len(remain): continue random.shuffle(remain[size - 1]) for i in range(len(remain[size - 1])): t = remain[size - 1][i] direction = [i for i in range(shape.tileMaxRotation[t])] random.shuffle(direction) for k in direction: f = 0 tile = Tiles(t, k, f) xlist, ylist = board.canDropPos(player, tile) if xlist.size != 0: j = np.random.choice(xlist.size) return [ t, # type of tile k, # rotation f, # flip xlist[j], # x ylist[j] # y ] if shape.tileMaxFlip[t]: f = 1 tile = Tiles(t, k, f) xlist, ylist = board.canDropPos(player, tile) if xlist.size == 0: continue j = np.random.choice(xlist.size) return [ t, # type of tile k, # rotation f, # flip xlist[j], # x ylist[j] # y ] return [-1, 0, 0, 0, 0]
def action(self, board, opponent, **info): if self.decisionMaker is None: raise ValueError("The player is human") if not isinstance(board, Board): raise TypeError if self.type != board.type or self.order >= board.playerNum: raise ValueError if 'setEvalWeight' in info: self.w1, self.w2 = info['setEvalWeight'] ef = 0 if 'setEvalFunc' in info: ef = info['setEvalFunc'] tileType, rot, flp, x, y = self.decisionMaker(board, self, opponent, \ setEvalWeight = [self.w1, self.w2], setEvalFunc = ef) if tileType != -1: tile = Tiles(tileType, rot, flp) board.dropTile(self, tile, x, y, False) self.used[tileType] = True self.score = self.score + tileSizes[tileType] return { "action": True, "tileType": tileType, "rotation": rot, "flip": flp, "x": x, "y": y } else: return {"action": False}
def action(self, board, opponent): if self.decisionMaker is None: raise ValueError("The player is human") if not isinstance(board, Board): raise TypeError if self.type != board.type or self.order >= board.playerNum: raise ValueError tileType, rot, flp, x, y = self.decisionMaker(board, self, opponent, setEvalWeight = [self.w1, self.w2]) if tileType != -1: tile = Tiles(tileType, rot, flp) board.dropTile(self, tile, x, y) self.used[tileType] = True for coo in cornerSet[tileType][rot + flp * 4]: if board.isInBound(x + coo[0], y + coo[1]): self.corners.update([(x + coo[0], y + coo[1])]) self.score = self.score + self.tiles[tileType].size return { "action" : True, "tileType" : tileType, "rotation" : rot, "flip" : flp, "x" : x, "y" : y } else: return { "action" : False }
def mctsEval(board, player, opponent, **info): score = 0 rev = False tot = 6 stp = 4 if 'setTot' in info: tot = info['setTot'] if 'setReverse' in info: rev = info['setReverse'] if 'setStep' in info: stp = info['setStep'] tmpDecMaker = [player.decisionMaker, opponent.decisionMaker] player.decisionMaker = opponent.decisionMaker = randomRandom tmpPlayer = player tmpOpponent = opponent if rev: tmpPlayer = opponent tmpOpponent = player initScore = greedyEval(board, tmpPlayer, tmpOpponent) for game in range(tot): tmpHistory = [] flag = False for step in range(stp): flag = False result = tmpPlayer.action(board, tmpOpponent, setEvalFunc=0) if result['action']: flag = True result['id'] = 0 tmpHistory.append(result) result = tmpOpponent.action(board, tmpPlayer, setEvalFunc=0) if result['action']: flag = True result['id'] = 1 tmpHistory.append(result) if not flag: break if flag: if greedyEval(board, tmpPlayer, tmpOpponent) > initScore: score += 1 else: if tmpPlayer.score > tmpOpponent.score: score += 1 for h in tmpHistory: if h['id'] == 0: tmpPlayer.used[h['tileType']] = False tmpPlayer.score -= shape.tileSizes[h['tileType']] else: tmpOpponent.used[h['tileType']] = False tmpOpponent.score -= shape.tileSizes[h['tileType']] board.retraceDrop(Tiles(h['tileType'], h['rotation'], h['flip']), h['x'], h['y']) player.decisionMaker, opponent.decisionMaker = tmpDecMaker return score / tot if not rev else 1 - score / tot
def greedy(board, player, opponent, evalFunc=0, **info): ''' Enumerate all possible drops, and get a score using EvalFunc[evalFunc] ''' if 'setEvalFunc' in info: evalFunc = info['setEvalFunc'] global evalWeight if 'setEvalWeight' in info: evalWeight = info['setEvalWeight'] maxScore = -32768 maxDecision = [] remain = np.where(player.used == False)[0] if remain.size == 0: return [-1, 0, 0, 0, 0] remain = remain[::-1] for i in remain: for p in range(shape.tileMaxRotation[i]): f = [0] if shape.tileMaxFlip[i]: f.append(1) for q in f: tile = Tiles(i, p, q) xlist, ylist = board.canDropPos(player, tile) if xlist.size == 0: continue for k in range(xlist.size): x = xlist[k] y = ylist[k] result = board.dropTile(player, tile, x, y, False) if result: player.score += tile.size player.used[tile.type] = True score = EvalFunc[evalFunc](board, player, opponent, setReverse=True) if score > maxScore: maxScore = score maxDecision = [ i, # type of tile p, # rotation q, # flip x, # x y # y ] board.retraceDrop(tile, x, y) player.used[tile.type] = False player.score -= tile.size if maxScore > -32768: return maxDecision else: return [-1, 0, 0, 0, 0]
def test_corner(self): fout = open("testCorner.out", "w+") tiles = [] for i in range(21): tiles.append(Tiles(i)) for i in range(21): fout.write("type %d\n" % i) for r in range(4): self.__printTileAll(tiles[i], fout) tiles[i].rightRotate() tiles[i].horFlip() for r in range(4): self.__printTileAll(tiles[i], fout) tiles[i].rightRotate() fout.write("\n")
def _alphaBeta(depth, board, player, opponent, evalFunc, alpha, beta, desPlayer): ''' Internal recursive alphabeta pruning ''' if depth == minimaxDepth: return EvalFunc[evalFunc](board, player, opponent) bestMove = [-1, 0, 0, 0, 0] remain = np.where(player.used == False)[0] remain = remain[::-1] #reverse the array to search in a specific order for i in remain: for p in range(shape.tileMaxRotation[i]): f = [0] if shape.tileMaxFlip[i]: f.append(1) for q in f: tile = Tiles(i, p, q) xlist, ylist = board.canDropPos(player, tile) if xlist.size == 0: continue for k in range(xlist.size): x = xlist[k] y = ylist[k] result = board.dropTile(player, tile, x, y, False) if result: player.score += tile.size score = -_alphaBeta(depth + 1, board, opponent, player, evalFunc, -beta, -alpha, desPlayer) board.retraceDrop(tile, x, y) player.score -= tile.size if score >= alpha: alpha = score if depth == 0: bestMove = [i, p, q, x, y] if alpha >= beta: return [alpha, bestMove] else: if alpha >= beta: return alpha return alpha if depth != 0 else [alpha, bestMove]
def test_rotate(self): fout = open("testRotate.out", "w+") tiles = [] for i in range(21): tiles.append(Tiles(i)) for i in range(21): fout.write("type %d\n" % i) for r in range(4): tiles[i].print(fout) fout.write("\n") tiles[i].rightRotate() tiles[i].horFlip() for r in range(4): tiles[i].print(fout) fout.write("\n") tiles[i].rightRotate() fout.write("\n") fout.close()
def __init__(self, type = -1, order = 0, level = 0, **info): if type == -1: pass else: self.type = type self.order = order if type is 0: self.tiles = [Tiles(i) for i in range(21)] self.used = [False for i in range(21)] self.score = 0 if order == 0: self.corners = set([(4, 4)]) else: self.corners = set([(9, 9)]) self.tmpSet = [] if level == -1: self.decisionMaker = None else: self.decisionMaker = DecisionFunc[level] self.w1, self.w2 = [20, 10] if 'setWeight' in info: self.w1, self.w2 = info['setWeight']
else: matrix = [[0 for i in range(14)] for j in range(14)] player = Player(0, 0, lv) opponent = Player(0, 1, 0) if playerOrder == 0: board.parseFromMatrix(matrix, [player, opponent]) else: board.parseFromMatrix(matrix, [opponent, player]) result = player.action(board, opponent, setEvalWeight=evalWeight, setEvalFunc=evalFunc) if result['action']: output['status'] = "Success" output['is_pass'] = False output['action'] = [] tile = Tiles(result['tileType'], result['rotation'], result['flip']) x = result['x'] y = result['y'] for (i, j) in tile.shape: output['action'].append({"row": int(x + i), "col": int(y + j)}) print(json.dumps(output)) else: output['status'] = "Success" output['is_pass'] = True output['action'] = [] print(json.dumps(output))
# test for Board.canDropPos from board import Tiles, Board from player import Player import numpy as np board = Board() player = Player(0, 0, -1) board.board[3][3] = 1 board.board[4][4] = 1 tile = Tiles(17, 0, 0) ret = board.canDropPos(player, tile) print(ret) print(board.getCorners(player)[0].size)
def analBoard(board, player, opponent, **info): ''' return the best 5 drops and their winning rate ''' maxDecision = [] remain = np.where(player.used == False)[0] for i in remain: for p in range(shape.tileMaxRotation[i]): f = [0] if shape.tileMaxFlip[i]: f.append(1) for q in f: tile = Tiles(i, p, q) xlist, ylist = board.canDropPos(player, tile) if xlist.size == 0: continue for k in range(xlist.size): x = xlist[k] y = ylist[k] board.dropTile(player, tile, x, y, False) player.score += tile.size player.used[tile.type] = True score = greedyEval(board, player, opponent, setEvalWeight=[20, 10]) if len(maxDecision) < 5: maxDecision.append({ 'score': score, 'tileType': i, # type of tile 'rot': p, # rotation 'flip': q, # flip 'x': x, # x 'y': y # y }) elif score > maxDecision[-1]['score']: m = 4 while m > 0: if maxDecision[m]['score'] > score: break maxDecision[m] = maxDecision[m - 1] m -= 1 maxDecision[m] = { 'score': score, 'tileType': i, # type of tile 'rot': p, # rotation 'flip': q, # flip 'x': x, # x 'y': y # y } board.retraceDrop(tile, x, y) player.used[tile.type] = False player.score -= tile.size for i, dec in enumerate(maxDecision): tile = Tiles(dec['tileType'], dec['rot'], dec['flip']) board.dropTile(player, tile, dec['x'], dec['y'], False) player.used[dec['tileType']] = True winningRate = mctsEval(board, player, opponent, setTot=61, setReverse=True) maxDecision[i]['winningRate'] = int(winningRate * 1000) board.retraceDrop(tile, dec['x'], dec['y']) player.used[dec['tileType']] = False return maxDecision
def mcts(board, player, opponent, evalFunc=0, **info): ''' Enumerate all possible drops and select the best 5 of them, then use mcstEval to reevaluate them ''' if 'setEvalFunc' in info: evalFunc = info['setEvalFunc'] global evalWeight if 'setEvalWeight' in info: evalWeight = info['setEvalWeight'] totGame = 80 if 'setTotalGame' in info: totGame = info['setTotalGame'] maxDecision = [] remain = np.where(player.used == False)[0] for i in remain: for p in range(shape.tileMaxRotation[i]): f = [0] if shape.tileMaxFlip[i]: f.append(1) for q in f: tile = Tiles(i, p, q) xlist, ylist = board.canDropPos(player, tile) if xlist.size == 0: continue for k in range(xlist.size): x = xlist[k] y = ylist[k] board.dropTile(player, tile, x, y, False) player.score += tile.size player.used[tile.type] = True score = EvalFunc[evalFunc](board, player, opponent, setReverse=True) if len(maxDecision) < 5: maxDecision.append({ 'score': score, 'tileType': i, # type of tile 'rot': p, # rotation 'flip': q, # flip 'x': x, # x 'y': y # y }) elif score > maxDecision[-1]['score']: m = 4 while m > 0: if maxDecision[m]['score'] > score: break maxDecision[m] = maxDecision[m - 1] m -= 1 maxDecision[m] = { 'score': score, 'tileType': i, # type of tile 'rot': p, # rotation 'flip': q, # flip 'x': x, # x 'y': y # y } board.retraceDrop(tile, x, y) player.used[tile.type] = False player.score -= tile.size if maxDecision != []: maxscore = -1 maxd = -1 for i, dec in enumerate(maxDecision): tile = Tiles(dec['tileType'], dec['rot'], dec['flip']) board.dropTile(player, tile, dec['x'], dec['y'], False) player.used[dec['tileType']] = True score = mctsEval(board, player, opponent, setTot=totGame, setReverse=True) if score > maxscore: maxd = i board.retraceDrop(tile, dec['x'], dec['y']) player.used[dec['tileType']] = False return [ maxDecision[maxd]['tileType'], maxDecision[maxd]['rot'], maxDecision[maxd]['flip'], maxDecision[maxd]['x'], maxDecision[maxd]['y'] ] else: return [-1, 0, 0, 0, 0]
p_id = int(args.player_id) player = Player(0, p_id, 0) opponent = Player(0, p_id ^ 1, 0) matrix = json.loads(args.state) if p_id == 0: board.parseFromMatrix(matrix, [player, opponent]) else: board.parseFromMatrix(matrix, [opponent, player]) result = analBoard(board, player, opponent) def wr(pack): return pack['winningRate'] result.sort(key=wr, reverse=True) output = [] for r in result: tile = Tiles(r['tileType'], r['rot'], r['flip']) x = r['x'] y = r['y'] action = [] for i, j in tile.shape: action.append({"row": int(x + i), "col": int(y + j)}) output.append({ "action": action, "winning_rate": r['winningRate'] / 10 }) print(json.dumps(output))