Public Access
The rules of the three Games (issue #101), with no screen and no keyboard in them: time and keys go in, the new state and what happened come out, and a seed decides the dice. With a player for a tune a note at a time, and Korobeiniki's notes. Host-tested. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0162FokPdvY2KsS4NBfwyWPk
61 lines
2.0 KiB
C++
61 lines
2.0 KiB
C++
#pragma once
|
|
|
|
#include <array>
|
|
#include <cstddef>
|
|
#include <cstdint>
|
|
#include <deque>
|
|
|
|
#include "game_rng.h"
|
|
|
|
namespace roro::games {
|
|
|
|
// Snake (issue #101): a field of 38 x 19 cells, the walls and its own body kill it, and it goes
|
|
// faster as it eats. Time comes in from outside, in milliseconds.
|
|
class Snake {
|
|
public:
|
|
static constexpr int kCols = 38, kRows = 19;
|
|
static constexpr uint32_t kSlowestMs = 150, kFastestMs = 60, kFasterMs = 5;
|
|
static constexpr int kFoodsAStep = 3; // it gets faster every so many
|
|
|
|
enum class Dir : uint8_t { Up, Right, Down, Left };
|
|
enum Event : uint8_t { Moved = 1, Ate = 2, Died = 4 };
|
|
struct Cell {
|
|
int8_t col, row;
|
|
bool operator==(const Cell& o) const { return col == o.col && row == o.row; }
|
|
};
|
|
|
|
explicit Snake(uint32_t seed) : rng_(seed) { start(); }
|
|
void start();
|
|
// A turn asked for; it is taken at the next move. Two are remembered, so a quick corner (up,
|
|
// then left) works; turning back on itself is not a turn.
|
|
void turn(Dir dir);
|
|
uint8_t step(uint32_t ms);
|
|
|
|
bool alive() const { return alive_; }
|
|
int score() const { return score_; } // foods eaten
|
|
const std::deque<Cell>& body() const { return body_; } // the head first
|
|
Cell food() const { return food_; }
|
|
Dir heading() const { return dir_; }
|
|
uint32_t intervalMs() const; // between two moves, now
|
|
// For the tests: the food put where one wants it.
|
|
void putFood(Cell at) { food_ = at; }
|
|
|
|
private:
|
|
bool taken(Cell c) const { return taken_[static_cast<size_t>(c.row * kCols + c.col)]; }
|
|
void mark(Cell c, bool on) { taken_[static_cast<size_t>(c.row * kCols + c.col)] = on; }
|
|
void placeFood();
|
|
uint8_t move();
|
|
|
|
Rng rng_;
|
|
std::deque<Cell> body_;
|
|
std::array<bool, kCols * kRows> taken_{};
|
|
Cell food_{0, 0};
|
|
Dir dir_ = Dir::Right;
|
|
Dir turns_[2] = {Dir::Right, Dir::Right};
|
|
int turnCount_ = 0, score_ = 0;
|
|
uint32_t sinceMs_ = 0;
|
|
bool alive_ = true;
|
|
};
|
|
|
|
} // namespace roro::games
|