Monopoly — Portage moderne 0.1.0
Portage moderne C/C++23 du Monopoly de 1999
Loading...
Searching...
No Matches
PieceMoveIngress.cpp
Go to the documentation of this file.
2
3#include <cstdlib>
4#include <utility>
5#include <vector>
6
7namespace monopoly::pieces
8{
9 namespace
10 {
11 [[nodiscard]] bool movementAction(actions::Type action) noexcept
12 {
13 return action == actions::Type::NotifyMoveForwards ||
16 }
17
18 [[nodiscard]] PieceMoveIngressError plannerError(
20 {
22 }
23 }
24
26 : PieceMoveIngress([] { return static_cast<std::uint8_t>(std::rand() & 1); })
27 {
28 }
29
35 {
36 pendingPlan_.reset();
37 pendingSpecial_.reset();
38 }
39
40 std::expected<PieceMovePlan, PieceMoveIngressError>
41 PieceMoveIngress::buildPlan(actions::Type action, std::uint8_t token,
42 std::int32_t before, std::int32_t after, bool animationsEnabled)
43 {
44 std::vector<std::uint8_t> choices;
46 for (;;)
47 {
48 auto planned = planTokenMove(action, token, before, after,
49 animationsEnabled, choices);
50 if (planned) return std::move(*planned);
52 return std::unexpected(plannerError(planned.error()));
53 if (choices.size() >= TokenAnimationItemLimit)
54 return std::unexpected(plannerError(
56 choices.push_back(randomBit_ ?
57 static_cast<std::uint8_t>(randomBit_() & 1U) : 0U);
58 }
59 }
60
61 std::optional<PieceMovePlan> PieceMoveIngress::takePlan()
62 {
63 auto result = std::move(pendingPlan_);
64 pendingPlan_.reset();
65 return result;
66 }
67 std::optional<PieceMoveSpecialRequest> PieceMoveIngress::takeSpecial()
68 {
69 auto result = std::move(pendingSpecial_);
70 pendingSpecial_.reset();
71 return result;
72 }
73
74 std::expected<PieceMoveIngressResult, PieceMoveIngressError>
76 const actions::Message& message, bool animationsEnabled)
77 {
78 if (!movementAction(message.action))
79 return std::unexpected(PieceMoveIngressError{
81 if (pendingPlan_ || pendingSpecial_)
82 return std::unexpected(PieceMoveIngressError{
83 PieceMoveIngressErrorCode::Busy, std::nullopt});
84 if (message.numberC < 0 ||
85 message.numberC >= static_cast<std::int64_t>(rules::MaxPlayers))
86 return std::unexpected(PieceMoveIngressError{
88
89 const auto player = static_cast<rules::PlayerNumber>(message.numberC);
90 const auto before = static_cast<std::int32_t>(uiState.players[player].currentSquare);
91 const auto after64 = message.numberA;
92 if (after64 < 0 || after64 >= static_cast<std::int64_t>(rules::SquareCount))
93 return std::unexpected(plannerError(PieceMovePlanError::InvalidSquare));
94 const auto after = static_cast<std::int32_t>(after64);
95 const auto token = uiState.players[player].token;
96
97 auto planned = buildPlan(message.action, token, before, after,
98 animationsEnabled);
99 if (!planned) return std::unexpected(planned.error());
100 auto plan = std::move(*planned);
102 {
103 const auto count = static_cast<std::size_t>(uiState.numberOfPlayers);
104 if (count == 0 || count > rules::MaxPlayers)
105 return std::unexpected(PieceMoveIngressError{
107 std::size_t alreadyOffBoard{};
108 for (std::size_t i = 0; i < count; ++i)
109 if (uiState.players[i].currentSquare == 41) ++alreadyOffBoard;
110 const auto outcome = alreadyOffBoard >= count - 1 ?
112 auto offBoard = planOffBoardMove(token, before, outcome);
113 if (!offBoard) return std::unexpected(plannerError(offBoard.error()));
114 plan = std::move(*offBoard);
115 }
116
117 PieceMoveIngressResult result{};
118 result.special = plan.special;
119 result.sourceQueueLockRequired = !plan.instructions.empty() ||
121
122 if (!animationsEnabled && plan.special == PieceMoveSpecial::GoToJail)
123 {
124 uiState.players[player].currentSquare = 40;
125 result.sourceQueueLockRequired = false;
126 result.projectionUpdated = true;
127 return result;
128 }
129
130 if (plan.special == PieceMoveSpecial::GoToJail ||
132 {
133 pendingSpecial_ = PieceMoveSpecialRequest{
134 plan.special, player, token, before, after};
135 }
136 else
137 {
138 pendingPlan_ = std::move(plan);
139 result.planQueued = true;
140 }
141
142 if (after != 40)
143 {
144 uiState.players[player].currentSquare = static_cast<std::uint8_t>(after);
145 result.projectionUpdated = true;
146 }
147 return result;
148 }
149}
std::size_t count
decision::EconomicActionPlan plan
unsigned index
int token
std::string error
std::optional< PieceMoveSpecialRequest > takeSpecial()
std::expected< PieceMoveIngressResult, PieceMoveIngressError > process(rules::GameState &uiState, const actions::Message &message, bool animationsEnabled)
std::function< std::uint8_t()> RandomBitSource
std::optional< PieceMovePlan > takePlan()
std::expected< PieceMovePlan, PieceMovePlanError > planTokenMove(actions::Type notification, std::uint8_t token, std::int32_t before, std::int32_t after, bool animationsEnabled, std::span< const std::uint8_t > randomChoices)
std::expected< PieceMovePlan, PieceMovePlanError > planOffBoardMove(std::uint8_t token, std::int32_t before, OffBoardOutcome outcome)
constexpr std::size_t TokenAnimationItemLimit
std::uint8_t PlayerNumber
Definition RuleTypes.hpp:12
constexpr std::size_t SquareCount
Definition RuleTypes.hpp:24
constexpr PlayerNumber MaxPlayers
Definition RuleTypes.hpp:14