<reponame>redfire/tzaar-python-ai<gh_stars>1-10
from shared.board import *
import random
from pprint import pprint

def playMove(board, turnInfo: TurnInformation):
    turns = 2
    if turnInfo.turns == 1:
        turns = 1

    moves_info = alphabeta(board, turns, -1, 101, turnInfo.player, turnInfo.turn_number, [], getItems(board))
    print('original win chance: ' + str(moves_info[0]))
    options_and_values = moves_info[2]

    from operator import itemgetter, attrgetter, methodcaller
    sorted_options = sorted(options_and_values, key=lambda x: x[0], reverse=True)
    v = 5
    best_moves = None
    index = 0
    last_index = None
    for option in sorted_options:
        move = option[1][0]
        test_board = getBoardAfterMove(board, move[0][0], move[0][1], move[1][0], move[1][1])
        if turns == 2:
            move = option[1][1]
            test_board = getBoardAfterMove(test_board, move[0][0], move[0][1], move[1][0], move[1][1])
        test_turn = TurnInformation(turnInfo.turn_number + turns)
        moves_info = alphabeta(test_board, 2, -1, 101, test_turn.player, test_turn.turn_number, [], getItems(test_board))
        value = moves_info[0]
        if value < v:
            best_moves = option[1]
            v = value
            last_index = index
        index += 1

    print('index: ' + str(last_index))
    print('their win chance: ' + str(v))
    print('our win chance: ' + str(sorted_options[last_index][0]))

    # This is the case where there are no more moves left to make.
    if moves_info[0] == 0:
        output = {}
        output['result'] = BoardResult.has_lost
        output['board'] = board
        output['moves'] = []
        return output

    moves = []
    if turnInfo.turns >= 1:
        chosen_option = best_moves[0]
        moves.append(chosen_option)
        board = getBoardAfterMove(board, chosen_option[0][0], chosen_option[0][1], chosen_option[1][0], chosen_option[1][1])

    if turnInfo.turns >= 2:
        chosen_option = best_moves[1]
        moves.append(chosen_option)
        board = getBoardAfterMove(board, chosen_option[0][0], chosen_option[0][1], chosen_option[1][0], chosen_option[1][1])

    output = {}
    output['result'] = getBoardresult(board, turnInfo.player)
    output['board'] = board
    output['moves'] = moves
    return output

def getPossibleMovesForPlayer(board, player: BoardItemType, allow_stacking):
    positions = getItemsOfType(board, player)
    all_options = []
    for pos_info in positions:
        options = getPossibleMoves(board, pos_info[0], pos_info[1], allow_stacking=allow_stacking)
        for option in options:
            all_options.append([pos_info, option])
    return all_options



import numpy as np
def alphabeta(board, depth, a, b, player, turn_number, returned_options, items):
    if depth == 0:
        turn_info = TurnInformation(turn_number-1)
        return [rateBoardForPlayer(board, turn_info.player, turn_info.opponent, items), returned_options]

    turn_info = TurnInformation(turn_number)
    options = getPossibleMovesForPlayer(board, turn_info.player, allow_stacking=turn_info.allow_stacking)
    if len(options) == 0:
        return [0, []]

    # we are maximizing our return.
    selected_move = None
    previous_moves = None
    total_move_scores = []
    if player == turn_info.player:
        v = -1
        for option in options:
            test_items = items[:]
            test_board = getBoardAfterMove(board, option[0][0], option[0][1], option[1][0], option[1][1], items=test_items)
            result = alphabeta(test_board, depth-1, a, b, player, turn_number+1, returned_options, test_items)
            total_move_scores.append([result[0], combineMoves(option, result[1])])
            if result[0] > v:
                v = result[0]
                selected_move = option
                previous_moves = result[1]
            a = max(a, v)
            if b <= a:
                break
    else:
        v = 101
        for option in options:
            test_items = items[:]
            test_board = getBoardAfterMove(board, option[0][0], option[0][1], option[1][0], option[1][1], items=test_items)
            result = alphabeta(test_board, depth-1, a, b, player, turn_number+1, returned_options, test_items)
            if result[0] < v:
                v = result[0]
                selected_move = option
                previous_moves = result[1]
            b = min(b, v)
            if b <= a:
                break

    returned_options = []
    returned_options.append(selected_move)
    for moves in previous_moves:
        returned_options.append(moves)
    return [v, returned_options, total_move_scores]

def combineMoves(new_move, previous_moves):
    combined_moves = []
    combined_moves.append(new_move)
    for moves in previous_moves:
        combined_moves.append(moves)
    return combined_moves

try:
    import pickle
    clf_f = open("classifiers/sample2_2.pickle", "rb")
    clf = pickle.load(clf_f)
except OSError as e:
    print("No preloaded classifier available. Please build a new one.")
    quit()

#return between 0 and 1. 1 is very good and 0 is very bad.
cache = {}
def rateBoardForPlayer(board, player: BoardItemType, opponent: BoardItemType, items):
    stats = getBoardStats(items)
    stats_player = stats[player]
    stats_opponent = stats[opponent]
    if stats_opponent.getHasLost():
        return 1
    elif stats_player.getHasLost():
        return 0

    features = []
    features.append(stats_player.type1_count)
    features.append(stats_player.type1_max_weight)
    features.append(stats_player.type2_count)
    features.append(stats_player.type2_max_weight)
    features.append(stats_player.type3_count)
    features.append(stats_player.type3_max_weight)
    features.append(stats_opponent.type1_count)
    features.append(stats_opponent.type1_max_weight)
    features.append(stats_opponent.type2_count)
    features.append(stats_opponent.type2_max_weight)
    features.append(stats_opponent.type3_count)
    features.append(stats_opponent.type3_max_weight)

    feature_str = ''.join('{:01x}'.format(x) for x in features)
    if feature_str in cache:
        return cache[feature_str]

    value = clf.predict([features])[0]
    cache[feature_str] = value

    return value
from shared.board import *
import random
from pprint import pprint

def playMove(board, turnInfo: TurnInformation):
    turns = 2
    if turnInfo.turns == 1:
        turns = 1

    moves_info = alphabeta(board, turns, -1, 101, turnInfo.player, turnInfo.turn_number, [], getItems(board))
    print('original win chance: ' + str(moves_info[0]))
    options_and_values = moves_info[2]

    from operator import itemgetter, attrgetter, methodcaller
    sorted_options = sorted(options_and_values, key=lambda x: x[0], reverse=True)
    v = 5
    best_moves = None
    index = 0
    last_index = None
    for option in sorted_options:
        move = option[1][0]
        test_board = getBoardAfterMove(board, move[0][0], move[0][1], move[1][0], move[1][1])
        if turns == 2:
            move = option[1][1]
            test_board = getBoardAfterMove(test_board, move[0][0], move[0][1], move[1][0], move[1][1])
        test_turn = TurnInformation(turnInfo.turn_number + turns)
        moves_info = alphabeta(test_board, 2, -1, 101, test_turn.player, test_turn.turn_number, [], getItems(test_board))
        value = moves_info[0]
        if value < v:
            best_moves = option[1]
            v = value
            last_index = index
        index += 1

    print('index: ' + str(last_index))
    print('their win chance: ' + str(v))
    print('our win chance: ' + str(sorted_options[last_index][0]))

    # This is the case where there are no more moves left to make.
    if moves_info[0] == 0:
        output = {}
        output['result'] = BoardResult.has_lost
        output['board'] = board
        output['moves'] = []
        return output

    moves = []
    if turnInfo.turns >= 1:
        chosen_option = best_moves[0]
        moves.append(chosen_option)
        board = getBoardAfterMove(board, chosen_option[0][0], chosen_option[0][1], chosen_option[1][0], chosen_option[1][1])

    if turnInfo.turns >= 2:
        chosen_option = best_moves[1]
        moves.append(chosen_option)
        board = getBoardAfterMove(board, chosen_option[0][0], chosen_option[0][1], chosen_option[1][0], chosen_option[1][1])

    output = {}
    output['result'] = getBoardresult(board, turnInfo.player)
    output['board'] = board
    output['moves'] = moves
    return output

def getPossibleMovesForPlayer(board, player: BoardItemType, allow_stacking):
    positions = getItemsOfType(board, player)
    all_options = []
    for pos_info in positions:
        options = getPossibleMoves(board, pos_info[0], pos_info[1], allow_stacking=allow_stacking)
        for option in options:
            all_options.append([pos_info, option])
    return all_options



import numpy as np
def alphabeta(board, depth, a, b, player, turn_number, returned_options, items):
    if depth == 0:
        turn_info = TurnInformation(turn_number-1)
        return [rateBoardForPlayer(board, turn_info.player, turn_info.opponent, items), returned_options]

    turn_info = TurnInformation(turn_number)
    options = getPossibleMovesForPlayer(board, turn_info.player, allow_stacking=turn_info.allow_stacking)
    if len(options) == 0:
        return [0, []]

    # we are maximizing our return.
    selected_move = None
    previous_moves = None
    total_move_scores = []
    if player == turn_info.player:
        v = -1
        for option in options:
            test_items = items[:]
            test_board = getBoardAfterMove(board, option[0][0], option[0][1], option[1][0], option[1][1], items=test_items)
            result = alphabeta(test_board, depth-1, a, b, player, turn_number+1, returned_options, test_items)
            total_move_scores.append([result[0], combineMoves(option, result[1])])
            if result[0] > v:
                v = result[0]
                selected_move = option
                previous_moves = result[1]
            a = max(a, v)
            if b <= a:
                break
    else:
        v = 101
        for option in options:
            test_items = items[:]
            test_board = getBoardAfterMove(board, option[0][0], option[0][1], option[1][0], option[1][1], items=test_items)
            result = alphabeta(test_board, depth-1, a, b, player, turn_number+1, returned_options, test_items)
            if result[0] < v:
                v = result[0]
                selected_move = option
                previous_moves = result[1]
            b = min(b, v)
            if b <= a:
                break

    returned_options = []
    returned_options.append(selected_move)
    for moves in previous_moves:
        returned_options.append(moves)
    return [v, returned_options, total_move_scores]

def combineMoves(new_move, previous_moves):
    combined_moves = []
    combined_moves.append(new_move)
    for moves in previous_moves:
        combined_moves.append(moves)
    return combined_moves

try:
    import pickle
    clf_f = open("classifiers/sample2_2.pickle", "rb")
    clf = pickle.load(clf_f)
except OSError as e:
    print("No preloaded classifier available. Please build a new one.")
    quit()

#return between 0 and 1. 1 is very good and 0 is very bad.
cache = {}
def rateBoardForPlayer(board, player: BoardItemType, opponent: BoardItemType, items):
    stats = getBoardStats(items)
    stats_player = stats[player]
    stats_opponent = stats[opponent]
    if stats_opponent.getHasLost():
        return 1
    elif stats_player.getHasLost():
        return 0

    features = []
    features.append(stats_player.type1_count)
    features.append(stats_player.type1_max_weight)
    features.append(stats_player.type2_count)
    features.append(stats_player.type2_max_weight)
    features.append(stats_player.type3_count)
    features.append(stats_player.type3_max_weight)
    features.append(stats_opponent.type1_count)
    features.append(stats_opponent.type1_max_weight)
    features.append(stats_opponent.type2_count)
    features.append(stats_opponent.type2_max_weight)
    features.append(stats_opponent.type3_count)
    features.append(stats_opponent.type3_max_weight)

    feature_str = ''.join('{:01x}'.format(x) for x in features)
    if feature_str in cache:
        return cache[feature_str]

    value = clf.predict([features])[0]
    cache[feature_str] = value

    return value
# This is the case where there are no more moves left to make. # we are maximizing our return. #return between 0 and 1. 1 is very good and 0 is very bad.