text:
//  Copyright 2020 John Buonagurio
//
//  Distributed under the Boost Software License, Version 1.0.
//
//  See accompanying file LICENSE_1_0.txt or copy at
//  http://www.boost.org/LICENSE_1_0.txt

#pragma once

/**
 * \file type_text.hpp
 * Compile-time mapping from primitive type to pxTypeText identifier wchar array.
 * \sa https://docs.microsoft.com/en-us/office/client-developer/excel/xlfregister-form-1#data-types
 */

#include <xll/config.hpp>

#include <xll/attributes.hpp>
#include <xll/fp12.hpp>
#include <xll/xloper.hpp>
#include <xll/pstring.hpp>
#include <xll/detail/type_traits.hpp>

#include <boost/mp11/list.hpp>
#include <boost/mp11/algorithm.hpp>
#include <boost/mp11/function.hpp>

#include <array>
#include <cstdint>
#include <functional>
#include <tuple>
#include <type_traits>

namespace xll {
namespace detail {

template<typename T>
struct is_array_type : std::false_type {};

template<std::size_t N>
struct is_array_type<static_fp12<N> *> : std::true_type {};

// Variable-type worksheet values and arrays (XLOPER12)
template<class T, class U = void>
struct type_text_arg {
    static_assert(!std::is_base_of_v<detail::variant_common_type, T>, "invalid operand type");
    static constexpr std::array<wchar_t, 1> value = { L'Q' };
};

template<class T>
struct type_text_arg<T, std::enable_if_t<std::is_same_v<T, variant *>>> {
    static constexpr std::array<wchar_t, 1> value = { L'Q' };
};

// Asynchronous call handle (XLOPER12, xlTypeBigData)
template<class T>
struct type_text_arg<T, std::enable_if_t<std::is_same_v<T, handle *>>> {
    static constexpr std::array<wchar_t, 1> value = { L'X' };
};

// Larger grid floating-point array structure (FP12)
template<class T>
struct type_text_arg<T, std::enable_if_t<is_array_type<T>::value>> {
    static constexpr std::array<wchar_t, 2> value = { L'K', L'%' };
};

// Asynchronous UDF return type
template<class T>
struct type_text_arg<T, std::enable_if_t<std::is_same_v<T, void>>> {
    static constexpr std::array<wchar_t, 1> value = { L'>' };
};

// Integral types
template<class T>
struct type_text_arg<T, std::enable_if_t<std::is_same_v<T, bool>>> {
    static constexpr std::array<wchar_t, 1> value = { L'A' };
};

template<class T>
struct type_text_arg<T, std::enable_if_t<std::is_same_v<T, bool *>>> {
    static constexpr std::array<wchar_t, 1> value = { L'L' };
};

template<class T>
struct type_text_arg<T, std::enable_if_t<std::is_same_v<T, uint16_t>>> {
    static constexpr std::array<wchar_t, 1> value = { L'H' };
};

template<class T>
struct type_text_arg<T, std::enable_if_t<std::is_same_v<T, int16_t>>> {
    static constexpr std::array<wchar_t, 1> value = { L'I' };
};

template<class T>
struct type_text_arg<T, std::enable_if_t<std::is_same_v<T, int16_t *>>> {
    static constexpr std::array<wchar_t, 1> value = { L'M' };
};

template<class T>
struct type_text_arg<T, std::enable_if_t<std::is_same_v<T, int32_t>>> {
    static constexpr std::array<wchar_t, 1> value = { L'J' };
};

template<class T>
struct type_text_arg<T, std::enable_if_t<std::is_same_v<T, int32_t *>>> {
    static constexpr std::array<wchar_t, 1> value = { L'N' };
};

// Floating-point types
template<class T>
struct type_text_arg<T, std::enable_if_t<std::is_same_v<T, double>>> {
    static constexpr std::array<wchar_t, 1> value = { L'B' };
};

template<class T>
struct type_text_arg<T, std::enable_if_t<std::is_same_v<T, double *>>> {
    static constexpr std::array<wchar_t, 1> value = { L'E' };
};

// Null-terminated ASCII byte string (max. 256 characters)
template<class T>
struct type_text_arg<T, std::enable_if_t<std::is_same_v<T, char *>>> {
    static constexpr std::array<wchar_t, 1> value = { L'C' };
};

template<class T>
struct type_text_arg<T, std::enable_if_t<std::is_same_v<T, const char *>>> {
    static constexpr std::array<wchar_t, 1> value = { L'C' };
};

// Null-terminated Unicode wide-character string (max. 32767 characters)
template<class T>
struct type_text_arg<T, std::enable_if_t<std::is_same_v<T, wchar_t *>>> {
    static constexpr std::array<wchar_t, 2> value = { L'C', L'%' };
};

template<class T>
struct type_text_arg<T, std::enable_if_t<std::is_same_v<T, const wchar_t *>>> {
    static constexpr std::array<wchar_t, 2> value = { L'C', L'%' };
};

template<class A>
struct attribute_text_arg;

// Function attributes
template<>
struct attribute_text_arg<tag::cluster_safe> {
    static constexpr std::array<wchar_t, 1> value = { L'&' };
};

template<>
struct attribute_text_arg<tag::volatile_> {
    static constexpr std::array<wchar_t, 1> value = { L'!' };
};

template<>
struct attribute_text_arg<tag::thread_safe> {
    static constexpr std::array<wchar_t, 1> value = { L'$' };
};

template<>
struct attribute_text_arg<tag::macro_sheet_equivalent> {
    static constexpr std::array<wchar_t, 1> value = { L'#' };
};

// Get a pxTypeText wchar array for a callable type. Concatenates the
// pxTypeText wchar arrays for the return type, arguments and attributes
// at compile-time using tuples.
//
// Requires compiler support for std::tuple_cat with std::array, and C++17
// for std::apply and std::invoke_result_t.
//
// Attributes:
// - Asynchronous
//   - Cannot be combined with Cluster Safe
//   - One 'X' parameter to store the async call handle (xlTypeBigData)
//   - void return type, '>'
// - Cluster Safe
//   - Cannot be combined with Asynchronous
//   - No XLOPER12 arguments that support range references (type 'U').
//   - Add '&' to end of type text
// - Volatile
//   - Add '!' to end of type text
// - Thread Safe
//   - Add '$' to end of type text
// - Macro Sheet Equivalent
//   - Cannot be combined with Thread Safe or Cluster Safe
//   - Handled as Volatile when using type 'R' or type 'U' arguments.
//   - Add '#' to end of type text

template<class Result, class... Args, class... Tags>
constexpr auto type_text_impl(attribute_set<Tags...>)
{
    using namespace boost::mp11;

    using async_handle_count = mp_count<mp_list<Args...>, handle *>;
    using is_asynchronous = mp_to_bool<async_handle_count>;
    using has_void_return = std::is_void<Result>;
    using is_cluster_safe = mp_contains<mp_list<Tags...>, tag::cluster_safe>;
    using is_thread_safe = mp_contains<mp_list<Tags...>, tag::thread_safe>;
    using is_macro_sheet_equivalent = mp_contains<mp_list<Tags...>, tag::macro_sheet_equivalent>;

    static_assert(!mp_any<std::is_void<Args>...>::value,
        "arguments cannot be void");
    static_assert(mp_less<async_handle_count, mp_size_t<2>>::value,
        "multiple async handles in argument list");
    static_assert(!mp_all<is_asynchronous, mp_not<has_void_return>>::value,
        "async functions must have void return type");
    static_assert(!mp_all<is_asynchronous, is_cluster_safe>::value,
        "async functions cannot be cluster-safe");
    static_assert(!mp_all<is_macro_sheet_equivalent, is_thread_safe>::value,
        "macro sheet equivalent functions cannot be thread-safe");
    static_assert(!mp_all<is_macro_sheet_equivalent, is_cluster_safe>::value,
        "macro sheet equivalent functions cannot be cluster-safe");

    // Construct tuple using std::tuple_cat specialization for std:array.
    constexpr auto tuple = std::tuple_cat(
        type_text_arg<extern_c_type_t<Result>>::value,
        type_text_arg<extern_c_type_t<Args>>::value...,
        attribute_text_arg<Tags>::value...
    );

    // Construct wchar array from the flat tuple.
    constexpr auto make_array = [](auto&& ...x) {
        return std::array{x...};
    };

    return std::apply(make_array, tuple);
}

// Overloads for various calling conventions and attributes.

#if BOOST_ARCH_X86_32

template<class F, class... Args, class... Tags>
constexpr auto type_text(F (__cdecl *)(Args...), attribute_set<Tags...> attrs)
{
    using result_t = std::invoke_result_t<F(Args...), Args...>;
    return detail::type_text_impl<result_t, Args...>(attrs);
}

template<class F, class... Args, class... Tags>
constexpr auto type_text(F (__stdcall *)(Args...), attribute_set<Tags...> attrs)
{
    using result_t = std::invoke_result_t<F(Args...), Args...>;
    return detail::type_text_impl<result_t, Args...>(attrs);
}

template<class F, class... Args, class... Tags>
constexpr auto type_text(F (__fastcall *)(Args...), attribute_set<Tags...> attrs)
{
    using result_t = std::invoke_result_t<F(Args...), Args...>;
    return detail::type_text_impl<result_t, Args...>(attrs);
}

template<class F, class... Args, class... Tags>
constexpr auto type_text(F (__vectorcall *)(Args...), attribute_set<Tags...> attrs)
{
    using result_t = std::invoke_result_t<F(Args...), Args...>;
    return detail::type_text_impl<result_t, Args...>(attrs);
}

#else

template<class F, class... Args, class... Tags>
constexpr auto type_text(F (*)(Args...), attribute_set<Tags...> attrs)
{
    using result_t = std::invoke_result_t<F(Args...), Args...>;
    return detail::type_text_impl<result_t, Args...>(attrs);
}

#endif // BOOST_ARCH_X86_32

} // namespace detail
} // namespace xll

max_stars_repo_name: jbuonagurio/libxll

max_issues_repo_name: jbuonagurio/libxll

max_forks_repo_name: jbuonagurio/libxll


text:
#include <gtest/gtest.h>
#include <random>
#include <gmp.h>
#include <boost/multiprecision/gmp.hpp>
#include <ojlibs/power.hpp>
using namespace std;
using namespace ojlibs;
namespace bm = boost::multiprecision;

std::mt19937 gen;

void test_power(const bm::mpz_int &a, int b) {
    bm::mpz_int expect = pow(a, b);
    bm::mpz_int answer = power(a, b);

    EXPECT_EQ(expect, answer);
}

TEST(BASIC, SMALL) {
    test_power(12, 0);
    test_power(12, 1);
    test_power(12, 2);
}

TEST(BASIC, RANDOM) {
    gmp_randstate_t ran;
    gmp_randinit_default(ran);

    static const int TEST_GROUP = 1000;
    uniform_int_distribution<> dist(0, 10000);

    for (int i = 0; i < TEST_GROUP; ++i) {
        bm::mpz_int a;
        mpz_urandomb(a.backend().data(), ran, 15);

        int b = dist(gen);

        test_power(a, b);
    }
}

ext: cpp

max_stars_repo_name: georeth/OJLIBS

max_issues_repo_name: georeth/OJLIBS

max_forks_repo_name: georeth/OJLIBS


text:
// SPDX-License-Identifier: BSD-3-Clause AND Apache-2.0
/*
Copyright (c) 2018, Regents of the University of California
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:

* Redistributions of source code must retain the above copyright notice, this
  list of conditions and the following disclaimer.

* Redistributions in binary form must reproduce the above copyright notice,
  this list of conditions and the following disclaimer in the documentation
  and/or other materials provided with the distribution.

* Neither the name of the copyright holder nor the names of its
  contributors may be used to endorse or promote products derived from
  this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

Copyright 2019 Blue Cheetah Analog Design Inc.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

#include <algorithm>

#include <boost/container_hash/hash.hpp>

#include <cbag/layout/via_info.h>
#include <cbag/layout/via_param.h>
#include <cbag/util/unique_heap.h>

namespace cbag {
namespace layout {

constexpr offset_t MAX_INT = std::numeric_limits<offset_t>::max();

venc_data::venc_data() = default;

via_info::via_info() = default;

via_info::via_info(std::string &&name, vector &&cdim, vector &&s, std::vector<vector> &&s2_list,
                   std::vector<vector> &&s3_list, std::array<venc_info, 2> &&e_list)
    : name_(std::move(name)), cut_dim_(std::move(cdim)), sp_list_(), sp2_list_(std::move(s2_list)),
      sp3_list_(std::move(s3_list)), enc_list_(std::move(e_list)) {
    sp_list_.push_back(std::move(s));
    if (sp2_list_.empty()) {
        sp2_list_.push_back(sp_list_.front());
    }
    if (sp3_list_.empty()) {
        sp3_list_.insert(sp3_list_.end(), sp2_list_.begin(), sp2_list_.end());
    }
}

const std::string &via_info::get_name() const noexcept { return name_; }

cnt_t get_n_max(offset_t dim, offset_t w, offset_t sp) {
    if (sp == MAX_INT) {
        // NOTE: always return 1, as we could have negative enclosure
        return 1;
    }
    return (dim + sp) / (w + sp);
}

const std::vector<vector> &get_enc_list(const venc_info &enc_info, offset_t width) {
    for (const auto &data : enc_info) {
        if (width <= data.width)
            return data.enc_list;
    }
    return enc_info.back().enc_list;
}

vector get_metal_dim(vector box_dim, vector arr_dim, const venc_info &enc_info,
                     orientation_2d_t dir_idx, bool extend) {
    auto pdir_idx = 1 - dir_idx;
    auto wire_w = box_dim[pdir_idx];
    vector ans;
    ans[dir_idx] = MAX_INT;
    ans[pdir_idx] = wire_w;
    for (const auto &enc_vec : get_enc_list(enc_info, wire_w)) {
        vector enc_dim = {2 * enc_vec[0] + arr_dim[0], 2 * enc_vec[1] + arr_dim[1]};
        if (enc_dim[pdir_idx] <= box_dim[pdir_idx]) {
            if (extend || enc_dim[dir_idx] <= box_dim[dir_idx]) {
                // enclosure rule passed, get optimal metal dimension
                ans[dir_idx] = std::min(ans[dir_idx], enc_dim[dir_idx]);
            }
        }
    }
    if (ans[dir_idx] == MAX_INT) {
        // no solution
        ans[0] = 0;
        ans[1] = 0;
    } else {
        ans[dir_idx] = std::max(ans[dir_idx], box_dim[dir_idx]);
    }

    return ans;
}

offset_t get_arr_dim(cnt_t n, offset_t w, offset_t sp) {
    if (sp == MAX_INT)
        if (n != 1)
            return 0;
        else
            return w;
    else
        return n * (w + sp) - sp;
}

via_param via_info::get_via_param(vector box_dim, direction_1d vdir, orientation_2d ex_dir,
                                  orientation_2d ex_adj_dir, bool extend) const {
    via_param ans;

    auto vidx = to_int(vdir);
    auto dir_idx = to_int(ex_dir);
    auto adj_dir_idx = to_int(ex_adj_dir);

    // get maximum possible number of vias
    auto min_sp = vector{MAX_INT, MAX_INT};
    for (const auto &arr : sp_list_) {
        min_sp[0] = std::min(min_sp[0], arr[0]);
        min_sp[1] = std::min(min_sp[1], arr[1]);
    }
    for (const auto &arr : sp2_list_) {
        min_sp[0] = std::min(min_sp[0], arr[0]);
        min_sp[1] = std::min(min_sp[1], arr[1]);
    }
    for (const auto &arr : sp3_list_) {
        min_sp[0] = std::min(min_sp[0], arr[0]);
        min_sp[1] = std::min(min_sp[1], arr[1]);
    }
    auto nx_max = get_n_max(box_dim[0], cut_dim_[0], min_sp[0]);
    auto ny_max = get_n_max(box_dim[1], cut_dim_[1], min_sp[1]);

    // check if it's possible to place a via
    if (nx_max == 0 || ny_max == 0)
        return ans;

    // use priority queue to find maximum number of vias
    util::unique_heap<via_cnt_t, boost::hash<via_cnt_t>> heap;
    heap.emplace(nx_max * ny_max, std::array<cnt_t, 2>{nx_max, ny_max});

    while (!heap.empty()) {
        auto & [ via_cnt, num_via ] = heap.top();
        auto[nx_cur, ny_cur] = num_via;

        // get list of valid via spacing
        const std::vector<vector> *sp_vec_ptr;
        if (nx_cur == 2 && ny_cur == 2) {
            sp_vec_ptr = &sp2_list_;
        } else if (nx_cur > 1 && ny_cur > 1) {
            sp_vec_ptr = &sp3_list_;
        } else {
            sp_vec_ptr = &sp_list_;
        }

        // find optimal legal enclosure via
        vector opt_arr_dim;
        std::array<vector, 2> opt_mdim = {vector{MAX_INT, MAX_INT}, vector{MAX_INT, MAX_INT}};
        vector opt_sp = {-1, -1};
        for (const auto &sp_via : *sp_vec_ptr) {
            vector arr_dim = {get_arr_dim(nx_cur, cut_dim_[0], sp_via[0]),
                              get_arr_dim(ny_cur, cut_dim_[1], sp_via[1])};
            if (arr_dim[0] == 0 || arr_dim[1] == 0)
                continue;

            auto m_dim = get_metal_dim(box_dim, arr_dim, enc_list_[vidx], dir_idx, extend);

            if (m_dim[0] == 0)
                continue;
            auto adj_m_dim =
                get_metal_dim(box_dim, arr_dim, enc_list_[vidx ^ 1], adj_dir_idx, extend);

            if (adj_m_dim[0] == 0)
                continue;

            if (m_dim[dir_idx] <= opt_mdim[vidx][dir_idx] &&
                adj_m_dim[adj_dir_idx] <= opt_mdim[1 - vidx][adj_dir_idx]) {
                opt_arr_dim = arr_dim;
                opt_mdim[vidx] = m_dim;
                opt_mdim[1 - vidx] = adj_m_dim;
                opt_sp = sp_via;
            }
        }

        if (opt_sp[0] < 0) {
            // fail to find legal via enclosure
            // continue searching
            if (nx_cur > 1) {
                heap.emplace((nx_cur - 1) * ny_cur, std::array<cnt_t, 2>{nx_cur - 1, ny_cur});
            }
            if (ny_cur > 1) {
                heap.emplace(nx_cur * (ny_cur - 1), std::array<cnt_t, 2>{nx_cur, ny_cur - 1});
            }
        } else {
            // solution found
            // set space to 0 if ony 1 via, this prevents space with MAX_INT values.
            if (nx_cur == 1)
                opt_sp[0] = 0;
            if (ny_cur == 1)
                opt_sp[1] = 0;
            auto enc1x = (opt_mdim[0][0] - opt_arr_dim[0]) / 2;
            auto enc1y = (opt_mdim[0][1] - opt_arr_dim[1]) / 2;
            auto enc2x = (opt_mdim[1][0] - opt_arr_dim[0]) / 2;
            auto enc2y = (opt_mdim[1][1] - opt_arr_dim[1]) / 2;

            ans = {nx_cur, ny_cur, cut_dim_[0], cut_dim_[1], opt_sp[0], opt_sp[1], enc1x,
                   enc1x,  enc1y,  enc1y,       enc2x,       enc2x,     enc2y,     enc2y};
            return ans;
        }

        heap.pop();
    }

    return ans;
}

via_info via_info::get_flip_xy(std::string new_name) const {
    auto ans = *this;
    ans.name_ = std::move(new_name);

    std::swap(ans.cut_dim_[0], ans.cut_dim_[1]);
    for (auto &vec : ans.sp_list_) {
        std::swap(vec[0], vec[1]);
    }
    for (auto &vec : ans.sp2_list_) {
        std::swap(vec[0], vec[1]);
    }
    for (auto &vec : ans.sp3_list_) {
        std::swap(vec[0], vec[1]);
    }
    for (auto &data : ans.enc_list_[0]) {
        for (auto &vec : data.enc_list) {
            std::swap(vec[0], vec[1]);
        }
    }
    for (auto &data : ans.enc_list_[1]) {
        for (auto &vec : data.enc_list) {
            std::swap(vec[0], vec[1]);
        }
    }

    return ans;
}

void _add_flipped_enclosures_helper(venc_info &obj) {
    for (auto &data : obj) {
        auto n = data.enc_list.size();
        for (decltype(n) i = 0; i < n; ++i) {
            auto &enc_vec = data.enc_list[i];
            if (enc_vec[0] != enc_vec[1]) {
                data.enc_list.push_back(vector{enc_vec[1], enc_vec[0]});
            }
        }
    }
}

void via_info::add_flipped_enclosures() {
    _add_flipped_enclosures_helper(enc_list_[0]);
    _add_flipped_enclosures_helper(enc_list_[1]);
}

} // namespace layout
} // namespace cbag

max_stars_repo_name: growly/cbag

max_issues_repo_name: growly/cbag

max_forks_repo_name: growly/cbag


text:
/* Copyright (C) 2015 INRA
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */

#include "echll.hpp"
#include "writer.hpp"
#include <ostream>
#include <fstream>
#include <cassert>

namespace vle { namespace devsml2 { namespace echll {

inline std::string abstract_name_get(const Abstract *model);

std::ostream& operator<<(std::ostream& os, const STAValue& value);

void write_variable(std::ostream& os, const Variable& variable);
void write_entities(std::ostream& os, const DevsML& data);
void write_internal(std::ostream& os, const Deltint& fn);
void write_internals(std::ostream& os, const Atomic& atomic);
void write_external(std::ostream& os, const Deltext& fn);
void write_externals(std::ostream& os, const Atomic& atomic);
void write_state_machine(std::ostream& os, const Atomic& atomic);
void write_atomic(std::ostream& os, const Atomic& atomic);
void write_coupled(std::ostream& os, const Coupled& coupled);
void write_main(std::ostream& os, const DevsML& data);

void write_variable(std::ostream& os, const Variable& variable)
{
    os << "    ";

    switch (variable.type) {
    case VARIABLE_TYPE_INT:
        os << "int";
        break;
    case VARIABLE_TYPE_DOUBLE:
        os << "double";
        break;
    case VARIABLE_TYPE_STRING:
        os << "std::string";
        break;
    case VARIABLE_TYPE_BOOLEAN:
        os << "bool";
        break;
    case VARIABLE_TYPE_ENTITY:
        os << variable.entity->name;
        break;
    default:
        assert(false && "unknown state");
    }

    os << ' ' << variable.name << ";\n";
}

void write_entities(std::ostream& os, const DevsML& data)
{
    for (const auto& entity : data.entities)
        os << "struct " << entity.name << ";\n";

    os << '\n';

    for (const auto& entity : data.entities) {
        os << "struct " << entity.name;

        if (entity.supertype)
            os << " : " << entity.supertype->name;

        os << " {\n";

        for (const auto& var: entity.variables)
            write_variable(os, var);

        os << "};\n";
    }
}

struct code_ostream {
    code_ostream(const std::string& code_)
        : code(code_)
    {}

    const std::string& code;
};

std::ostream& operator<<(std::ostream& os, const code_ostream& code);

std::ostream& operator<<(std::ostream& os, const code_ostream& code)
{
    if (not code.code.empty())
        return os << "{\n" << code.code << "}\n";

    return os;
}

std::ostream& operator<<(std::ostream& os, const STAValue& value)
{
    const double *real = boost::get <const double>(&value);
    if (real != nullptr)
        return os << *real;

    const Variable* const* variable = boost::get <Variable*>(&value);
    if (variable != nullptr)
        return os << (*variable)->name;

    assert(false && "STAValue convertion failure");
}

void write_internal(std::ostream& os, const Deltint& fn)
{
    os << "    case " << fn.state->name << ":\n"
       << "        m_current_state = " << fn.target->name << ";\n"
       << "        " << fn.code << "\n"
       << "        return " << fn.target->value << ";\n";

    os << ";\n";
}

void write_internals(std::ostream& os, const Atomic& atomic)
{
    os << "    time_type internal()\n"
       << "    {\n";

    if (not atomic.statemachine.deltint.empty()) {
        os << "    switch (m_current_state) {\n";

        for (const auto& fn : atomic.statemachine.deltint)
            write_internal(os, fn);

        if (atomic.statemachine.deltint.size() != atomic.stas.size())
            os << "    default:\n"
                << "        return FIXME;\n";

        os << "    }\n";
    }

    os << "    }\n";
}

void write_external(std::ostream& os, const Deltext& fn)
{
    (void)fn;
    (void)os;
}

void write_externals(std::ostream& os, const Atomic& atomic)
{
    (void)atomic;

    os << "    time_type external(const time_type& e, const time_type& r, const time_type& t)\n"
       << "    {\n"
       << "    }\n";
}

void write_state_machine(std::ostream& os, const Atomic& atomic)
{
    os << "    virtual time_type\n"
       << "    init(vle::Common /*common*/, const time_type& time) override\n"
       << "    {\n"
       << "        m_current_state = " << atomic.statemachine.initState.state->name
       << "        " << atomic.statemachine.initState.code << "\n"
       << "        return 0.0;\n" // FIXME
       << "    }\n";

    os << "    virtual time_type\n"
       << "    delta(const time_type& e, const time_type& r, const time_type& t) override\n"
       << "    {\n"
       << "        if (x.empty() && r == 0.0) {\n";

    //
    // FIXME We can improve this code generation for both IGNORE_INPUT and
    // INPUT_ONLY which can be merged with internal or external condition part.
    //

    switch (atomic.statemachine.confluent) {
    case CONFLUENT_IGNORE_INPUT:
        os << "            internal();\n";
        break;
    case CONFLUENT_INPUT_ONLY:
        os << "            external(e, r, t);\n";
        break;
    case CONFLUENT_INPUT_FIRST:
        os << "            external(e, r, t);\n"
           << "            internal();\n";
        break;
    case CONFLUENT_INPUT_LATER:
        os << "            internal();\n"
           << "            external(e, r, t);\n";
        break;
    default:
        assert(false && "unknown state");
    }

    os << "        } else if (x.empty()) {\n"
       << "            return internal();\n"
       << "        } else {\n"
       << "            return external(e, r, t);\n"
       << "        }\n"
       << "    }\n";

    os << "    virtual void\n"
       << "    lambda() override const\n"
       << "    {\n";

    for (const auto& fn : atomic.statemachine.outfn) {
        os << "        if (" << fn.state->name << " == m_current_state) {\n"
           << "        }\n"
           << "};\n";
    }

    os << "    }\n";
}

void write_atomic(std::ostream& os, const Atomic& atomic)
{
    os << "class " << atomic.name << "\n"
        << "{\n"
        << "public:\n"
        << "    " << atomic.name << "(const vle::Context& ctx)\n"
        << "         : AtomicModel(ctx, " << atomic.ins.size() << ", "
                                          << atomic.outs.size() << ")\n"
        << "    {}\n\n";

    for (const auto& var : atomic.variables)
        write_variable(os, var);

    os << "    enum { ";
    for (auto i = atomic.stas.begin(), e = atomic.stas.end(); i != e; ++i) {
        os << i->name;
        if ((i + 1) != e)
            os << ", ";
    }
    os << " } m_current_state;\n";

    write_state_machine(os, atomic);

    os << "};\n";
}

inline
std::string abstract_name_get(const Abstract *model)
{
    assert(model && "abstract_name_get called with null model");

    switch (model->type) {
    case COMPONENT_ATOMIC:
        return static_cast <const Atomic*>(model)->name;
    case COMPONENT_COUPLED:
        return static_cast <const Coupled*>(model)->name;
    default:
        assert(false && "unknown state");
    }
}

void write_coupled(std::ostream& os, const Coupled& coupled)
{
    os << "class " << coupled.name << "\n"
       << "{\n"
       << "public:\n"
       << "    " << coupled.name << "(const vle::Context& ctx)\n"
       << "        : CoupledModel(ctx," << coupled.ins.size() << ", "
                                        << coupled.outs.size() << ")\n"
       << "    {}\n\n";

    for (const auto& component: coupled.components)
        os << "    " << abstract_name_get(component.model)
                     << " " << component.name << ";\n";

    os << '\n';

    os << "    void post(const UpdatedPort& out, UpdatedPort& in) const\n"
       << "    {\n";

    /// FIXME perhaps check @e out paramter to improve speedup.
    //for (const auto& coupling : coupled.couplings) {
    //}

    os << "        }\n"
       << "    }\n";

    os << "};\n";
}

void write_main(std::ostream& os, const DevsML& data)
{
    os << "int main(int argc, char **argv)\n"
        << "{\n"
        << "    vle::Context ctx = std::make_shared <vle::ContextImpl>();\n"
        << "    DSDE dsde_engine;\n"
        << "    " << data.top->name << " model(ctx);\n"
        << "    vle::SimulationDbg <MyDSDE> sim(ctx, dsde_engine);\n"
        << "    double final_date = sim.run(model, 0., 100.);\n"
        << "}\n"
        << std::endl;
}

void write(const DevsML& data,
           const std::string& output_directory,
           const std::string& /*package_name*/,
           const license& lic)
{
    std::string filename(output_directory);
    if (!filename.empty())
        filename += '/';

    filename += data.top->name + ".cpp";

    std::ofstream ofs(filename);
    if (not ofs)
        throw writer_error(filename, "failed to open");

    ofs << lic << '\n'
        << "#include <vle/echll/dsde/dsde.hpp>\n"
        << "#include <vle/echll/port.hpp>\n"
        << "#include <boost/variant.hpp>\n"
        << "#include <string>\n"
        << "#include <vector>\n"
        << '\n'
        << "using Value = boost::variant <int, double, std::string, bool>;\n"
        << "using Time = vle::DoubleTime;\n"
        << "using time_type = Time::time_type;\n"
        << "using Port = vle::SparsePortList <Value>;\n"
        << "using DSDE = vle::dsde::Engine <Time>;\n"
        << "using AtomicModel = vle::dsde::AtomicModel <Time, Port, Port>;\n"
        << "using CoupledModel = vle::dsde::CoupledModel\n"
        << "                 <Time, Port, Port, Port, Port,\n"
        << "                  vle::dsde::TransitionPolicyDefault <Time>>;\n"
        << '\n';

    write_entities(ofs, data);

    for (const auto& atomic : data.atomics)
        write_atomic(ofs, atomic);

    for (const auto& coupled: data.coupleds)
        write_coupled(ofs, coupled);

    write_main(ofs, data);
}

}}}

max_stars_repo_name: vle-forge/Echll

max_issues_repo_name: vle-forge/Echll

max_forks_repo_name: vle-forge/Echll


text:
#include <fstream>
#include <iostream>

#include <boost/exception/all.hpp>
#include <boost/filesystem.hpp>
#include <boost/program_options.hpp>

#include <framework/exception.h>
#include <framework/settings.h>
#include <framework/paths.h>

namespace po = boost::program_options;
namespace fs = boost::filesystem;

namespace fw {

static bool is_initialized = false;
static po::variables_map g_variables_map;
static po::options_description g_option_descriptions;
static fs::path g_executable_path;

settings::settings() {
  if (!is_initialized) {
    BOOST_THROW_EXCEPTION(fw::exception() << message_error_info("settings::initialize() has not been called."));
  }
}

settings::~settings() {
}

po::variables_map& settings::get_variables() const {
  return g_variables_map;
}

po::variable_value const &settings::get_variable_value(std::string const &name) const {
  po::variable_value const &val = g_variables_map[name];
  if (val.empty()) {
    BOOST_THROW_EXCEPTION(fw::exception()
        << fw::message_error_info("specified option does not exist, or has no value: " + name));
  }

  return val;
}

void settings::print_help() {
  std::cerr << g_option_descriptions << std::endl;
}

fs::path settings::get_executable_path() const {
  return g_executable_path;
}

// you must call this at program startup (*before* you call the framework::initialize() method!) it'll parse the
// command-line options and so on.
void settings::initialize(po::options_description const &additional_options, int argc, char **argv,
    std::string const &options_file/* = "default.conf"*/) {
  g_executable_path = argv[0];

  po::options_description graphics_options("Graphics options");
  graphics_options.add_options()
      ("windowed-width", po::value<int>()->default_value(800), "The width of the window when running in windowed mode")
      ("windowed-height", po::value<int>()->default_value(600), "The height of the window when running in windowed mode")
      ("fullscreen-width,W", po::value<int>()->default_value(0), "The width of the screen when running in fullscreen mode")
      ("fullscreen-height,H", po::value<int>()->default_value(0), "The height of the screen when running in fullscreen mode")
      ("windowed", po::value<bool>()->default_value(true), "Run in windowed mode")
      ("disable-antialiasing", "If specified, we'll disable fullscreen anti-aliasing (better performance, lower quality)")
    ;

  po::options_description audio_options("Audio options");
  audio_options.add_options()
      ("disable-audio", "If specified, audio is completely disabled (usually only useful for debugging)")
    ;

  po::options_description debugging_options("Debugging options");
  debugging_options.add_options()
      ("debug-logfile", po::value<std::string>()->default_value(""), "Name of the file to do debug logging to. If not specified, does not log.")
      ("debug-console", po::value<bool>()->default_value(true), "If set, we'll log to the console as well as the log file.")
      ("debug-libcurl", po::value<bool>()->default_value(false), "If true, debug HTTP requests and responses.")
      ("debug-view", po::value<bool>()->default_value(false), "If true, show some debug info in the bottom-right of the screen.")
      ("dbghelp-path", po::value<std::string>()->default_value(""), "Windows-only, path to dbghelp.dll file.")
    ;

  po::options_description other_options("Other options");
  other_options.add_options()
      ("help", "Prints this help message.")
      ("data-path", po::value<std::string>()->default_value(""), "Path to load data files from.")
      ("lang", po::value<std::string>()->default_value("en"), "Name of the language we'll use for display and UI, etc. Default is 'en' (English)")
    ;

  po::options_description keybinding_options("Keybindings");
  keybinding_options.add_options()
      ("bind.toggle-fullscreen", po::value<std::string>()->default_value("Alt+Enter"))
      ("bind.cam-left", po::value<std::string>()->default_value("Left"))
      ("bind.cam-right", po::value<std::string>()->default_value("Right"))
      ("bind.cam-forward", po::value<std::string>()->default_value("Up"))
      ("bind.cam-backward", po::value<std::string>()->default_value("Down"))
      ("bind.cam-rot-left", po::value<std::string>()->default_value("["))
      ("bind.cam-rot-right", po::value<std::string>()->default_value("]"))
      ("bind.cam-zoom-in", po::value<std::string>()->default_value("Plus"))
      ("bind.cam-zoom-out", po::value<std::string>()->default_value("Minus"))
      ("bind.cam-rot-mouse", po::value<std::string>()->default_value("Middle-Mouse"))
    ;

  g_option_descriptions.add(graphics_options)
      .add(audio_options)
      .add(debugging_options)
      .add(other_options)
      .add(additional_options)
      .add(keybinding_options);

  po::store(po::parse_command_line(argc, argv, g_option_descriptions), g_variables_map);

  // Mark ourselves initialized so that fw::install_base_path can query the command-line for data-path.
  is_initialized = true;

  std::ifstream default_ini((fw::install_base_path() / options_file).string().c_str());
  po::store(po::parse_config_file(default_ini, g_option_descriptions), g_variables_map);
  default_ini.close();

  std::ifstream custom_ini((fw::user_base_path() / options_file).string().c_str());
  po::store(po::parse_config_file(custom_ini, g_option_descriptions), g_variables_map);
  custom_ini.close();

  po::notify(g_variables_map);
}

}

ext: cc

max_stars_repo_name: codeka/ravaged-planets

max_issues_repo_name: codeka/ravaged-planets

max_forks_repo_name: codeka/ravaged-planets


text:
/*
 * LYHoldemGame.cpp
 *
 *  Created on: 2013-7-6
 *      Author: caiqingfeng
 */

#include "LYHoldemGame.h"
#include "LYHoldemTable.h"
#include "common/src/my_log.h"
#include <boost/foreach.hpp>
#include "LYHoldemAlgorithmDelegate.h"
#include <iostream>
#include "poker/src/LYCardHelpers.h"

void LYHoldemGame::reset()
{
	_id = "";
	gameStatus = LY_HOLDEMGAME_OVER;
	smallBlindPrice = 0;
	bigBlindPrice = 0;
	btnSeatNo = ::LYHouse;
	sbSeatNo = ::LYHouse;
	bbSeatNo = ::LYHouse;
	roundOfTournament = 0;

	seqNo = 0;
	round = LYGameInit;
	betIfCall = 0;
	minBetIfRaise = 0;
	seqNo = 0;
	dutySeatNo = ::LYHouse;
	continueThisRound = LYHoldemRoundCont;
	flopCards.clear();
	turnCard = flipCard;
	riverCard = flipCard;

	flop_action.table_id = table->_id;
	turn_action.table_id = table->_id;
	river_action.table_id = table->_id;
	assurance_summary_action.table_id = table->_id;
	assurance_summary_action.summarizeAssure(0, table->assurance_income);

	assureActionNumbers = 0;
	assureActions.clear();
}
/*
 * 初始化，本构造函数只能用于反序列化，如从DB或者NW中收到Scene，先创建一个空的Game实例，然后再调用赋值
 * 仅用于从NW中收到Scene，之所以不在构造中传参，是因为Protobuf比较大，并且跟具体项目关系比较大，因此不从构造中设置
 */
LYHoldemGame::LYHoldemGame(const std::string &game_id, LYHoldemAlgorithmDelegate *had)
	:LYGame((LYPokerAlgorithmDelegate *)had), pm(this)
{
	this->reset();
	_id = game_id;
}

/*
 * 初始化，本构造函数用于反序列化，如从DB或者NW中收到Scene，先创建一个空的Game实例，然后再赋值
 */
LYHoldemGame::LYHoldemGame(const std::string &game_id,
		std::vector<LYSeatPtr> &all_seats, LYHoldemTable *tbl, LYHoldemAlgorithmDelegate *had) :
				LYGame(game_id, all_seats, (LYTable *)tbl, (LYPokerAlgorithmDelegate *)had), pm(this)
{
	this->reset();
	_id = game_id;

	sortSeats();
}

/*
 * 初始化，本构造函数用于反序列化，仅用于从DB中恢复Table/Game，直接构造函数传参
 * 20160320
 */
LYHoldemGame::LYHoldemGame(const std::string &game_id,
		std::vector<LYSeatPtr> &all_seats, LYHoldemTable *tbl,
		std::vector < std::pair<std::string, std::string> >& kvps,
		LYHoldemAlgorithmDelegate *had) :
				LYGame(game_id, all_seats, (LYTable *)tbl, (LYPokerAlgorithmDelegate *)had), pm(this)
{
	this->reset();
	_id = game_id;

	std::vector < std::pair<std::string, std::string> >::iterator it = kvps.begin();
	for (; it!=kvps.end(); it++) {
		std::pair<std::string, std::string> kvp = *it;
		if (kvp.first == "gameStatus") {
			this->gameStatus = std::stoi(kvp.second);
		} else if (kvp.first == "_id") {
			this->_id = kvp.second;
		} else if (kvp.first == "roundOfTournament") {
			this->roundOfTournament = std::stoi(kvp.second);
		} else if (kvp.first == "btnSeatNo") {
			this->btnSeatNo = (LYApplicant)std::stoi(kvp.second);
		} else if (kvp.first == "sbSeatNo") {
			this->sbSeatNo = (LYApplicant)std::stoi(kvp.second);
		} else if (kvp.first == "bbSeatNo") {
			this->bbSeatNo = (LYApplicant)std::stoi(kvp.second);
		} else if (kvp.first == "flopCards") {
			LYCardHelpers::stringifiedIntToCards(kvp.second, this->flopCards);
		} else if (kvp.first == "turnCard") {
			this->turnCard = LYCard(std::stoi(kvp.second));
		} else if (kvp.first == "riverCard") {
			this->riverCard = LYCard(std::stoi(kvp.second));
		} else if (kvp.first == "smallBlindPrice") {
			this->smallBlindPrice = std::stoi(kvp.second);
		} else if (kvp.first == "bigBlindPrice") {
			this->bigBlindPrice = std::stoi(kvp.second);
		} else if (kvp.first == "seqNo") {
			this->seqNo = std::stoi(kvp.second);
		} else if (kvp.first == "round") {
			this->round = (LYGameRound)std::stoi(kvp.second);
		} else if (kvp.first == "dutySeatNo") {
			this->dutySeatNo = (LYApplicant)std::stoi(kvp.second);
		} else if (kvp.first == "betIfCall") {
			this->betIfCall = std::stoi(kvp.second);
		} else if (kvp.first == "minBetIfRaise") {
			this->minBetIfRaise = std::stoi(kvp.second);
		} else if (kvp.first == "betBySeatNo") {
			this->betBySeatNo = (LYApplicant)std::stoi(kvp.second);
		} else if (kvp.first == "continueThisRound") {
			this->continueThisRound = (LYHoldemRoundContinue)(std::stoi(kvp.second));
		} else if (kvp.first == "assureActionNumbers") {
			this->assureActionNumbers = std::stoi(kvp.second);
		} else if (kvp.first == "lastPollingAt") {
			this->lastPollingAt = std::stoi(kvp.second);
		} else if (kvp.first == "lastPollingAction") {
			this->lastPollingAction = LYHoldemAction::build_from_action_string(kvp.second);
		}
	}

	sortSeatsWithoutChangeStatus();
	reverseCommunityCardActions();
	this->appendLog(this->toString());
}

LYHoldemGame::LYHoldemGame(const std::string &game_id,
		std::vector<LYSeatPtr> &all_seats, unsigned int sbp, unsigned int bbp,
		LYSeatPtr btnSeat, LYSeatPtr sbSeat, LYSeatPtr bbSeat,
		LYHoldemTable *tbl, LYHoldemAlgorithmDelegate *had, unsigned int rot) :
				LYGame(game_id, all_seats, (LYTable *)tbl, (LYPokerAlgorithmDelegate *)had), pm(this)
{
	this->reset();
	_id = game_id;
	// TODO Auto-generated constructor stub
	smallBlindPrice = sbp;
	bigBlindPrice = bbp;
	btnSeatNo = btnSeat->seatNo;
	sbSeatNo = sbSeat->seatNo;
	bbSeatNo = bbSeat->seatNo;
	roundOfTournament = rot;
//	LY_LOG_DBG("small="<<smallBlindPrice << ", big="<<bigBlindPrice);

	sortSeats();

	//init dynamics
	round = LYGameInit;
	betIfCall = 0;
	minBetIfRaise = 0;
	seqNo = 0;
	dutySeatNo = sbSeatNo;
	continueThisRound = LYHoldemRoundCont;
	LYHoldemAction action;
	action.betSmallBlind(sbSeatNo, smallBlindPrice);
	this->onAction(action);
//	seqNo++;
	dutySeatNo = bbSeatNo;
	action.betBigBlind(bbSeatNo, bigBlindPrice);
	this->onAction(action);
	//shuffle and set cards to seats
//    this->deck.shuffle();
	//set pocket cards
    std::vector<LYSeatPtr>::iterator it = sortedSeats.begin();
    for (; it!=sortedSeats.end(); it++) {
    	LYSeatPtr seat = *it;
		LYHoldemSeat *hs = (LYHoldemSeat *)seat.get();
		LYCard card = deck.pop();
//    	LY_LOG_DBG("first handcard:" << card.toInteger());
//		hs->setFirstCard(card);
		hs->setFirst(card);
//    	LY_LOG_DBG("first handcard:" << hs->firstCard().toInteger() << ", seat=" << hs->seatNo);
	}
    it = sortedSeats.begin();
    for (; it!=sortedSeats.end(); it++) {
    	LYSeatPtr seat = *it;
		LYHoldemSeat *hs = (LYHoldemSeat *)seat.get();
		LYCard card = deck.pop();
//    	LY_LOG_DBG("second handcard:" << card.toInteger());
//		hs->setSecondCard(card);
		hs->setSecond(card);
//    	LY_LOG_DBG("second handcard:" << card.toInteger() << ", seat=" << hs->seatNo);
	}
	//设置Community Actions
	this->genCommunityCardActions();

	//set dynamics
	betIfCall = bigBlindPrice;
	minBetIfRaise = bigBlindPrice * 2;
	seqNo = 0;
	dutySeatNo = this->fetchNextSeatInGame(bbSeatNo)->seatNo;
	round = LYGamePreflop;

	this->genNewScene();
	this->appendLog(this->toString());
}

LYHoldemGame::~LYHoldemGame() {
	// TODO Auto-generated destructor stub
	scenes.clear();
}

enum LYGameRound LYHoldemGame::getRound()
{
	return round;
}

LYHoldemScenePtr LYHoldemGame::getLastScene()
{
	if (scenes.size() < 1) return LYHoldemScenePtr();
	return scenes.back();
}

/*
 * sortSeats: sort all seats according to small_blind, big_blind, ..., button
 */
void LYHoldemGame::sortSeats()
{
    this->sortedSeats.clear();
	if (::LYHouse == this->sbSeatNo || ::LYHouse == this->btnSeatNo || ::LYHouse == this->bbSeatNo || this->seatsOfTable.size() < 2) return;
    LYSeatPtr seat = this->smallBlindSeat();
    if (table->occupied_seat_number == 2) seat = this->bigBlindSeat();

	int i = 0;
    while (seat->seatNo != this->btnSeatNo && i < 9) {
		i++;
    	seat->status = LYSeatInGame;
    	LYHoldemSeat *hs = (LYHoldemSeat *)seat.get();
    	hs->gameStatus = LYSeatHoldemWaiting;
    	sortedSeats.push_back(seat);
    	seat = table->fetchNextOccupiedSeat(seat->seatNo);
    	if (NULL == seat.get()) break;
    }
    buttonSeat()->status = LYSeatInGame;
	LYHoldemSeat *hs = (LYHoldemSeat *)buttonSeat().get();
	hs->gameStatus = LYSeatHoldemWaiting;
    sortedSeats.push_back(this->buttonSeat());
}

void LYHoldemGame::debugGame()
{
	std::cout << toString() << std::endl;
//	for (int i=0; i<table->seats.size(); i++) {
//		std::cout << ((LYHoldemSeat *)table->seats[i].get())->toString() << std::endl;
//	}
}

std::string LYHoldemGame::toString()
{
    std::string str;
    std::string cards;
    LYCardHelpers::cardsToStringifiedInt(flopCards, cards);
    str = "{";
    str =   str + "\"_id\":\"" + _id + "\"," +
			"\"gameStatus\":" + std::to_string(gameStatus) + "," +
    		"\"roundOfTournament\":" + std::to_string(roundOfTournament) + "," +
    		"\"btnSeatNo\":" + std::to_string(btnSeatNo) + "," +
    		"\"sbSeatNo\":" + std::to_string(sbSeatNo) + "," +
    		"\"bbSeatNo\":" + std::to_string(bbSeatNo) + "," +
    		"\"flopCards\":\"" + cards + "\"," +
    		"\"turnCard\":" + std::to_string(turnCard.toInteger()) + "," +
    		"\"riverCard\":" + std::to_string(riverCard.toInteger()) + "," +
    		"\"smallBlindPrice\":" + std::to_string(smallBlindPrice) + "," +
    		"\"bigBlindPrice\":" + std::to_string(bigBlindPrice) + "," +
    		"\"seqNo\":" + std::to_string(seqNo) + "," +
    		"\"round\":" + std::to_string(round) + "," +
    		"\"dutySeatNo\":" + std::to_string(dutySeatNo) + "," +
    		"\"betIfCall\":" + std::to_string(betIfCall) + "," +
    		"\"minBetIfRaise\":" + std::to_string(minBetIfRaise) + "," +
    		"\"betBySeatNo\":" + std::to_string(betBySeatNo) + "," +
    		"\"continueThisRound\":" + std::to_string(continueThisRound) + "," +
    		"\"assureActionNumbers\":" + std::to_string(assureActionNumbers) + "," +
    		"\"lastPollingAt\":" + std::to_string(lastPollingAt) + "," +
    		"\"lastPollingAction\":{" + lastPollingAction.toString() + "}"
    		;

	str = str + ",\"seats\":[";
	int s = 0;
	for (int i=0; i<table->seats.size(); i++) {
		if (((LYHoldemSeat *)table->seats[i].get())->status == LYSeatOpen) continue;
		s++;
		str = str + "{" +((LYHoldemSeat *)table->seats[i].get())->toString() + "},";
	}
	if (s > 0) str = str.substr(0, str.size()-1);
	str = str + "]";

	str = str + "}";
    return str;
}

/*
 * sortSeats: sort all seats according to small_blind, big_blind, ..., button
 */
void LYHoldemGame::sortSeatsWithoutChangeStatus()
{
//std::cout << "enter sortSeats" << std::endl;
	cleanZombies();

	this->sortedSeats.clear();
	if (::LYHouse == this->sbSeatNo || ::LYHouse == this->btnSeatNo || ::LYHouse == this->bbSeatNo || this->seatsOfTable.size() < 2) return;
//	debugGame();

    LYSeatPtr seat = this->smallBlindSeat();
    int i = 0;
    if (table->occupied_seat_number == 2) seat = this->bigBlindSeat();
	while (seat->seatNo != this->btnSeatNo && i < 9) {
//std::cout << "seat no:" << seat->seatNo << ", status:" << seat->status << std::endl;
		i++;
		if (seat->status != LYSeatOpen) {
			sortedSeats.push_back(seat);
		}
		seat = table->fetchNextOccupiedSeat(seat->seatNo);
		if (NULL == seat.get()) {
//			LY_LOG_ERR("something weired happend!");
			return;
		}
	}
	if (sortedSeats.size() < 1) {
		//means no seats or only one seat occupied here!
		this->reset();
		return;
	}
    sortedSeats.push_back(this->buttonSeat());
}

/*
 * sortSeatsInGame: Client calls sortSeatsInGame when get scene
 */
void LYHoldemGame::sortSeatsInGame()
{
	this->sortedSeats.clear();
	if (::LYHouse == this->sbSeatNo || ::LYHouse == this->btnSeatNo || ::LYHouse == this->bbSeatNo || this->seatsOfTable.size() < 2) return;

    LYSeatPtr seat = this->smallBlindSeat();
    int i = 0;
    if (table->occupied_seat_number == 2) seat = this->bigBlindSeat();
	while (seat->seatNo != this->btnSeatNo && i < 9) {
		i++;
		if (seat->status == LYSeatInGame) {
			sortedSeats.push_back(seat);
		}
		seat = table->fetchNextOccupiedSeat(seat->seatNo);
		if (NULL == seat.get()) {
			return;
		}
	}
	if (sortedSeats.size() < 1) {
		//means no seats or only one seat occupied here!
		return;
	}
    sortedSeats.push_back(this->buttonSeat());
}

void LYHoldemGame::cleanZombies()
{
	std::vector<LYSeatPtr>::iterator it = seatsOfTable.begin();
	for (; it!=seatsOfTable.end(); it++) {
		LYSeatPtr seat = *it;
		if (seat.get() == NULL) {
			continue;
		}
		if (seat->playerId == "NULL" || seat->playerId == "") {
			seat->reset();
		}
	}
}

/*
 * 判断Action是否有效
 * 根据不同的Action调用不同的函数处理 onCall/onFold/...
 * 成功后再生成Scene
 */
bool LYHoldemGame::onAction(LYHoldemAction &action)
{
//	LY_LOG_DBG("duty_seat=" << this->dutySeatNo);
	if (!isValidAction(action)) {
//		LY_LOG_ERR("invalid action" << action.toString());
		return false;
	}
	LYSeatPtr seat = table->fetchSeat(action.applicant);
	if (action.applicant > 0 && action.applicant < 9) {
		if (seat->status == LYSeatOpen ||
			((LYHoldemSeat *)seat.get())->gameStatus == LYSeatHoldemInFold) {
			return false;
		}
	}
	if (action.verb == LYHousePollingDecision) {
		lastPollingAction = action;
		lastPollingAt = time(NULL);
		this->onPolling(seat);
		return true;
	}
	switch (action.verb)
	{
	case LYCall:
		this->onCall(seat, action.bet);
		break;
	case LYBet:
		this->onBet(seat, action.bet);
		break;
	case LYBetSmallBlind:
		this->onBetSmallBlind(seat, action.bet);
		break;
	case LYBetBigBlind:
		this->onBetBigBlind(seat, action.bet);
		break;
	case LYRaise:
		this->onRaise(seat, action.bet);
		break;
	case LYCheck:
		this->onCheck(seat);
		break;
	case LYFold:
		this->onFold(seat, action.desc);
		break;
	case LYAllin:
		this->onAllin(seat, action.bet);
		break;
	case LYHouseIssueFlop:
		this->onFlop(action.cards);
		break;
	case LYHouseIssueTurn:
		this->onTurn(action.cards.front());
		break;
	case LYHouseIssueRiver:
		this->onRiver(action.cards.front());
		break;
	case LYAskAssurance: //对Game状态无影响
	case LYSummarizeAssurance: //对Game状态无影响
	case LYPayAssurance: //客户端收到PaidAssurance，不在Game里处理，只是View视图处理即可
		return true;
	case LYBuyAssurance: //服务器收到玩家的
	{
//	LY_LOG_DBG("on assurance");
		this->onAssure(round, seat, action.bet, action.desc);
		this->genNewScene();
		return true;
	}
		break;
	default:
//		LY_LOG_ERR("invalid action" << action.toString());
		return false;
	}

	this->updateHoldemRound(action);
	this->genNewScene();
	this->appendLog(action.toString());

	return true;
}

void LYHoldemGame::genNewScene()
{
	LYHoldemScene *nc = new LYHoldemScene(sortedSeats, this->pots(), this->dutySeatNo,
			this->betIfCall, this->betIfCall*2, this->betBySeatNo,
			this->round, this->continueThisRound,
			seqNo++);
	LYHoldemScenePtr scene(nc);
//	LY_LOG_DBG("after this action, scene = \n" << nc->toString());
	scenes.push_back(scene);
}

void LYHoldemGame::onFlop(const std::vector<LYCard> &cards)
{
//	LY_LOG_DBG("enter onFlop");
	if (cards.size() < 3) {
//		LY_LOG_ERR("cards size should be greater than 3");
		return;
	}
    this->flopCards = cards;
    while (this->flopCards.size() > 3) {
    	this->flopCards.pop_back();
    }
    this->round = LYGameFlop;
    this->newRound();
}

void LYHoldemGame::onTurn(const LYCard &card)
{
    this->turnCard = card;
    this->round = LYGameTurn;
    this->newRound();
    this->checkAssurance(card);
}

void LYHoldemGame::onRiver(const LYCard &card)
{
    this->riverCard = card;
    this->round = LYGameRiver;
    this->newRound();
    this->checkAssurance(card);
}

void LYHoldemGame::onCall(LYSeatPtr st, unsigned int bet)
{
	if (st.get() == NULL) return;
    LYHoldemSeat *seat = (LYHoldemSeat *)st.get();
    if (bet > this->betIfCall ||
    		(bet < this->betIfCall && bet < (seat->chipsAtHand+seat->lastBet)))
    { //既不相等，也没有Allin，那就认为出错了！
//    	LY_LOG_INF("on onCall bet error "<< bet);
    	return;
    }

    pm.betBySeat(bet, st);
    if (seat->chipsAtHand > 0) {
    	seat->gameStatus = LYSeatHoldemInCalled;
    } else {
    	seat->gameStatus = LYSeatHoldemInAllin;
    }
	seat->timeoutCount = 0;
    return;
}

void LYHoldemGame::onRaise(LYSeatPtr st, unsigned int bet)
{
	if (st.get() == NULL) return;
//    LY_LOG_INF("on raise");
    //verify action.bet > betIfCall * 2
    LYHoldemSeat *seat = (LYHoldemSeat *)st.get();
//std::cout << "kkkkk, bet=" << bet << std::endl;
    if (bet < this->minBetIfRaise) {
        if (bet < (seat->chipsAtHand+seat->lastBet)) { //既没有2倍，也没有Allin，那就认为出错了！
//            LY_LOG_INF("on raise bet error "<< bet);
            return;
        }
    }

    this->betIfCall = bet;
    //added by chenfeng 20130524
    this->minBetIfRaise = bet * 2;
    this->betBySeatNo = st->seatNo;
//std::cout << "minBetIfRase:" << minBetIfRaise << ", betIfCall:" << betIfCall<< std::endl;

    pm.betBySeat(bet, st);
    if (seat->chipsAtHand > 0) {
    	seat->gameStatus = LYSeatHoldemInRaised;
    } else {
    	seat->gameStatus = LYSeatHoldemInAllin;
    }
	seat->timeoutCount = 0;
    return;
}

void LYHoldemGame::onBet(LYSeatPtr st, unsigned int bet)
{
	if (st.get() == NULL) return;
	this->onRaise(st, bet);
    LYHoldemSeat *seat = (LYHoldemSeat *)st.get();
	if (seat->gameStatus != LYSeatHoldemInAllin) {
		seat->gameStatus = LYSeatHoldemInBet;
	}
	seat->timeoutCount = 0;
}

void LYHoldemGame::onBetSmallBlind(LYSeatPtr st, unsigned int bet)
{
	if (st.get() == NULL) return;
	unsigned int tc = st->timeoutCount;
	this->onRaise(st, bet);
    LYHoldemSeat *seat = (LYHoldemSeat *)st.get();
	if (seat->gameStatus != LYSeatHoldemInAllin) {
		seat->gameStatus = LYSeatHoldemBetSmall;
	}
	seat->timeoutCount = tc;
}

void LYHoldemGame::onBetBigBlind(LYSeatPtr st, unsigned int bet)
{
	if (st.get() == NULL) return;
	unsigned int tc = st->timeoutCount;
	this->onRaise(st, bet);
    LYHoldemSeat *seat = (LYHoldemSeat *)st.get();
	if (seat->gameStatus != LYSeatHoldemInAllin) {
		seat->gameStatus = LYSeatHoldemBetBig;
	}
	seat->timeoutCount = tc;
}

void LYHoldemGame::onAllin(LYSeatPtr st, unsigned int bet)
{
	if (st.get() == NULL) return;
    LYHoldemSeat *seat = (LYHoldemSeat *)st.get();
	seat->gameStatus = LYSeatHoldemInAllin;
    unsigned int toBet = (bet>0)?bet:(st->chipsAtHand+st->lastBet);
    pm.betBySeat(toBet, st);
    pm.topPot()->priceFixed = true;
    if (toBet > this->betIfCall) {
        this->betIfCall = toBet;
        //added by chenfeng 20130524
        this->minBetIfRaise = toBet * 2;
        this->betBySeatNo = st->seatNo;
    }
	seat->timeoutCount = 0;
    return;
}

/*
 * 20140113 fold时，将Pot的involvedSeats去掉
 */
void LYHoldemGame::onFold(LYSeatPtr st, const std::string &reason)
{
	if (st.get() == NULL) return;
//	LY_LOG_DBG("folded reason " << reason);
    LYHoldemSeat *seat = (LYHoldemSeat *)st.get();
	seat->gameStatus = LYSeatHoldemInFold;
	pm.fold(st->seatNo);
	seat->fold(reason);
}

void LYHoldemGame::onCheck(LYSeatPtr st)
{
	if (st.get() == NULL) return;
    LYHoldemSeat *seat = (LYHoldemSeat *)st.get();
	seat->gameStatus = LYSeatHoldemInChecked;
	seat->timeoutCount = 0;
}

void LYHoldemGame::onPolling(LYSeatPtr st)
{
	if (st.get() == NULL) return;
    LYHoldemSeat *seat = (LYHoldemSeat *)st.get();
	seat->gameStatus = LYSeatHoldemMakingDecision;
}

void LYHoldemGame::onAssure(unsigned int assurance_round, LYSeatPtr st, unsigned int assurance, const std::string& pot)
{
	if (st.get() == NULL) return;
//std::cout << "onAssure:" << assureActionNumbers << std::endl;
	if (assureActionNumbers == 0) return;
    LYHoldemSeat *seat = (LYHoldemSeat *)st.get();
    pm.buyAssurance(assurance_round, st, assurance, pot);
	assureActionNumbers--;
//std::cout << "leaving onAssure:" << assureActionNumbers << std::endl;
}

/*
 * 最复杂的方法之一，根据当前Action和状态机，更新continueThisRound
 * 而continueThisRound被用于后续决定是否发Polling还是NextRound等
 * HoldemRoundDown: 接下来Turn、River等发牌动作都要进行，并在最后决出胜负
 * HoldemRoundEnd：如果只余下一个玩家，宣布比赛结束
 * 游戏结束时根据round和continueThisRound决定是否Show赢家的牌
 */
void LYHoldemGame::updateHoldemRound(LYHoldemAction &action)
{
//	if (continueThisRound == LYHoldemRoundDown || continueThisRound == LYHoldemRoundEnd) {
//		return;
//	}
	if (continueThisRound != LYHoldemRoundDown)
		continueThisRound = LYHoldemRoundCont;
	switch (action.verb) {
	case LYHouseIssueFirstCard:
	case LYHouseIssueSecondCard:
//	case LYHouseIssueFlop:
//	case LYHouseIssueTurn:
//	case LYHouseIssueRiver:
		return; //do nothing
	default:
		break;
	}
	unsigned int seated = 0;
	unsigned int allinSeats = 0;
	LYSeatPtr waitingSeat = LYSeatPtr();
	std::vector<LYSeatPtr>::iterator it = sortedSeats.begin();
	for (; it!=sortedSeats.end(); it++)
	{
		LYSeatPtr st = *it;
		LYHoldemSeat *seat = (LYHoldemSeat *)st.get();
		if (seat->status == LYSeatOpen) continue;

		switch (seat->gameStatus) {
		case LYSeatHoldemWaiting:
		case LYSeatHoldemBetSmall:
		case LYSeatHoldemBetBig:
		case LYSeatHoldemMakingDecision:
		case LYSeatHoldemInCalled:
		case LYSeatHoldemInChecked:
		case LYSeatHoldemInRaised:
		case LYSeatHoldemInBet:
			if (seat->chipsAtHand == 0) {
				allinSeats++;
				seat->gameStatus = LYSeatHoldemInAllin;
			} else {
				seated++;
				waitingSeat = st;
			}
			break;
		case LYSeatHoldemInAllin:
			allinSeats++;
			break;
		default:
			break;
		}
	}
	if (seated == 1) {
//		LY_LOG_DBG("allinSeats=" << allinSeats << ", seated=" << seated << ", betIfCall=" << this->betIfCall << ", waitingSeat->lastBet=" << waitingSeat->lastBet);
	} else {
//		LY_LOG_DBG("allinSeats=" << allinSeats << ", seated=" << seated << ", betIfCall=" << this->betIfCall );
	}
	/*
	 * 如果没有任何座位在游戏状态，即所有座位都Fold或者Allin，则直接进入到HoldemRoundDown状态
	 */
	if (0 == seated) {
		if (allinSeats < 2) {
			continueThisRound = LYHoldemRoundEnd;
			return;
		}
		continueThisRound = LYHoldemRoundDown;
		return ;
	}
	if (1 == seated) {
		/*
		 * 如果仅有一个座位在游戏状态，而且Allinseats = 0说明，只有一个玩家
		 */
		if (0 == allinSeats) {
			continueThisRound = LYHoldemRoundEnd;
			return ;
		}
		/*
		 * 如果仅有一个座位在游戏状态，其它所有座位都Fold或者Allin，则直接进入到HoldemRoundDown状态
		 */
		if (this->betIfCall <= waitingSeat->lastBet) {
			//说明未Allin的Seat已经做出大于当前最大注的决定，因此无需再做决定
			((LYHoldemSeat *)waitingSeat.get())->gameStatus = LYSeatHoldemInAllin;
			continueThisRound = LYHoldemRoundDown;
			return ;
		}
		/*
		 * 其它情况AllinSeats>0，并且当前注大于未Allin座位的上次出注，因此该座位还有出注机会
		 * 但需要判断一种情况，就是大盲已经出注Allin且其筹码小于小盲
		 */
		if (round == LYGameInit && waitingSeat->seatNo == sbSeatNo
				&& bigBlindSeat()->chipsAtHand == 0 && bigBlindSeat()->lastBet < smallBlindPrice) {
			continueThisRound = LYHoldemRoundDown;
			return ;
		}
		continueThisRound = LYHoldemRoundCont;
		return ;
	}

	if (round == LYGameInit) { //说明是大小盲下注，检查完Seats之后即返回，不判断Action
		return;
	}

	/*
	 * 以下根据Action进行判断
	 */
	if (action.applicant == LYHouse) {
		if (continueThisRound != LYHoldemRoundDown)
			continueThisRound = LYHoldemRoundCont;
		return;
	}

	LYSeatPtr nextSeatInGame = table->fetchNextSeatInGame(action.applicant);
	LYSeatPtr firstSeatInGame = this->fetchFirstSeatInGame();
	if (nextSeatInGame.get() == NULL || firstSeatInGame.get() == NULL) {
		return;
	}
	if (action.bet == 0 && action.verb != LYFold) {
		if (firstSeatInGame->seatNo == nextSeatInGame->seatNo) {
			continueThisRound = LYHoldemRoundNext;
			return ;
		}
		continueThisRound = LYHoldemRoundCont;
		return ;
	}

	if (this->round == LYGamePreflop) {
		if (nextSeatInGame->seatNo == this->bbSeatNo) {
			if (action.bet == this->bigBlindPrice) {
				continueThisRound = LYHoldemRoundCont;
				return;
			}
		}
	}

	if (nextSeatInGame->lastBet > 0
			&& nextSeatInGame->lastBet == action.bet) {
		continueThisRound = LYHoldemRoundNext;
		return ;
	}

	if (continueThisRound != LYHoldemRoundDown)
		continueThisRound = LYHoldemRoundCont;
	return ;
}

/*
 * 在一个桌子已经开始的情况下，Dealer检验Action是否合法
 * 先设DutySeat，然后执行onAction
 *
 */
bool LYHoldemGame::isValidAction(LYHoldemAction &action)
{
	//20130713注：Fold可能来自于LeaveSeat导致的离席Fold
	if (round == LYGameInit &&
			(action.verb == LYBetSmallBlind || action.verb == LYBetBigBlind)) {
		return true;
	}
	if (action.verb == LYFold ){ //&& action.desc == "byleave") {
		//20160701 在任何位置都可以fold
		//20160730 但不可以对已经allin的位置再fold
		if (this->round == LYGameClosed || this->round == LYGameInit) return false;
		LYSeatPtr seat = table->fetchSeat(action.applicant);
		LYHoldemSeat *holdemSeat = (LYHoldemSeat *)seat.get();
		if (holdemSeat != NULL && holdemSeat->gameStatus == LYSeatHoldemInAllin) return false;

		return true;
	}
	if (::LYHouse == dutySeatNo) { //check down（所有玩家allin）的情况下，
		return true;
	}
	if (action.verb == LYSummarizeAssurance) {
		return true; //任何时候都允许获取保险统计
	}
	if (action.applicant != LYHouse && dutySeatNo != action.applicant) {
//	std::cout << "duty:" << dutySeatNo << ", action="<< action.toString() << std::endl;
		if (action.isAssuranceRelevant()) {
			return true;
		}
		return false;
	}
	if (action.applicant == LYHouse) {
		switch (this->round)
		{
		case LYGamePreflop: //发完第二张牌
			if (action.verb == LYHouseIssueFlop) {
				return true;
			}
			return false;
		case LYGameFlop: //发完Flop
			if (action.verb == LYHouseIssueTurn) {
				return true;
			}
			return false;
		case LYGameTurn: //发完Turn
			if (action.verb == LYHouseIssueRiver) {
				return true;
			}
			return false;

		case LYGameRiver: //发完River
			return false;

		default:
			return false;
		}
	}
	//到此,duty != NULL, duty.seatNo == action.applicant
	LYSeatPtr seat = table->fetchSeat(action.applicant);
	LYHoldemSeat *holdemSeat = (LYHoldemSeat *)seat.get();
	if (action.verb != LYHousePollingDecision &&
			action.verb != LYBuyAssurance && //added 20160321 for assurance
			holdemSeat->gameStatus != LYSeatHoldemMakingDecision) {
//		LY_LOG_ERR("invalid action");
		return false;
	}

	if (action.verb == LYBetSmallBlind || action.verb == LYBetBigBlind) {
		if (round != LYGameInit) {
			return false;
		}
		return true;
	}
	switch (this->round)
	{
	case LYGameWaiting: //跟这个Dealer和桌子相关的，下一个动作应该只允许新游戏开始，或者在上面就返回了
	case LYGameInit: //新游戏开始
	case LYGameClosed:
		return false;

	case LYGamePreflop: //发完第二张牌
		switch (action.verb)
		{
		case LYHouseIssueFlop: //发Flop
		case LYHousePollingDecision: //询问下一个做决定
			return true;
		case LYBet: //下一个做的决定
		case LYRaise: //下一个做的决定
			if (action.bet < this->minBetIfRaise) return false;
			return true;
		case LYCall: //下一个做的决定
			if (action.bet < this->betIfCall) return false;
			return true;
		case LYFold: //下一个做的决定
		case LYAllin: //下一个做的决定
//		case LYBuyAssurance:
		case LYAskAssurance:
//		case LYPayAssurance:
			return true;
		case LYCheck: //下一个做的决定
			if (0 == this->betIfCall || seat->lastBet == this->betIfCall) return true;
			return false;

		default:
			return false;
		}
		break;

	case LYGameFlop: //发完Flop
		switch (action.verb)
		{
		case LYHouseIssueTurn: //发Turn
		case LYHousePollingDecision: //询问下一个做决定
			return true;
		case LYBet: //下一个做的决定
		case LYRaise: //下一个做的决定
			if (action.bet < this->minBetIfRaise) return false;
			return true;
		case LYCall: //下一个做的决定
			if (action.bet < this->betIfCall) return false;
			return true;
		case LYFold: //下一个做的决定
		case LYAllin: //下一个做的决定
		case LYBuyAssurance:
		case LYAskAssurance:
//		case LYPayAssurance:
			return true;
		case LYCheck: //下一个做的决定
			if (0 == this->betIfCall || seat->lastBet == this->betIfCall) return true;
			return false;

		default:
			return false;
		}
		break;

	case LYGameTurn: //发完Turn
		switch (action.verb)
		{
		case LYHouseIssueRiver: //发Turn
		case LYHousePollingDecision: //询问下一个做决定
			return true;
		case LYBet: //下一个做的决定
		case LYRaise: //下一个做的决定
			if (action.bet < this->minBetIfRaise) return false;
			return true;
		case LYCall: //下一个做的决定
			if (action.bet < this->betIfCall) return false;
			return true;
		case LYFold: //下一个做的决定
		case LYAllin: //下一个做的决定
		case LYBuyAssurance:
		case LYAskAssurance:
		case LYPayAssurance:
			return true;
		case LYCheck: //下一个做的决定
			if (0 == this->betIfCall || seat->lastBet == this->betIfCall) return true;
			return false;

		default:
			return false;
		}
		break;

	case LYGameRiver: //发完River
		switch (action.verb)
		{
		case LYHousePollingDecision: //询问下一个做决定
			return true;
		case LYBet: //下一个做的决定
		case LYRaise: //下一个做的决定
			if (action.bet < this->minBetIfRaise) return false;
			return true;
		case LYCall: //下一个做的决定
			if (action.bet < this->betIfCall) return false;
			return true;
		case LYFold: //下一个做的决定
		case LYAllin: //下一个做的决定
		case LYPayAssurance:
			return true;
		case LYCheck: //下一个做的决定
			if (0 == this->betIfCall || seat->lastBet == this->betIfCall) return true;
			return false;

		default:
			return false;
		}
		break;

	default:
		break;
	}
	return false;
}

LYSeatPtr LYHoldemGame::fetchFirstSeatInGame()
{
	if (round == LYGameInit) {
		return this->smallBlindSeat();
	}
	if (round == LYGamePreflop) {
		return this->fetchNextSeatInGame(this->bbSeatNo);
	}
	return this->fetchNextSeatInGame(this->btnSeatNo);
}

LYSeatPtr LYHoldemGame::fetchNextSeatInGame(LYApplicant seat_no)
{
	if ((unsigned int)seat_no < 1 || (unsigned int)seat_no > 9) {
//		LY_LOG_ERR("fetchNextSeatInGame::seat_no must be between 1..9, " << (unsigned int)seat_no);
		return LYSeatPtr();
	}
	std::vector<LYSeatPtr>::iterator it = sortedSeats.begin();
	LYSeatPtr right_hand;
	LYSeatPtr left_hand;
	bool checking_right = true;
	for (; it!=sortedSeats.end(); it++) {
		LYSeatPtr cur = *it;
		if (cur->seatNo == seat_no) {
			checking_right = false;
			continue;
		}
		LYHoldemSeat *seat = (LYHoldemSeat *)((*it).get());
		if (checking_right && NULL == right_hand.get() && seat->isInGame()) {
			right_hand = *it;
		}
		if (!checking_right && NULL == left_hand.get() && seat->isInGame()) {
			left_hand = *it;
			return left_hand;
		}
	}
	return right_hand;
}

LYSeatPtr LYHoldemGame::fetchNextSeatInGameAndNotAllin(LYApplicant seat_no)
{
	if ((unsigned int)seat_no < 1 || (unsigned int)seat_no > 9) {
//		LY_LOG_ERR("fetchNextSeatInGameAndNotAllin::seat_no must be between 1..9, " << (unsigned int)seat_no);
		return LYSeatPtr();
	}
	std::vector<LYSeatPtr>::iterator it = sortedSeats.begin();
	LYSeatPtr right_hand;
	LYSeatPtr left_hand;
	bool checking_right = true;
	for (; it!=sortedSeats.end(); it++) {
		LYSeatPtr cur = *it;
		if (cur->seatNo == seat_no) {
			checking_right = false;
			continue;
		}
		LYHoldemSeat *seat = (LYHoldemSeat *)((*it).get());
		if (checking_right && NULL == right_hand.get() && seat->isInGameAndNotAllin()) {
			right_hand = *it;
		}
		if (!checking_right && NULL == left_hand.get() && seat->isInGameAndNotAllin()) {
			left_hand = *it;
			return left_hand;
		}
	}
	return right_hand;
}

/*
 * gen community card actions
 * flop
 * turn
 * river
 * called by startGame()
 */
void LYHoldemGame::genCommunityCardActions()
{
	this->deck.pop();
	std::vector<LYCard> cards;
	cards.push_back(this->deck.pop());
	cards.push_back(this->deck.pop());
	cards.push_back(this->deck.pop());
	flop_action.issueFlopCards(cards);
	flop_action.table_id = this->table->_id;

	this->deck.pop();
	LYCard cd = deck.pop();
	turn_action.issueTurnCard(cd);
	turn_action.table_id = this->table->_id;

	this->deck.pop(); cd = deck.pop();
	river_action.issueRiverCard(cd);
	river_action.table_id = this->table->_id;
}

/*
 * gen community card actions
 * flop
 * turn
 * river
 * called by startGame()
 */
void LYHoldemGame::reverseCommunityCardActions()
{
	flop_action.issueFlopCards(flopCards);
	flop_action.table_id = this->table->_id;

	turn_action.issueTurnCard(turnCard);
	turn_action.table_id = this->table->_id;

	river_action.issueRiverCard(riverCard);
	river_action.table_id = this->table->_id;
}

/*
 * 当continueThisRound == LYSeatHoldemRoundEnd时，调用本方法
 * 负责分出胜负
 * 20160329 added 要对保险进行计算
 */
void LYHoldemGame::gameOver()
{
	std::vector<LYPotPtr> allPots = this->pots();
	std::vector<LYPotPtr>::iterator it = allPots.begin();

	if (totalSeatsInGame() == 1) { //所有人都弃牌，只留下一个玩家时，他获得所有pot
		LYSeatPtr seat = findLastSeatInGame();
		if (seat.get() == NULL) {
			LY_LOG_ERR("weired, should not get over here!");
			return;
		}
    	for (; it!=allPots.end(); it++) {
    		LYPotPtr pot = *it;
    		seat->chipsAtHand += pot->chipsInPot;
    		pot->winnersInPot.clear();
    		pot->winnersInPot.push_back(seat->seatNo);
		}
	} else {
		std::vector<LYCard> communityCards = this->getCommunityCards();

    	for (; it!=allPots.end(); it++) {
    		LYPotPtr pot = *it;
    		pot->caculateMatchResult(this);
		}
	}
	this->round = LYGameClosed;
	this->genNewScene();
	this->appendLog(this->toString());
}

void LYHoldemGame::caculateAssuranceResult(LYAssurance *assure)
{
//std::cout << assure->toString() << std::endl;
//std::cout << "assure result:" << assure->result << std::endl;
	LYSeatPtr seat = fetchSeat((LYApplicant)assure->seat);
	if (assure->result > 0) { //击中保险，赔付
		seat->chipsAtHand += assure->result;
		table->assurance_income -= assure->result;
		assurance_summary_action.bet -= assure->result;
	} else {
		seat->chipsAtHand -= assure->assurance;
		table->assurance_income += assure->assurance;
		assurance_summary_action.bet += assure->assurance;
	}
}

/*
 * 20160320 added for refactoring
 */
std::vector<LYCard> LYHoldemGame::getCommunityCards()
{
	std::vector<LYCard> communityCards = this->flopCards;
//	LY_LOG_DBG("game round" << this->round);
	switch (this->round) {
	case LYGameRiver:
		communityCards.push_back(this->riverCard);
	case LYGameTurn:
		communityCards.push_back(this->turnCard);
		break;
	default:
		break;
	}

	return communityCards;
}

void LYHoldemGame::makePaidAssurances(std::vector<LYHoldemAction>& actions, const LYCard& card)
{
	std::vector<LYPotPtr>& allPots = pots();
	std::vector<LYPotPtr>::iterator it = allPots.begin();
	std::vector<LYHoldemAction> assures;
	//首先生成之前的保险结果
	for (; it!=allPots.end(); it++) {
    	LYPotPtr pot = *it;
    	if (card == flipCard) continue;
    	pot->makePaidAssuranceActions(this, card, assures);
    }
	actions.insert(actions.end(), assures.begin(), assures.end());
}

/*
 * 20160323 generate assurance actions
 * 20160710 只返回第一条买保险的请求，当来了买保险的动作时，再
 */
void LYHoldemGame::genAssureActions(std::vector<LYHoldemAction>& actions,
					const LYCard card, bool nomoreAssure)
{
//LY_LOG_DBG("card =" );
	std::vector<LYPotPtr>& allPots = pots();
	std::vector<LYPotPtr>::iterator it = allPots.begin();
	std::vector<LYHoldemAction> assures;
	//其次生成新的保险请求
	for (it=allPots.begin(); it!=allPots.end(); it++) {
		LYPotPtr pot = *it;
		pot->makeAskAssuranceActions(this, assures);
	}
	assureActionNumbers = assures.size();
//LY_LOG_DBG("generated assure actions:" << assureActionNumbers);
//	actions.insert(actions.end(), assures.begin(), assures.end());
	if (assureActionNumbers > 0) {
		actions.push_back(this->popAssureAction());
		//只保留最后一个询问保险的请求，如果一局中有多个玩家触发买保险的动作，在重入时只能看到最后一个
		//mark by cqf 20160630
		lastPollingAction = assures[assureActionNumbers-1];
		lastPollingAt = time(NULL);
	}
}

void LYHoldemGame::dutyMoveToNextSeat()
{
//	LY_LOG_DBG("before duty=" << dutySeatNo << ", sortedSeats=" << sortedSeats.size());
//	std::cout << "before duty=" << dutySeatNo << ", sortedSeats=" << sortedSeats.size() << std::endl;
    if (LYHouse == dutySeatNo) return;
    unsigned int i = 0;
    while (i<sortedSeats.size()) {
    	i++;
    	LYSeatPtr seat = this->fetchNextSeatInGame(dutySeatNo);
    	if (NULL == seat.get()) {
    		//just one seat left in game
    		return;
    	}
        dutySeatNo = seat->seatNo;
//    	LY_LOG_DBG("looping i=" << i << ", duty="<< dutySeatNo);
        LYHoldemSeat *holdemSeat = (LYHoldemSeat *)dutySeat().get();
        if (holdemSeat->isInGameAndNotAllin()){
            break;
        }
    }
//	LY_LOG_DBG("after duty=" << dutySeatNo);
}

void LYHoldemGame::newRound()
{
	std::vector<LYSeatPtr>::iterator it = sortedSeats.begin();
	for (; it!=sortedSeats.end(); it++) {
		LYHoldemSeat *seat = (LYHoldemSeat *)(*it).get();
		if (seat->status != LYSeatOpen ) {
			switch (seat->gameStatus)
			{
			case LYSeatHoldemWaiting:
			case LYSeatHoldemInBet:
			case LYSeatHoldemInCalled:
			case LYSeatHoldemInChecked:
			case LYSeatHoldemInRaised:
				seat->gameStatus = LYSeatHoldemWaiting;
				break;
			default:
				//do nothing
				break;
			}
		}
	}
    if (continueThisRound != LYHoldemRoundEnd && continueThisRound != LYHoldemRoundDown) {
    	continueThisRound = LYHoldemRoundCont;
    }

    if (round == LYGamePreflop) {
        dutySeatNo = this->fetchNextSeatInGameAndNotAllin(bbSeatNo)->seatNo;
        betIfCall = this->bigBlindPrice;
        minBetIfRaise = 2*this->bigBlindPrice;
        betBySeatNo = bbSeatNo;
        return;
    }
    LYSeatPtr ds = this->fetchNextSeatInGameAndNotAllin(btnSeatNo);
    dutySeatNo = LYHouse;
    if (NULL != ds.get()) {
    	dutySeatNo = ds->seatNo;
    }
    betIfCall = 0;
    minBetIfRaise = bigBlindPrice;
    betBySeatNo = LYHouse;

    lastPollingAt = 0;
    lastPollingAction.reset();
    assureActionNumbers = 0;
	assureActions.clear();

    pm.newRound();
}

LYSeatPtr LYHoldemGame::buttonSeat()
{
	return table->fetchSeat(this->btnSeatNo);
}
LYSeatPtr LYHoldemGame::smallBlindSeat()
{
	return table->fetchSeat(this->sbSeatNo);
}
LYSeatPtr LYHoldemGame::bigBlindSeat()
{
	return table->fetchSeat(this->bbSeatNo);
}
LYSeatPtr LYHoldemGame::dutySeat()
{
	return table->fetchSeat(this->dutySeatNo);
}
LYSeatPtr LYHoldemGame::betBy()
{
	return table->fetchSeat(this->betBySeatNo);
}

/*
 * added 20130605
 */
std::string LYHoldemGame::getHandCardFace(enum LYApplicant player)
{
	if ((unsigned int)player < 1 || (unsigned int)player > 9) {
//		LY_LOG_ERR("getHandCardFace::seat_no must be between 1..9, " << (unsigned int)player);
		return "00";
	}
	LYSeatPtr st = this->fetchSeat(player);
	std::string faces = "00";
	if (st->handCards.size() != 2) {
		return faces;
	}
    if (st->handCards[0].isFlipCard() ||
        st->handCards[1].isFlipCard()) {
        return faces;
    }
    if (st->handCards[0] > st->handCards[1]) {
    	faces[0] = st->handCards[0].getFaceSymbol();
    	faces[1] = st->handCards[1].getFaceSymbol();
    } else {
    	faces[0] = st->handCards[1].getFaceSymbol();
    	faces[1] = st->handCards[0].getFaceSymbol();
    }
    return faces;
}

bool LYHoldemGame::isHandCardFlush(enum LYApplicant player)
{
    LYSeatPtr st = this->fetchSeat(player);
	if (NULL == st.get() || st->handCards.size() != 2) {
		return false;
	}
    if (st->handCards[0].isFlipCard() ||
        st->handCards[1].isFlipCard()) {
        return false;
    }
    if (st->handCards[0].suit == st->handCards[1].suit) {
        return true;
    } else {
        return false;
    }
}

/*
 * added 20130605
 */
enum LYHandsOrder LYHoldemGame::judgeHand(enum LYApplicant player)
{
	if (this->round != LYGameFlop && this->round != LYGameTurn && this->round != LYGameRiver) {
		return LYON_DRAW;
	}
	LYSeatPtr st = this->fetchSeat(player);
	if (NULL == st.get() || st->handCards.size() != 2) {
		return LYON_DRAW;
	}
	LYHandStrengthPtr hs = LYHandStrengthPtr(this->getHandStrength(player));
	enum LYHandsOrder community = this->judgeCommunity();
	switch (hs->ranking)
	{
	case OnePair:
	case HighCard:
	case TwoPair:
		return LYON_DRAW;
	case ThreeOfAKind:
		if (st->handCards[0].face != hs->topRankCard.face) {
			if (st->handCards[1].face != hs->topRankCard.face) {
				//set for community, everyone has a set
				return LYSECOND_NUTS;
			}
			//community has a pair and it hits a set
			return LYSECOND_NUTS;
		}
		if (st->handCards[1].face != hs->topRankCard.face) {
			//set for community, everyone has a set
			return LYSECOND_NUTS;
		}
		//player has a pair and hits a set
		switch (community)
		{
		case LYFOUROFAKIND_ODDS:
		case LYFULLHOUSE_ODDS:
		case LYFLUSH_ODDS:
		case LYOUTSIDE_ODDS:
		case LYGUTSHOT_ODDS:
			return LYSECOND_NUTS;
		default:
			return LYNUTS;
		}
		return LYNUTS;
	default:
		break;
	}
    return LYON_DRAW;
}

/*
 * added 20130605
 */
enum LYHandsOrder LYHoldemGame::judgeCommunity()
{
	if (this->round != LYGameFlop && this->round != LYGameTurn && this->round != LYGameRiver) {
		return LYON_DRAW;
	}
    std::vector<LYCard> cards = flopCards;
    if (!turnCard.isFlipCard()) {
        cards.push_back(turnCard);
    } else {
    	cards.push_back(smallGhost);
    }
    if (!riverCard.isFlipCard()) {
        cards.push_back(riverCard);
    } else {
    	cards.push_back(bigGhost);
    }
    LYHoldemAlgorithmDelegate had; //把HandStrength算法从类里移到了外面，改来改去，这个Ugly的代码以后再改掉吧
    LYHandOdds *hsp = new LYHandOdds(cards, &had);
//    LYHandOdds *hsp = new LYHandOdds(cards);
    LYHandOddsPtr hs = LYHandOddsPtr(hsp);
    unsigned int sbase = 0;
    unsigned int baseCount = 2;
    if (this->round == LYGameRiver) baseCount = 3;
	switch (hs->ranking)
	{
	case OnePair:
	case TwoPair:
	case ThreeOfAKind:
		return LYFOUROFAKIND_ODDS;
	case Straight:
		if (hs->flush_base()>=baseCount) {
			return LYFLUSH_ODDS;
		}
		return LYOUTSIDE_ODDS;
	case Flush:
		return LYFLUSH_ODDS;
	case HighCard:
		if (hs->flush_base()>=baseCount) {
			return LYFLUSH_ODDS;
		}
		sbase = hs->straight_base();
		if (sbase >= baseCount) {
			if (sbase == 2) return LYGUTSHOT_ODDS; //not 100% correct here!
			return LYOUTSIDE_ODDS;
		}
		return LYFLUSH_ODDS;
	default:
		break;
	}
    return LYON_DRAW;
}

/*
 * added 20130605
 */
unsigned int LYHoldemGame::getOuts(enum LYApplicant player)
{
	if ((unsigned int)player < 1 || (unsigned int)player > 9) {
//		LY_LOG_ERR("getOuts::player must be between 1..9, " << (unsigned int)player);
		return 0;
	}
//	LY_LOG_DBG("enter getOuts, round=" << this->round);
	if (this->round == LYGameRiver || this->round == LYGamePreflop) {
		return 0;
	}
	//only process game in flop/turn
	LYHandOddsPtr hs = LYHandOddsPtr(this->getHandOdds(player));
	if (NULL == hs.get()) {
		return 0;
	}
	if (NULL != hs.get() && (hs->ranking == StraightFlush
							|| hs->ranking == FourOfAKind)) {
		//don't really think these two hands need any out
		return 0;
	}
	LYSeatPtr seat = this->fetchSeat(player);
	std::vector<std::string> indexs = hs->genIndex(seat->handCards[0]);
	std::vector<std::string> indexs2 = hs->genIndex(seat->handCards[1]);
	//merge two indexs
	std::vector<std::string> newIndex = indexs;
	BOOST_FOREACH(std::string idx1, indexs2)
	{
		bool dup = false;
		BOOST_FOREACH(std::string idx2, newIndex)
		{
			if (idx2 == idx1) {
				dup = true;
			}
		}
		if (!dup) {
			newIndex.push_back(idx1);
		}
	}
	unsigned int outs = 0;
	BOOST_FOREACH(std::string idx, newIndex)
	{
		std::vector<LYCard> cards = hs->get_odds(idx);
		unsigned int sz = cards.size();
		std::string flag = idx.substr(0, 3);
//		LY_LOG_DBG("idx=" <<idx << ", size=" << sz << ", outs=" << outs);
		if (flag == "Qua" && sz == 3) {
			outs++;
		}
		if (flag == "Set" && sz == 2) {
			outs += 2;
		}
		if (flag == "Flu" && sz == 4) {
			outs += 9;
		}
		if (flag == "Str" && sz == 4) {
			outs += 4;
		}
		if (flag == "Ful" && sz == 4) {
			outs += 3;
		}
//		if (flag == "SnF" && sz == 4) {
//			outs += 1;
//		}
//		if (flag == "2pr" && sz == 3) {
//			outs += 3;
//		}
//		if (flag == "1pr" && sz == 1) {
//			outs += 3;
//		}
	}
    return outs;
}

/*
 * added 20130605
 */
unsigned int LYHoldemGame::getChipsIfWin(enum LYApplicant player)
{
    return pm.getChipsIfWin(player);
}

LYHandOdds *LYHoldemGame::getHandOdds(enum LYApplicant player)
{
	LYSeatPtr st = this->fetchSeat(player);
	if (NULL == st.get() || st->handCards.size() != 2) {
		return NULL;
	}
    if (st->handCards[0].isFlipCard() ||
        st->handCards[1].isFlipCard()) {
        return NULL;
    }
    std::vector<LYCard> cards = flopCards;
    if (!turnCard.isFlipCard()) {
        cards.push_back(turnCard);
    }
    if (!riverCard.isFlipCard()) {
        cards.push_back(riverCard);
    }
    cards.push_back(st->handCards[0]);
    cards.push_back(st->handCards[1]);
    LYHoldemAlgorithmDelegate had; //把HandStrength算法从类里移到了外面，改来改去，这个Ugly的代码以后再改掉吧
    LYHandOdds *ho = new LYHandOdds(cards, &had);
    return ho;
}

LYHandStrength *LYHoldemGame::getHandStrength(enum LYApplicant player)
{
	LYSeatPtr st = this->fetchSeat(player);
	if (NULL == st.get() || st->handCards.size() != 2) {
		return NULL;
	}
    if (st->handCards[0].isFlipCard() ||
        st->handCards[1].isFlipCard()) {
        return NULL;
    }
    std::vector<LYCard> cards = flopCards;
    if (!turnCard.isFlipCard()) {
        cards.push_back(turnCard);
    }
    if (!riverCard.isFlipCard()) {
        cards.push_back(riverCard);
    }
    cards.push_back(st->handCards[0]);
    cards.push_back(st->handCards[1]);
    LYHoldemAlgorithmDelegate had;
    LYHandStrength *hs = new LYHandStrength(cards, &had);
    return hs;
}

LYHoldemScene *LYHoldemGame::lastScene()
{
	LYHoldemScene *scene = NULL;
	LYHoldemScenePtr scenePtr = scenes.back();
	if (scenes.size() > 0 && NULL != scenePtr.get()) {
		return scenePtr.get();
	}
	return scene;
}

LYRanking LYHoldemGame::caculateSeatRanking(LYApplicant seatNo)
{
	LYHandStrength *hs = this->getHandStrength(seatNo);
	if (NULL == hs) {
		return HighCard;
	}
	LYRanking ranking = hs->ranking;
	delete hs;
	return ranking;
}

void LYHoldemGame::genActionView(LYApplicant seatNo, LYHoldemActionView& actionView)
{
	LYHoldemSeat *seat = (LYHoldemSeat *)this->fetchSeat(seatNo).get();
	if (NULL == seat || seat->status == LYSeatOpen ||
//			LYSeatHoldemWaiting == seat->gameStatus ||
			LYSeatHoldemInFold == seat->gameStatus ||
			LYSeatHoldemInAllin == seat->gameStatus){
		//nothing to do
		return;
	}

	//now seat is in game
	if (continueThisRound != LYHoldemRoundCont) { //means ends this round
		//nothing to do as well
//		std::cout << "kkkkk" << std::endl;
//		LY_LOG_DBG("not continue this round! " << continueThisRound);
		return;
	}

	if (this->dutySeatNo == seatNo) {
		actionView.onDuty = true;
	}

	actionView.betIfCall = this->betIfCall;
	actionView.betToCall = 0;

	//get all involved users from the top pot
	unsigned int chipsLeft = seat->getChipsLeft();
	unsigned int maxLeft = this->getMaxChipsLeftOfOthers(seatNo); //其他人最大的筹码量
	//actionView.raiseMax：从chipsLeft, maxLeft二者中取小
	//actionView.raiseMin：从chipsLeft, this->minBetIfRaise二者中取小
	actionView.raiseMax = (chipsLeft<maxLeft)?chipsLeft:maxLeft;
	actionView.raiseMin = (this->minBetIfRaise < chipsLeft)?this->minBetIfRaise:chipsLeft;
	if (actionView.raiseMax < actionView.raiseMin) { //意味着除了自己，其它人的筹码都不够Raise
		actionView.raiseMin = actionView.raiseMax;
	}
//	raiseMax == raiseMin means allin if raise
	if (seat->lastBet == this->betIfCall) { //只有在Preflop时，一路Call到BigBlind
		//view显示：fold/check/raise, view判断是否allin根据raiseMin和raiseMax两个参数
		actionView.checkEnabledForBigBlind = true;
		return;
	}
	//只可能是seat->lastBet < this->betIfCall
	//view显示fold/call/raise，需要区分的是如果Call就Allin即显示另外一种情况fold/allin
	if (chipsLeft <= this->betIfCall) {
		actionView.allinIfCall = true;
		actionView.betToCall = seat->chipsAtHand;
	} else {
		actionView.betToCall = this->betIfCall - seat->lastBet;
	}
}

unsigned int LYHoldemGame::getMaxChipsLeftOfOthers(LYApplicant seatNo)
{
	LYPotPtr& topPot = pm.topPot();
	std::vector<LYApplicant>::iterator it = topPot->seatsInPot.begin();
	unsigned int max_chips = 0;
	for (; it!=topPot->seatsInPot.end(); it++) {
		if (*it == seatNo) continue;
		LYHoldemSeat* seat = (LYHoldemSeat*)(fetchSeat(*it).get());
		if (NULL == seat) continue;
		if (seat->getChipsLeft() > max_chips) {
			max_chips = seat->getChipsLeft();
		}
	}
	return max_chips;
}

bool LYHoldemGame::isWinner(LYApplicant seatNo)
{
	if ((unsigned int)seatNo < 1 || (unsigned int)seatNo > 9) {
//		LY_LOG_ERR("isWinner::seatNo must be between 1..9, " << (unsigned int)seatNo);
		return false;
	}
	std::vector<LYPotPtr>& _pots = this->pots();
	std::vector<LYPotPtr>::iterator it = _pots.begin();
	for (; it!=_pots.end(); it++) {
		LYPotPtr pot = *it;
		if (pot->isWinner(seatNo)) {
			return true;
		}
	}
	return false;
}

/*
 * 被takeSeat/leaveSeat调用，如果round是在游戏中，则返回false，否则返回true
 */
bool LYHoldemGame::readyForNext()
{
	if (this->round == LYGameClosed || this->round == LYGameInit || this->round == LYGameWaiting) {
		return true;
	}

//	std::vector<LYSeatPtr>::iterator it = seatsOfTable.begin();
//	int seated = 0;
//	for (; it != seatsOfTable.end(); it ++) {
//		LYSeatPtr seat = *it;
//		if (seat->status != LYSeatOpen) {
//			seated ++;
//		}
//		if (seated > 2) {
//			return false;
//		}
//	}
//
//	if (seated == 2) {
//		this->round = LYGameWaiting;
//		return true;
//	}
//
	return false;
}

/*
 * 之前的持久化/序列化跟数据库有关，因此把它放到了后台
 * 现在持久化到redis中，只需要key-value-pair，因此又在本类中实现。
 * 2016-03-10
 */
std::vector<std::pair<std::string, std::string> > LYHoldemGame::game2kvps()
{
	std::vector<std::pair<std::string, std::string> > kvps = static2kvps();

	std::vector<std::pair<std::string, std::string> > v = dynamic2kvps();
	kvps.insert(kvps.end(), v.begin(), v.end());

	std::pair < std::string, std::string > kvp;
	kvp.first = "flopCards";
	LYCardHelpers::cardsToStringifiedInt(this->flop_action.cards, kvp.second);
	kvps.push_back(kvp);

	kvp.first = "turnCard";
	kvp.second = std::to_string(this->turn_action.cards[0].toInteger());
	kvps.push_back(kvp);

	kvp.first = "riverCard";
	kvp.second = std::to_string(this->river_action.cards[0].toInteger());
	kvps.push_back(kvp);

	kvp.first = "_id";
	kvp.second = this->_id;
	kvps.push_back(kvp);

	return kvps;
}

void LYHoldemGame::buildPot(std::vector<std::pair<std::string, std::string>>& kvps)
{
	pm.buildPot(kvps);
}

std::vector<LYCard> LYHoldemGame::getAllVisibleCards()
{
	std::vector<LYCard> cards = this->getCommunityCards();
	std::vector<LYSeatPtr>::iterator it = seatsOfTable.begin();
	for (; it!=seatsOfTable.end(); it++) {
		LYHoldemSeat *seat = (LYHoldemSeat *)(*it).get();
		if (seat->status == LYSeatInGame && seat->gameStatus == LYSeatHoldemInAllin) {
			cards.insert(cards.end(), seat->handCards.begin(), seat->handCards.end());
		}
	}

	return cards;
}

void LYHoldemGame::checkAssurance(const LYCard &card)
{
	std::vector<LYPotPtr>& allpots = pots();
	std::vector<LYPotPtr>::iterator it = allpots.begin();
	for (; it!=allpots.end(); it++) {
		LYPotPtr pot = *it;
		pot->checkAssurance(this->round, card);
	}
}

bool LYHoldemGame::finishAssurance()
{
LY_LOG_DBG("assure:" << assureActionNumbers);
	return (assureActionNumbers == 0);
}

/*
 * added 20160701
 * for white list when game finished
 */
std::vector<std::string> LYHoldemGame::getWhiteList()
{
	std::vector<std::string> white_list;
	if (round != LYGameClosed || totalSeatsInGame() < 2) 	return white_list;
    std::vector<LYSeatPtr>::iterator it = sortedSeats.begin();
    for (; it!=sortedSeats.end(); it++) {
    	LYSeatPtr seat = *it;
		LYHoldemSeat *hs = (LYHoldemSeat *)seat.get();
		if (hs->gameStatus == LYSeatHoldemInAllin || this->isWinner(hs->seatNo)) {
			white_list.push_back(hs->playerId);
		}
	}

	return white_list;
}

/*
 * added 20160701
 * for white list when game finished
 */
unsigned int LYHoldemGame::totalSeatsInGame()
{
	unsigned int count = 0;
    std::vector<LYSeatPtr>::iterator it = sortedSeats.begin();
    for (; it!=sortedSeats.end(); it++) {
    	LYSeatPtr seat = *it;
		LYHoldemSeat *hs = (LYHoldemSeat *)seat.get();
		if (hs->gameStatus == LYSeatHoldemWaiting || hs->gameStatus == LYSeatHoldemInFold) continue;
		count ++;
	}
	return count;
}

LYSeatPtr LYHoldemGame::findLastSeatInGame()
{
	LYSeatPtr seat;
    std::vector<LYSeatPtr>::iterator it = sortedSeats.begin();
    for (; it!=sortedSeats.end(); it++) {
    	seat = *it;
		LYHoldemSeat *hs = (LYHoldemSeat *)seat.get();
		if (hs->gameStatus == LYSeatHoldemWaiting || hs->gameStatus == LYSeatHoldemInFold) continue;
		break;
	}
	return seat;
}

LYHoldemAction LYHoldemGame::popAssureAction()
{
	LYHoldemAction action;
	std::vector<LYPotPtr>::iterator it = pots().begin();
	for (; it != pots().end(); it++) {
		LYPotPtr pot = *it;
		if (pot->assureActions.size() > 0) {
			return pot->popAssureAction();
		}
	}
	return action;
}

void LYHoldemGame::appendLog(const std::string& log)
{
	logMgr.appendLog(log);
}

std::vector<std::string> LYHoldemGame::getGameLogs()
{
	return logMgr.getLogs();
}

max_stars_repo_name: caiqingfeng/libpoker

max_issues_repo_name: caiqingfeng/libpoker

max_forks_repo_name: caiqingfeng/libpoker


text:
// This file is part of the dune-xt-common project:
//   https://github.com/dune-community/dune-xt-common
// Copyright 2009-2018 dune-xt-common developers and contributors. All rights reserved.
// License: Dual licensed as BSD 2-Clause License (http://opensource.org/licenses/BSD-2-Clause)
//      or  GPL-2.0+ (http://opensource.org/licenses/gpl-license)
//          with "runtime exception" (http://www.dune-project.org/license.html)
// Authors:
//   Felix Schindler (2014, 2016 - 2019)
//   René Fritze     (2013 - 2016, 2018)
//   Tobias Leibner  (2018 - 2019)

#ifndef DUNE_XT_COMMON_PARALLEL_THREADSTORAGE_HH
#define DUNE_XT_COMMON_PARALLEL_THREADSTORAGE_HH

#if HAVE_TBB
#  include <tbb/enumerable_thread_specific.h>
#endif

#include <algorithm>
#include <list>
#include <mutex>
#include <numeric>
#include <system_error>
#include <type_traits>

#include <dune/xt/common/exceptions.hh>

// TODO: the following includes can be removed when UnsafePerThreadValue is removed
#include <deque>
#include <memory>
#include <boost/noncopyable.hpp>
#include <dune/xt/common/parallel/threadmanager.hh>

namespace Dune {
namespace XT {
namespace Common {
namespace internal {

#if HAVE_TBB

template <class ValueImp>
class EnumerableThreadSpecificWrapper
{
  // enumerable_thread_specific does not compile with ConstValueType as template param
  using BackendType = typename tbb::enumerable_thread_specific<std::remove_const_t<ValueImp>>;

public:
  using ValueType = ValueImp;
  using ConstValueType = std::add_const_t<ValueType>;
  using iterator = typename BackendType::iterator;
  using const_iterator = typename BackendType::const_iterator;

  template <class... InitTypes>
  explicit EnumerableThreadSpecificWrapper(InitTypes&&... ctor_args)
    : values_(std::forward<InitTypes>(ctor_args)...)
  {}

  ValueType& local()
  {
    return values_.local();
  }

  // tbb does not provide a const version of local (as elements may be inserted when a new thread accesses values_), so
  // values_ has to be mutable
  const ValueType& local() const
  {
    return values_.local();
  }

  typename BackendType::iterator begin()
  {
    return values_.begin();
  }

  typename BackendType::iterator end()
  {
    return values_.end();
  }

  typename BackendType::const_iterator begin() const
  {
    return values_.begin();
  }

  typename BackendType::const_iterator end() const
  {
    return values_.end();
  }

  template <class BinaryOperation>
  ValueType combine(BinaryOperation op) const
  {
    return values_.combine(op);
  }

private:
  mutable BackendType values_;
}; // class EnumerableThreadSpecificWrapper<ValueImp>

#else // HAVE_TBB

template <class ValueImp>
class EnumerableThreadSpecificWrapper
{
  using BackendType = std::unique_ptr<std::remove_const_t<ValueImp>>;

public:
  using ValueType = ValueImp;
  using ConstValueType = std::add_const_t<ValueType>;
  using iterator = ValueType*;
  using const_iterator = const ValueType*;

  //! Initialization by copy construction of ValueType
  explicit EnumerableThreadSpecificWrapper(ConstValueType& value)
    : values_(std::make_unique<std::remove_const_t<ValueType>>(value))
  {}

  //! Initialization by in-place construction ValueType with \param ctor_args
  template <class... InitTypes>
  explicit EnumerableThreadSpecificWrapper(InitTypes&&... ctor_args)
    : values_(std::make_unique<std::remove_const_t<ValueType>>(std::forward<InitTypes>(ctor_args)...))
  {}

  ValueType& local()
  {
    return *values_;
  }

  const ValueType& local() const
  {
    return *values_;
  }

  iterator begin()
  {
    return values_.get();
  }

  iterator end()
  {
    return values_.get() + 1;
  }

  const_iterator begin() const
  {
    return values_.get();
  }

  const_iterator end() const
  {
    return values_.get() + 1;
  }

  template <class BinaryOperation>
  ValueType combine(BinaryOperation /*op*/) const
  {
    return *values_;
  }

private:
  BackendType values_;
}; // class EnumerableThreadSpecificWrapper<ValueImp>

#endif // HAVE_TBB

} // namespace internal

/** Automatic Storage of non-static, N thread-local values
 **/
template <class ValueImp>
class PerThreadValue
{
  using ContainerType = internal::EnumerableThreadSpecificWrapper<ValueImp>;

public:
  using ValueType = typename ContainerType::ValueType;
  using ConstValueType = typename ContainerType::ConstValueType;

  //! Initialization by copy construction of ValueType
  explicit PerThreadValue(ConstValueType& value)
    : values_(value)
  {}

  //! Initialization by in-place construction ValueType with \param ctor_args
  template <class... InitTypes>
  explicit PerThreadValue(InitTypes&&... ctor_args)
    : values_(std::forward<InitTypes>(ctor_args)...)
  {}

  operator ValueType() const
  {
    return values_.local();
  }

  ValueType& operator*()
  {
    return values_.local();
  }

  ConstValueType& operator*() const
  {
    return values_.local();
  }

  ValueType* operator->()
  {
    return &values_.local();
  }

  ConstValueType* operator->() const
  {
    return &values_.local();
  }

  template <class BinaryOperation>
  ValueType accumulate(ValueType init, BinaryOperation op) const
  {
    return op(init, values_.combine(op));
  }

  ValueType sum() const
  {
    return accumulate(ValueType(0), std::plus<ValueType>());
  }

  typename ContainerType::iterator begin()
  {
    return values_.begin();
  }
  typename ContainerType::iterator end()
  {
    return values_.end();
  }

  typename ContainerType::const_iterator begin() const
  {
    return values_.begin();
  }
  typename ContainerType::const_iterator end() const
  {
    return values_.end();
  }

private:
  ContainerType values_;
}; // class PerThreadValue<ValueImp>

/**
 * Previous implementation of PerThreadValue. This implementation suffers from the fact that it is not possible (or
 * at least we did not find a way yet) to set a hard upper limit on the number of threads TBB uses. Setting max_threads
 * via tbb::task_scheduler_init apparently only sets a soft limit on the number of threads. In addition, even if TBB
 * uses only N threads at a time, it might be possible that a thread is destroyed and later in the program another
 * thread with a different id replaces it, which will then get a number greater than or equal to N in our
 * implementation (see ThreadManager::thread()). This occasionally leads to segfaults.
 * We keep this implementation around as it is currently used by TimingData (see dune/xt/common/timings.hh) and the
 * new implementation can't replace it in that context, as the new implementation based on
 * tbb::enumerable_thread_specific lazily initalizes the values in each thread.
 * \todo Either fix TimingData and remove this class or fix this class.
 **/
template <class ValueImp>
class UnsafePerThreadValue : public boost::noncopyable
{
public:
  typedef ValueImp ValueType;
  typedef typename std::conditional<std::is_const<ValueImp>::value, ValueImp, const ValueImp>::type ConstValueType;

private:
  typedef UnsafePerThreadValue<ValueImp> ThisType;
  typedef std::deque<std::unique_ptr<ValueType>> ContainerType;

public:
  //! Initialization by copy construction of ValueType
  explicit UnsafePerThreadValue(ConstValueType& value)
    : values_(threadManager().max_threads())
  {
    std::generate(values_.begin(), values_.end(), [=]() { return std::make_unique<ValueType>(value); });
  }

  //! Initialization by in-place construction ValueType with \param ctor_args
  template <class... InitTypes>
  explicit UnsafePerThreadValue(InitTypes&&... ctor_args)
    : values_(threadManager().max_threads())
  {
    for (auto&& val : values_)
      val = std::make_unique<ValueType>(ctor_args...);
  }

  ThisType& operator=(ConstValueType&& value)
  {
    std::generate(values_.begin(), values_.end(), [=]() { return std::make_unique<ValueType>(value); });
    return *this;
  }

  operator ValueType() const
  {
    return this->operator*();
  }

  ValueType& operator*()
  {
    return *values_[threadManager().thread()];
  }

  ConstValueType& operator*() const
  {
    return *values_[threadManager().thread()];
  }

  ValueType* operator->()
  {
    return values_[threadManager().thread()].get();
  }

  ConstValueType* operator->() const
  {
    return values_[threadManager().thread()].get();
  }

  auto& get_pointer()
  {
    return values_[threadManager().thread()];
  }

  template <class BinaryOperation>
  ValueType accumulate(ValueType init, BinaryOperation op) const
  {
    typedef const typename ContainerType::value_type ptr;
    auto l = [&](ConstValueType& a, ptr& b) { return op(a, *b); };
    return std::accumulate(values_.begin(), values_.end(), init, l);
  }

  ValueType sum() const
  {
    return accumulate(ValueType(0), std::plus<ValueType>());
  }

  typename ContainerType::iterator begin()
  {
    return values_.begin();
  }
  typename ContainerType::iterator end()
  {
    return values_.end();
  }

  typename ContainerType::const_iterator begin() const
  {
    return values_.begin();
  }
  typename ContainerType::const_iterator end() const
  {
    return values_.end();
  }

private:
  ContainerType values_;
}; // class UnsafePerThreadValue<...>

/**
 * \brief Propagates results from copies in each thread (usually stemming from PerThreadValue) to base functor on
 *calling finalize.
 * \param imp_ Pointer to implementation
 * \param base_ Pointer to initial base functor
 **/
template <class Imp, typename Result, class Reduction = std::plus<Result>>
class ThreadResultPropagator
{
public:
  ThreadResultPropagator(Imp* imp)
    : imp_(imp)
    , base_(imp)
  {}

  ThreadResultPropagator(const ThreadResultPropagator& other)
    : imp_(other.imp_)
    , base_(other.base_)
    , mutex_()
  {}

  Imp* copy_imp()
  {
    auto* cpy = new Imp(*imp_);
    cpy->base_ = imp_->base_;
    cpy->imp_ = cpy;
    return cpy;
  }

  void finalize_imp()
  {
    Reduction reduce;
    base_->set_result(reduce(base_->result(), imp_->result()));
  }

protected:
  Imp* imp_;
  Imp* base_;
  std::mutex mutex_;
};

template <typename T>
struct concatenate_container
{
  T operator()(const T& a, const T& b)
  {
    T result = a;
    result.insert(b.begin(), b.end());
    return result;
  }
}; // struct concatenate_container

} // namespace Common
} // namespace XT
} // namespace Dune

#endif // DUNE_XT_COMMON_PARALLEL_THREADSTORAGE_HH

ext: hh

max_stars_repo_name: ftschindler-work/dune-xt-common

max_issues_repo_name: ftschindler-work/dune-xt-common

max_forks_repo_name: ftschindler-work/dune-xt-common