def expectimax_calc(move, old_board, depth, isChance): board_to_check = util.execute_move(move, old_board) if depth == MAX_DEPTH: return heuristic_value(move, board_to_check, old_board) if isChance == 1: avg = 0 ecc = util.cell_of_type_count(0, board_to_check) if ecc == 0: possibility_multiplier = 1 else: possibility_multiplier = 1 / ecc for x in range(4): for y in range(4): if board_to_check[x][y] == 0: board_to_check[x][y] = 2 avg += possibility_multiplier * CHANCE_2 * expectimax_calc(move, old_board, depth + 1, 0) board_to_check[x][y] = 4 avg += possibility_multiplier * CHANCE_4 * expectimax_calc(move, old_board, depth + 1, 0) board_to_check[x][y] = 0 return avg else: results = [] for m in move_args: check_board = util.execute_move(m, board_to_check) if util.board_equals(check_board, board_to_check): results.append(0) else: results.append(expectimax_calc(m, board_to_check, depth + 1, 1)) return max(results)
def heuristics_combineable_cells_count(new_board, old_board): ''' Clunky evaluation: what was the last move? UP/DOWN or LEFT/RIGHT? TODO: Refactoring ''' if util.board_equals(util.execute_move(UP, old_board), new_board): move = UP elif util.board_equals(util.execute_move(DOWN, old_board), new_board): move = DOWN elif util.board_equals(util.execute_move(LEFT, old_board), new_board): move = LEFT else: move = RIGHT combineable_tiles_count = 0 '''Check Directions''' if (move == UP) or (move == DOWN): '''0,1 = UP, DOWN''' for y in range(4): if (new_board[0][y] == new_board[1][y]) and (new_board[0][y] != 0): if (new_board[1][y] == new_board[2][y]) and (new_board[2][y] == new_board[3][y]): # xxxx combineable_tiles_count += 2 else: # xxab. xxxa combineable_tiles_count += 1 elif (new_board[1][y] == new_board[2][y]) and (new_board[1][y] != 0): # axxx, axxb combineable_tiles_count += 1 elif (new_board[2][y] == new_board[3][y]) and (new_board[2][y] != 0): # abxx combineable_tiles_count += 1 else: '''2,3 = LEFT, RIGHT''' for x in range(4): if (new_board[x][0] == new_board[x][1]) and (new_board[x][0] != 0): if (new_board[x][1] == new_board[x][2]) and (new_board[x][2] == new_board[x][3]): # xxxx combineable_tiles_count += 2 else: # xxab. xxxa combineable_tiles_count += 1 elif (new_board[x][1] == new_board[x][2]) and (new_board[x][1] != 0): # axxx, axxb combineable_tiles_count += 1 elif (new_board[x][2] == new_board[x][3]) and (new_board[x][2] != 0): # abxx combineable_tiles_count += 1 # return combineable_tiles_count return util.round_nearest(combineable_tiles_count/7, 0.01)
def a_very_lauenchr_expectimax_calc(depth, new_board, isChance, old_board): if depth == MAX_DEPTH: return heuristic_value(new_board, old_board) if isChance == 1: avg = 0 chance_2 = 0.9 chance_4 = 0.1 ecc = util.cell_of_type_count(0, new_board) if ecc == 0: chance_cel = 0 else: chance_sel = 1 / heuristics_empty_cells_count(new_board) for x in range(4): for y in range(4): if new_board[x][y] == 0: new_board[x][y] = 2 avg += chance_sel * chance_2 * a_very_lauenchr_expectimax_calc(depth + 1, new_board, 0, old_board) new_board[x][y] = 4 avg += chance_sel * chance_4 * a_very_lauenchr_expectimax_calc(depth + 1, new_board, 0, old_board) new_board[x][y] = 0 return avg else: results = [] for m in move_args: results.append(a_very_lauenchr_expectimax_calc(depth + 1, util.execute_move(m, new_board), 1, new_board)) return max(results)
def build_heuristic_array(move_possible_array, board): heuristic_array = util.build_list(math.inf, 4) for i in range(4): if move_possible_array[i] > 0: board_to_check = util.execute_move(i, board) act = heuristics_combineable_cells_count(i, board) ndh = heuristics_neighbour_difference(board_to_check) ecc = heuristics_empty_cells_count(board_to_check) htic = heuristics_highest_tile_in_corner(board, board_to_check) # heuristic_array[i] = coeff[0] * act/7 + coeff[1] * (ndh/41) + coeff[2] * (ecc/15) + coeff[3] * htic + coeff[4] * (heuristics_monotonous_row(board_to_check) / heuristics_monotonous_row(board)) heuristic_array[i] = coeff[0] * act + coeff[1] * ndh + coeff[ 2] * ecc + coeff[3] * htic + coeff[4] * ( heuristics_monotonous_row(board_to_check) / heuristics_monotonous_row(board)) # add heuristics together # heuristic_array[i] = (-2*act) + (4*ndh) - ecc - 50 * (heuristics_monotonous_row(board_to_check) / heuristics_monotonous_row(board)) # (1) # heuristic_array[i] = - (act/7) + 3*(ndh/41) - (ecc/15) + htic - heuristics_monotonous_row(board_to_check) / heuristics_monotonous_row(board) # (2) weighted # heuristic_array[i] = - 2*(act/7) + (ndh/41) - 4*(ecc/15) + htic - heuristics_monotonous_row(board_to_check) / heuristics_monotonous_row(board) # (3) weighted2 # heuristic_array[i] = - (act/7) + 2*(ndh/41) - (ecc/15) + htic - 2 * heuristics_monotonous_row(board_to_check) / heuristics_monotonous_row(board) # (4) weighted3 # heuristic_array[i] = 2*(ndh/41) + htic - 2 * heuristics_monotonous_row(board_to_check) / heuristics_monotonous_row(board) # (5) weighted4 # heuristic_array[i] = (-2*act) + (4*ndh) - ecc - 100 * (heuristics_monotonous_row(board_to_check) / heuristics_monotonous_row(board)) # (6) weighted5 # TODO! # ============================== # - each heuristic on its own with the monotonous row # ============================== return heuristic_array
def score_toplevel_move(move, board): """Entry Point to score the first move.""" board_to_check = util.execute_move(move, board) if util.board_equals(board, board_to_check): return 0 expectimax_score = expectimax_calc(board_to_check, board, 0, 0) return expectimax_score
def score_toplevel_move(move, board): """Entry Point to score the first move.""" newboard = util.execute_move(move, board) if util.board_equals(board,newboard): return 0 expectimax_score = a_very_lauenchr_expectimax_calc(0, newboard, 0, board) htic = heuristics_highest_tile_in_corner(newboard) return expectimax_score + coeff[3] * htic
def score_toplevel_move(move, board): """Entry Point to score the first move.""" board_to_check = util.execute_move(move, board) if util.board_equals(board, board_to_check): return -1 htic = heuristics_highest_tile_in_corner(board_to_check) expectimax_score = expectimax_calc(0, board, 0, 0) + htic return expectimax_score
def build_heuristic_array(move_possible_array, board): heuristic_array = util.build_list(math.inf, 4) for i in range(4): if move_possible_array[i] > 0: board_to_check = util.execute_move(i, board) act = heuristics_combineable_cells_count(i, board) ndh = heuristics_neighbour_difference(board_to_check) ecc = heuristics_empty_cells_count(board_to_check) htic = heuristics_highest_tile_in_corner(board, board_to_check) # add heuristics together heuristic_array[i] = (-2*act) + (4*ndh) - ecc + htic # => original (1) return heuristic_array
def heuristics_combineable_cells_count(move, board): new_board = util.execute_move(move, board) combineable_tiles_count = 0 '''Check Directions''' if (move == UP) or (move == DOWN): '''0,1 = UP, DOWN''' for y in range(4): if (new_board[0][y] == new_board[1][y]) and (new_board[0][y] != 0): if (new_board[1][y] == new_board[2][y]) and (new_board[2][y] == new_board[3][y]): # xxxx combineable_tiles_count += 2 else: # xxab. xxxa combineable_tiles_count += 1 elif (new_board[1][y] == new_board[2][y]) and (new_board[1][y] != 0): # axxx, axxb combineable_tiles_count += 1 elif (new_board[2][y] == new_board[3][y]) and (new_board[2][y] != 0): # abxx combineable_tiles_count += 1 else: '''2,3 = LEFT, RIGHT''' for x in range(4): if (new_board[x][0] == new_board[x][1]) and (new_board[x][0] != 0): if (new_board[x][1] == new_board[x][2]) and (new_board[x][2] == new_board[x][3]): # xxxx combineable_tiles_count += 2 else: # xxab. xxxa combineable_tiles_count += 1 elif (new_board[x][1] == new_board[x][2]) and (new_board[x][1] != 0): # axxx, axxb combineable_tiles_count += 1 elif (new_board[x][2] == new_board[x][3]) and (new_board[x][2] != 0): # abxx combineable_tiles_count += 1 # return combineable_tiles_count return util.round_nearest(combineable_tiles_count / 7, 0.01)
def find_best_move(board): global move_count global coeff global score '''Which moves are possible? 1 for possible, 0 for not possible''' possible_moves_array = util.build_possible_moves_list(board) if console_logging: print(f'possible_moves_array: {possible_moves_array}') '''What are the scores for each move?''' heuristic_array = build_heuristic_array(possible_moves_array, board) '''Choose the best move out of all possible''' best_move = util.index_min(heuristic_array) handle_logging(board, util.execute_move(best_move, board), best_move, heuristic_array) move_count += 1 return best_move
def find_best_move(board): global move_count """find the best move for the next turn. It will split the workload in 4 process for each move.""" bestmove = 0 result = [score_toplevel_move(i, board) for i in range(len(move_args))] bestmove = result.index(max(result)) if console_logging: print(np.around(result,decimals=2)) time.sleep(5) # time.sleep(move_count / 1000) handle_logging(util.execute_move(bestmove, board), bestmove) move_count += 1 return bestmove
def find_best_move(board): '''Which moves are possible? 1 for possible, 0 for not possible''' possible_moves_array = util.build_possible_moves_list(board) if console_logging: print(f'possible_moves_array: {possible_moves_array}') '''What are the scores for each move?''' heuristic_array = build_heuristic_array(possible_moves_array, board) '''Choose the best move out of all possible''' best_move = util.index_min(heuristic_array) log.log(file_writer, [ ai_id, heuristics_empty_cells_count(board), heuristics_neighbour_difference(board), util.highest_tile(board), heuristics_highest_tile_in_corner( board, util.execute_move(best_move, board)), best_move, score, heuristics_combineable_cells_count(best_move, board), possible_moves_array, heuristic_array ]) # logging return best_move
def find_best_move(board): global move_count """ find the best move for the next turn. It will split the workload in 4 process for each move. """ bestmove = -1 result = [score_toplevel_move(i, board) for i in range(len(move_args))] maxResult = max(result) if maxResult != 0: bestmove = result.index(maxResult) print(maxResult) #for m in move_args: # print(m) # print(result[m]) handle_logging(util.execute_move(bestmove, board), bestmove) move_count += 1 return bestmove
def expectimax_calc(board_to_check, old_board, depth, isChance): # TODO: kann man bei der Suche abbrechen, :higest_tile aus der Ecke getrieben wird? # => welchen Einfluss hat dies auf Anfangsszenarien? if depth == MAX_DEPTH: return heuristic_value(board_to_check, old_board) if isChance == 1: avg = 0 empty_cells_count = util.cell_of_type_count(0, board_to_check) if empty_cells_count == 0: moves_to_check_count = 0 return 0 else: possibility_multiplier = 1 / empty_cells_count for x in range(4): for y in range(4): if board_to_check[x][y] == 0: board_to_check[x][y] = 2 avg += possibility_multiplier * CHANCE_2 * expectimax_calc( board_to_check, old_board, depth + 1, 0) board_to_check[x][y] = 4 avg += possibility_multiplier * CHANCE_4 * expectimax_calc( board_to_check, old_board, depth + 1, 0) board_to_check[x][y] = 0 return avg else: results = [] for m in move_args: results.append( expectimax_calc(util.execute_move(m, board_to_check), board_to_check, depth + 1, 1)) return max(results)