Repository navigation
Expand file tree
/
Copy pathgame_state.cpp
More file actions
150 lines (128 loc) · 4.97 KB
/
Copy pathgame_state.cpp
File metadata and controls
150 lines (128 loc) · 4.97 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
// GameState 实现:状态机,编排 Snake + Fruit,判定胜负。
// 坐标系约定:核心 0 基坐标 Position{x=列, y=行},x∈[0,width),y∈[0,height);
// 与日志 1 基「行×列」的换算由集成层负责(见 DESIGN.md §3 / log_entry 注释)。
//
// 初始布局(由实现决定):蛇初始长度为 1(仅蛇头),位于棋盘中心,
// 默认朝向上方;首个果实随即随机放置在空闲格。
#include "core/game_state.hpp"
#include <cstdint>
#include <vector>
namespace snake::core {
namespace {
// 收集当前未被蛇占据的空闲格(行优先顺序),供 Fruit::respawn 使用。
// Args:
// width/height: 棋盘尺寸。
// s: 蛇(其身体占据的格子被排除)。
// Returns: 空闲格列表;棋盘被填满时为空。
std::vector<Position> CollectFreeCells(std::int32_t width, std::int32_t height,
const Snake& s) {
std::vector<Position> cells;
cells.reserve(static_cast<std::size_t>(width) *
static_cast<std::size_t>(height));
for (std::int32_t y = 0; y < height; ++y) {
for (std::int32_t x = 0; x < width; ++x) {
const Position p{x, y};
if (!s.occupies(p)) cells.push_back(p);
}
}
return cells;
}
} // namespace
// 构造:放置初始蛇(中心、朝上、长度 1)并随机生成首个果实。
// 若棋盘为空闲格放置失败(例如 1×1 棋盘被蛇头占满),直接判胜。
GameState::GameState(std::int32_t width, std::int32_t height, std::uint32_t seed)
: width_(width),
height_(height),
snake_(Position{width / 2, height / 2}, Direction::Up),
rng_(seed) {
if (!fruit_.respawn(CollectFreeCells(width_, height_, snake_), rng_)) {
phase_ = Phase::Won; // 初始即填满棋盘
}
}
std::int32_t GameState::width() const noexcept {
return width_;
}
std::int32_t GameState::height() const noexcept {
return height_;
}
Phase GameState::phase() const noexcept {
return phase_;
}
// 得分 = 蛇长 - 初始长(本实现初始长度为 1)。
std::size_t GameState::score() const noexcept {
return snake_.length() - 1;
}
const Snake& GameState::snake() const noexcept {
return snake_;
}
const Fruit& GameState::fruit() const noexcept {
return fruit_;
}
// 转发转向请求;Snake::turn 内部拒绝 180° 掉头。对局结束后忽略输入。
void GameState::request_turn(Direction d) noexcept {
if (phase_ == Phase::Running) {
snake_.turn(d);
}
}
// 推进一个游戏节拍:墙/自碰判定 → 移动/生长 → 果实判定与重放 → 状态迁移。
// 每次调用只允许发生在 Running 期间;结束时返回的快照不再变化。
TickResult GameState::tick() noexcept {
TickResult r;
r.phase = phase_;
if (phase_ != Phase::Running) {
// 已结束:返回冻结快照,不再推进。
r.head = snake_.head();
r.moved = snake_.facing();
r.fruit = fruit_.position();
r.fruit_exists = fruit_.exists();
return r;
}
const Position next = snake_.head().advanced(snake_.facing());
r.moved = snake_.facing();
// 1) 撞墙:下一格越界 ⇒ Lost(不移动)。
if (next.x < 0 || next.x >= width_ || next.y < 0 || next.y >= height_) {
phase_ = Phase::Lost;
r.phase = Phase::Lost;
r.head = snake_.head();
r.fruit = fruit_.position();
r.fruit_exists = fruit_.exists();
return r;
}
// 2) 吃果实判定:下一格是否正好是果实。
const bool will_eat = fruit_.exists() && fruit_.position() == next;
if (will_eat) {
fruit_.consume();
snake_.grow(); // 本 tick 保留尾部(长度 +1)
r.ate_fruit = true;
}
// 3) 自碰判定:按当前朝向再走一步会否咬到身体。
// 吃果时蛇将生长、尾部不弹走;self_collision_next 依据
// pending_growth 内部标志决定是否排除尾格,因此需在 grow 之后判定。
if (snake_.self_collision_next()) {
phase_ = Phase::Lost;
r.phase = Phase::Lost;
r.head = snake_.head();
r.fruit = fruit_.position();
r.fruit_exists = fruit_.exists();
return r;
}
// 4) 前进一步(若刚 grow 则保留尾部 ⇒ 长度 +1)。
snake_.move();
r.head = snake_.head();
// 5) 吃果后重放果实:无空闲格说明棋盘已被填满 ⇒ Won。
if (will_eat) {
const auto placed = fruit_.respawn(
CollectFreeCells(width_, height_, snake_), rng_);
r.fruit_exists = placed.has_value();
if (placed) r.fruit = *placed;
if (!r.fruit_exists) {
phase_ = Phase::Won;
r.phase = Phase::Won;
}
} else {
r.fruit = fruit_.position();
r.fruit_exists = fruit_.exists();
}
return r;
}
} // namespace snake::core