#pragma once
#include "template/domain_dependent/game_base.h"

template<typename Poker_t>
int next_player(int survivor_code, int player){
    int player_checked = 1;
    for(; player_checked < Poker_t::num_players; ++player_checked) {
        if(survivor_code & (1<<((player + player_checked) % Poker_t::num_players)))
            break;
    }

    if(player_checked<Poker_t::num_players){
        return (player + player_checked) % Poker_t::num_players;
    }
    else {
        return -1;
    }

}

////////////////////////////////////////////////////////////////////////////////////////////////

template<typename Poker_t>
inline constexpr std::tuple<int, int, int, int, std::array<int,Poker_t::num_rounds>, std::array<int,Poker_t::num_rounds>, std::array<int,Poker_t::num_rounds>, std::array<int,Poker_t::num_rounds>>  GameBase<Poker_t>::num_sequences_ = GameBase<Poker_t>::count_sequences();

template<typename Poker_t>
inline constexpr int GameBase<Poker_t>::num_chance = std::get<0>(GameBase<Poker_t>::num_sequences_);

template<typename Poker_t>
inline constexpr int GameBase<Poker_t>::num_internal = std::get<1>(GameBase<Poker_t>::num_sequences_);

template<typename Poker_t>
inline constexpr int GameBase<Poker_t>::num_terminal = std::get<2>(GameBase<Poker_t>::num_sequences_);

template<typename Poker_t>
inline constexpr int GameBase<Poker_t>::num_total = std::get<3>(GameBase<Poker_t>::num_sequences_);

template<typename Poker_t>
inline constexpr std::array<int, Poker_t::num_rounds> GameBase<Poker_t>::num_chance_round = std::get<4>(GameBase<Poker_t>::num_sequences_);

template<typename Poker_t>
inline constexpr std::array<int, Poker_t::num_rounds> GameBase<Poker_t>::num_internal_round = std::get<5>(GameBase<Poker_t>::num_sequences_);

template<typename Poker_t>
inline constexpr std::array<int, Poker_t::num_rounds> GameBase<Poker_t>::num_terminal_round = std::get<6>(GameBase<Poker_t>::num_sequences_);

template<typename Poker_t>
inline constexpr std::array<int, Poker_t::num_rounds> GameBase<Poker_t>::num_sequence_round = std::get<7>(GameBase<Poker_t>::num_sequences_);

template<typename Poker_t>
void GameBase<Poker_t>::init(){

    /* count the number of each type of betting sequence first */
    count_sequences();

    // 计算每个sequence的动作数以及构造转移表
    num_actions_     = new int[num_internal];
    count_actions();
    transition_      = new int*[num_internal];
    for (int u = 0; u<num_internal; ++u){
        transition_[u] = new int[num_actions[u]];
    }

    /* now that we know the counts we can construct the betting sequences */
    /* first allocate memory */
    pot_               = new type::chip_t[num_terminal][Poker_t::num_players];
    survivor_code_     = new int[num_total];
    round_             = new int[num_total];
    parent_             = new int[num_total];
    whose_turn_        = new int[num_total];
    action_result_from_ = new type::action_t[num_total];
    action_result_from_idx_ = new int[num_total];

    for (int i = 0; i<Poker_t::num_rounds; ++i){
        sequence_list_round_[i] = new int[num_sequence_round[i]];
    }

    /* now construct the sequences */
    construct_sequences();

    /* root has no parent */
    parent_[0]                 = -1;
    action_result_from_[0]     = 0;
    action_result_from_idx_[0] = -1;

    initialized = true;
}

template<typename Poker_t>
void GameBase<Poker_t>::free(){

    for (int i = 0; i<Poker_t::num_rounds; ++i){
        delete[] sequence_list_round_[i];
    }

    delete[] action_result_from_idx_;
    delete[] action_result_from_;
    delete[] parent_;
    delete[] pot_;
    delete[] survivor_code_;
    delete[] whose_turn_;
    delete[] round_;

    for (int u = 0; u<num_internal; ++u){
        delete[] transition_[u];;
    }
    delete[] transition_;

    delete[] num_actions_;
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////

