// SPDX-License-Identifier: MIT pragma solidity 0.8.30; /// @notice A public deterministic 5x5 maze. Each account has an independent route. contract MazevraPath { struct Run { uint64 round; uint32 moves; uint8 cell; bool active; } mapping(address => Run) public runs; // Rows: S.### / #.#.. / #...# / ###.# / ###.G . uint32 public constant OPEN_CELLS = (1<<0)|(1<<1)|(1<<6)|(1<<8)|(1<<9)|(1<<11)|(1<<12)|(1<<13)|(1<<18)|(1<<23)|(1<<24); event Reset(address indexed account, uint64 round); event Stepped(address indexed account, uint64 round, uint8 cell, uint32 moves, bool finished); error NotActive(); error StaleState(); error InvalidDirection(); error Wall(); function reset() external { Run storage r = runs[msg.sender]; ++r.round; r.moves = 0; r.cell = 0; r.active = true; emit Reset(msg.sender, r.round); } /// @param direction 0 north, 1 east, 2 south, 3 west. function step(uint8 direction, uint64 expectedRound, uint32 expectedMoves) external { Run storage r = runs[msg.sender]; if (!r.active) revert NotActive(); if (r.round != expectedRound || r.moves != expectedMoves) revert StaleState(); uint8 next = r.cell; if (direction == 0) { if (next < 5) revert Wall(); next -= 5; } else if (direction == 1) { if (next % 5 == 4) revert Wall(); ++next; } else if (direction == 2) { if (next >= 20) revert Wall(); next += 5; } else if (direction == 3) { if (next % 5 == 0) revert Wall(); --next; } else revert InvalidDirection(); if ((OPEN_CELLS & (uint32(1) << next)) == 0) revert Wall(); r.cell = next; ++r.moves; if (next == 24) r.active = false; emit Stepped(msg.sender, r.round, next, r.moves, !r.active); } }