/
RedResistance
/
wonders
Обзор
Документация
Войти
/
RedResistance
/
wonders
Код
Запросы
2
Задачи
Вики
Пакеты
0
Релизы
0
CI/CD
Аналитика
Безопасность
master
manager.cpp
345 строк
13 KB
Domovoi-Kuzma
рефактор
12 июл 2026, 12:44
12 июл 2026, 12:44
8d5786d
Код
Авторство
О чём код?
#include <algorithm> // ��� shuffle #include <random> // ��� random_device � mt19937 #include <set> #include "manager.h" #include "payment_status.h" #include "console_strategy.h" manager::manager(int player_cnt, std::vector<std::unique_ptr<Card> >&& all_cards) : players_hands(player_cnt), three_decks(3)// ������������� ������������� ���������� ����� (3) { players.resize(player_cnt); // ����������� ������ ��� ������������� for (PlayerIndex i = 0; i < player_cnt; ++i) { strategies.emplace_back(std::make_unique<ConsoleStrategy>(i)); // ������� ������ � ���������� ���������� } std::random_device rd; std::mt19937 g(rd()); // ������������ ����� �� ������� for (size_t i = 0; i < all_cards.size(); ++i) { if (all_cards[i]->fit_for_players(player_cnt)) { int deck_idx = all_cards[i]->get_deck_as_array_index(); // ������ ������ three_decks[deck_idx].emplace_back(std::move(all_cards[i])); } } auto& deck = three_decks[2]; // ������ III ����� std::vector<std::unique_ptr<Card>> guilds; std::vector<std::unique_ptr<Card>> others; for (auto& c : deck) { if (c->get_color() == Color::Purple) guilds.emplace_back(std::move(c)); else others.emplace_back(std::move(c)); } deck.clear(); std::shuffle(guilds.begin(), guilds.end(), g); size_t keep = std::min(guilds.size(), static_cast<size_t>(player_cnt + 2)); for (size_t i = 0; i < keep; ++i) others.emplace_back(std::move(guilds[i])); deck = std::move(others); // ������������� ������ ������ for (auto& deck : three_decks) { std::shuffle(deck.begin(), deck.end(), g); } int i = 0; for (auto& plr : players) { cout << "Player " << i << ", input name:"; getline(cin, plr.name); ++i; } } void manager::deal(std::vector<std::unique_ptr<Card> >& deck_) { int i = 0; for (auto& card_ : deck_) { players_hands[i].push_back(std::move(card_)); ++i; if (i == players_hands.size()) i = 0; } } void manager::run_epoch() { ++current_epoch; current_round = 0; while(!players_hands[0].empty()) { run_round(); } resolve_conflicts(); } void manager::run_game() { current_epoch = 0; first_player_hand_id = 0; for (auto& deck_ : three_decks) { deal(deck_); run_epoch(); } } void manager::build_last_round_state_view() { last_round_state_view = std::make_shared<GameStateView>(); auto& view = *last_round_state_view; view.epoch = current_epoch; view.round = current_round; view.players.resize(players.size()); for (PlayerIndex i = 0; i < players.size(); ++i) view.players[i] = players[i].get_state_view(); } void manager::run_round() { ++current_round; ++first_player_hand_id; if (first_player_hand_id == players_hands.size()) first_player_hand_id = 0; build_last_round_state_view(); vector<CardAction> applied_actions; for (PlayerIndex i = 0; i < players.size(); ++i) { applied_actions.emplace_back( run_player_selection(i) ); } for (PlayerIndex i = 0; i < players.size(); ++i) { run_player_action(i, applied_actions[i]); } } CardAction manager::run_player_selection(PlayerIndex player_index) { player& plr = players[player_index]; HandIndex hand_index = (first_player_hand_id + player_index) % players_hands.size(); auto& hand = players_hands[hand_index]; HandChoiceView hand_view = build_hand_choice_view(hand); ChoiceResult choice; do { choice = strategies[player_index]->choose_card(hand_view); switch (choice.type) { case ShowScores: strategies[player_index]->notify_scores(make_shared<GameStateView>()); break; case ShowGameState: strategies[player_index]->notify_game_state(last_round_state_view); break; } } while (choice.type != ChoiseMade); plr.select_building(std::move(hand[choice.value])); hand.erase(hand.begin() + choice.value); CardUsageView use_view = build_card_usage_view(player_index); do { choice = strategies[player_index]->choose_usage(use_view); switch (choice.type) { case ShowScores: strategies[player_index]->notify_scores(make_shared<GameStateView>()); break; case ShowGameState: strategies[player_index]->notify_game_state(last_round_state_view); break; } } while (choice.type != ChoiseMade); return use_view.allowed_actions[choice.value]; } void manager::run_player_action(PlayerIndex player_index, CardAction action) { player& plr = players[player_index]; for (auto tr : action.required_to_pay.all_transactions) { if (!tr.money.get()) continue; player& nghbr = players[addDir(player_index, tr.whom)]; plr.modify_money(-tr.money); nghbr.modify_money(tr.money); } switch (action.type) { case CardActionType::Build: case CardActionType::BuildBuy: case CardActionType::BuildBonus: case CardActionType::BuildFree: plr.build_building(*this); return; case CardActionType::Sell: plr.modify_money(3); return; default: throw std::runtime_error("unready CardAction"); } } HandChoiceView manager::build_hand_choice_view(const Hand& hand) { HandChoiceView view; view.cards.reserve(hand.size()); for (const auto& c : hand) view.cards.push_back(c->get_view_data()); return view; } CardUsageView manager::build_card_usage_view(PlayerIndex pi) { const player& plr = players[pi]; CardUsageView view; view.selected_card = plr.get_selected_building_view_data(); //������ �������� �������, ��� ����������� �� ���������� ����� � ������� ������ view.allowed_actions.push_back({ CardActionType::Sell }); if (plr.is_selected_duplicated()) { //skip all kinds of action build } else if (plr.is_selected_bonus_buildable()) { view.allowed_actions.push_back({ CardActionType::BuildBonus }); } else if (view.selected_card.dollars.get() > 0) { if (plr.get_money().get() > view.selected_card.dollars.get()) { view.allowed_actions.push_back({ CardActionType::BuildBuy }); } } else if (view.selected_card.cost.is_zero()) { view.allowed_actions.push_back({ CardActionType::BuildFree }); } else { std::vector<PaymentBatch> variants = manager::calculate_buy_variants(pi, view.selected_card.cost); for (auto batch : variants) view.allowed_actions.push_back({ CardActionType::Build, batch}); } return view; } std::vector<PaymentStatus> manager::append_one_side_trade_variants(std::vector<PaymentStatus> input_variants, PlayerIndex pi, Direction dir) { std::vector<PaymentStatus> output_variants; const player& plr = players[pi]; const CostVariants& buyable_variants = players[addDir(pi, dir)].get_tradable_variants(); std::set<Cost> used; for (auto& part_paid : input_variants) { for (const Cost& income_variant : buyable_variants) { vector<Transaction> from_product = { { dir, {}, 0 } }, to_product; //vector �� PaymentBatch, ������� ���� ������ ������ ��� ��� �� �����, � �����-������� for (Resource res : globals::allResources) { int can_be_bought_max_counting_only_resources = min(income_variant[res], part_paid.unpaid_goods[res]); int price = plr.get_neighbor_price(dir, res).get(); int can_be_bought_max_counting_only_money = part_paid.money_left.get() / price; int max_buy = min(can_be_bought_max_counting_only_resources, can_be_bought_max_counting_only_money); //������� � 0, ���� ���������� �������� ����� ������ � ������� for (int ammount_res = 0; ammount_res <= max_buy; ++ammount_res) { for (auto from : from_product) { from.goods[res] = ammount_res; from.money += price * ammount_res; to_product.push_back(from); } } swap(from_product, to_product); to_product.clear(); } for (auto tr_var : from_product) { auto left_unpaid = part_paid.unpaid_goods - tr_var.goods; if (used.find(left_unpaid) == used.end()) { used.insert(left_unpaid); // ��������� � ��������� ���������� ��������� int new_money = part_paid.money_left.get() - tr_var.money.get(); if (new_money >= 0) { PaymentStatus output_variant = part_paid; output_variant.money_left = new_money; output_variant.unpaid_goods -= tr_var.goods; output_variant.already_paid.all_transactions.emplace_back(tr_var); output_variants.emplace_back(output_variant); } } } } } return output_variants; } std::vector<PaymentBatch> manager::calculate_buy_variants(PlayerIndex pi, const Cost& cost) { Transaction from_self = { Direction::Self, cost, 0 }; const player& plr = players[pi]; std::vector<PaymentStatus> part_paid_variants, two_part_paid_variants; std::vector<PaymentBatch> paid_variants; std::set<Cost> used_self; for (const Cost& income_variant: plr.get_total_variants()) { PaymentStatus part_paid_variant; part_paid_variant.unpaid_goods = cost - income_variant; if (part_paid_variant.unpaid_goods.is_zero()) { //cout << "is_zero"<<endl; return { { {from_self} } }; // ��� ��� �� part_paid_variant � full_paid_variant ���������� ������ ���������, //����� ������� ���� ������� ��� ��������� } if (used_self.find(part_paid_variant.unpaid_goods) == used_self.end()) { Transaction from_self = { Direction::Self, cost - part_paid_variant.unpaid_goods, //�������� �������������� 0 }; used_self.insert(part_paid_variant.unpaid_goods); part_paid_variant.already_paid.all_transactions.emplace_back(from_self); part_paid_variant.money_left = plr.get_money(); part_paid_variants.emplace_back(part_paid_variant); } } part_paid_variants = append_one_side_trade_variants(part_paid_variants, pi, Direction::Right); for (auto& part_paid_variant : part_paid_variants) { if (part_paid_variant.unpaid_goods.is_zero()) { paid_variants.emplace_back(part_paid_variant.already_paid); continue; } if (part_paid_variant.money_left.get() == 0) continue; two_part_paid_variants.emplace_back(part_paid_variant); } two_part_paid_variants = append_one_side_trade_variants(two_part_paid_variants, pi, Direction::Left); for (auto& part_paid_variant : two_part_paid_variants) if (part_paid_variant.unpaid_goods.is_zero()) paid_variants.emplace_back(part_paid_variant.already_paid); return paid_variants; } PlayerIndex manager::addDir(PlayerIndex current, Direction d) const { switch (d) { case Direction::Left: return (current + players.size() - 1) % players.size(); case Direction::Right: return (current + 1) % players.size(); case Direction::Self: return current; } throw std::runtime_error("unexpected Direction"); } int manager::count_color_around(PlayerIndex pi, Color c) const { return players[addDir(pi,Direction::Left)].count_color(c) + players[addDir(pi, Direction::Right)].count_color(c); } PlayerIndex manager::index_of(const player& plr) const { return static_cast<PlayerIndex>(&plr - players.data()); } void manager::resolve_conflicts() { for (PlayerIndex pi = 0; pi < players.size(); ++pi) { auto& current = players[pi]; auto& rightOne = players[addDir(pi, Direction::Right)]; current.createConflict(current_epoch, &rightOne); rightOne.createConflict(current_epoch, ¤t); } } vector<player*> manager::getNeighbors(player& plr, ReferringPlayers ref) { vector<player*> result; PlayerIndex current_index = index_of(plr); std::vector<PlayerIndex> target_indices; switch (ref) { case ReferringPlayers::Both: target_indices.push_back(current_index); case ReferringPlayers::Neighbors: target_indices.push_back(addDir(current_index, Direction::Left)); target_indices.push_back(addDir(current_index, Direction::Right)); break; case ReferringPlayers::Self: target_indices.push_back(current_index); break; default: throw std::runtime_error("Unsupported Direction in onBuild"); } for (PlayerIndex idx : target_indices) { result.push_back(&players[idx]); } return result; }