Public Access
Games: Pong, Snake and Tetris as seeded state machines, and a tune
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
This commit is contained in:
@@ -0,0 +1,60 @@
|
||||
#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
|
||||
Reference in New Issue
Block a user