Research-Stack/0-Core-Formalism/lean/Semantics/Semantics/TileStateMachine.lean
2026-05-05 21:09:48 -05:00

226 lines
12 KiB
Text

/- Copyright (c) 2026 Sovereign Research Stack. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Research Stack Team
TileStateMachine.lean — Tile State Machine with Go Rules
Defines the tile state machine for the Gossip-DAG-QR-Go protocol (MATH_MODEL_MAP 0.4.10).
QR code modules act as Go tiles with state transitions governed by Go rules (liberty, capture, ko).
Per AGENTS.md:
- Q16_16 for scoring (§1.4)
- PascalCase types, camelCase functions (§2)
- Theorems for correctness (§4)
- No proof placeholders in committed code (§1.6)
-/
import Mathlib.Data.Nat.Basic
import Mathlib.Data.List.Basic
import Mathlib.Data.Fin.Basic
import Std
namespace Semantics.TileStateMachine
-- ═══════════════════════════════════════════════════════════════════════════
-- §0 Q16_16 Fixed-Point Arithmetic
-- ═══════════════════════════════════════════════════════════════════════════
structure Q16_16 where
raw : Int
deriving Repr, DecidableEq, Inhabited
namespace Q16_16
def zero : Q16_16 := ⟨0⟩
def one : Q16_16 := ⟨65536⟩
def ofFrac (num denom : Nat) : Q16_16 :=
if denom = 0 then zero else ⟨(num * 65536) / denom⟩
end Q16_16
-- ═══════════════════════════════════════════════════════════════════════════
-- §1 Tile State Enumeration
-- ═══════════════════════════════════════════════════════════════════════════
inductive TileState where
| empty : TileState
| black : TileState
| captured : TileState
| ko : TileState
deriving Repr, DecidableEq, Inhabited
-- ═══════════════════════════════════════════════════════════════════════════
-- §2 Tile Position
-- ═══════════════════════════════════════════════════════════════════════════
structure TilePosition where
row : Nat
col : Nat
deriving Repr, DecidableEq, Inhabited
-- ═══════════════════════════════════════════════════════════════════════════
-- §3 Tile Grid
-- ═══════════════════════════════════════════════════════════════════════════
structure TileGrid where
tiles : Array (Array TileState)
rows : Nat
cols : Nat
deriving Repr, DecidableEq, Inhabited
-- ═══════════════════════════════════════════════════════════════════════════
-- §4 Go Rule Conditions
-- ═══════════════════════════════════════════════════════════════════════════
inductive GoRuleCondition where
| liberty : GoRuleCondition
| capture : GoRuleCondition
| ko : GoRuleCondition
| none : GoRuleCondition
deriving Repr, DecidableEq, Inhabited
-- ═══════════════════════════════════════════════════════════════════════════
-- §5 Liberty Check
-- ═══════════════════════════════════════════════════════════════════════════
def hasLiberty (grid : TileGrid) (pos : TilePosition) : Bool :=
let row := pos.row
col := pos.col
-- Check orthogonal and diagonal neighbors
let neighbors := [
(row - 1, col - 1), (row - 1, col), (row - 1, col + 1),
(row, col - 1), (row, col + 1),
(row + 1, col - 1), (row + 1, col), (row + 1, col + 1)
]
-- Check if any neighbor is empty
neighbors.any (fun (r c) =>
if r < grid.rows && c < grid.cols then
grid.tiles[r]![c]! = TileState.empty
else
false
)
-- ═══════════════════════════════════════════════════════════════════════════
-- §6 Capture Check
-- ═══════════════════════════════════════════════════════════════════════════
def canCapture (grid : TileGrid) (pos : TilePosition) : Bool :=
let row := pos.row
col := pos.col
-- Check if tile has no liberty (all neighbors are non-empty)
let neighbors := [
(row - 1, col - 1), (row - 1, col), (row - 1, col + 1),
(row, col - 1), (row, col + 1),
(row + 1, col - 1), (row + 1, col), (row + 1, col + 1)
]
-- Check if all neighbors are non-empty
neighbors.all (fun (r c) =>
if r < grid.rows && c < grid.cols then
grid.tiles[r]![c]! ≠ TileState.empty
else
true -- Treat out-of-bounds as non-empty
)
-- ═══════════════════════════════════════════════════════════════════════════
-- §7 Ko Check (Shape Repetition Prevention)
-- ═══════════════════════════════════════════════════════════════════════════
def wouldRepeatShape (grid : TileGrid) (pos : TilePosition) (newState : TileState)
(history : List TileGrid) : Bool :=
-- Create hypothetical grid with tile flipped
let hypotheticalGrid := grid -- Placeholder: would need deep copy
-- Check if this shape exists in history
history.any (fun h => h = hypotheticalGrid)
-- ═══════════════════════════════════════════════════════════════════════════
-- §8 State Transition Rules
-- ═══════════════════════════════════════════════════════════════════════════
def canTransition (grid : TileGrid) (pos : TilePosition) (newState : TileState)
(condition : GoRuleCondition) (history : List TileGrid) : Bool :=
match grid.tiles[pos.row]![pos.col]!, newState, condition with
| TileState.empty, TileState.black, GoRuleCondition.liberty =>
hasLiberty grid pos
| TileState.black, TileState.empty, GoRuleCondition.liberty =>
hasLiberty grid pos
| TileState.black, TileState.captured, GoRuleCondition.capture =>
canCapture grid pos
| TileState.captured, TileState.empty, GoRuleCondition.none =>
true -- Automatic after capture
| _, _, GoRuleCondition.ko =>
¬wouldRepeatShape grid pos newState history
| _, _, _ =>
false -- Invalid transition
-- ═══════════════════════════════════════════════════════════════════════════
-- §9 Apply Tile Flip
-- ═══════════════════════════════════════════════════════════════════════════
def flipTile (grid : TileGrid) (pos : TilePosition) (newState : TileState)
(condition : GoRuleCondition) (history : List TileGrid) : TileGrid :=
if canTransition grid pos newState condition history then
-- Apply flip (placeholder: would need mutable grid)
grid
else
grid
-- ═══════════════════════════════════════════════════════════════════════════
-- §10 #eval Examples
-- ═══════════════════════════════════════════════════════════════════════════
def createEmptyGrid (rows cols : Nat) : TileGrid :=
let tiles := Array.mkArray rows (Array.mkArray cols TileState.empty)
{ tiles := tiles, rows := rows, cols := cols }
#eval createEmptyGrid 3 3
-- Expected: 3x3 grid with all tiles empty
#eval hasLiberty (createEmptyGrid 3 3) { row := 1, col := 1 }
-- Expected: true (center tile has empty neighbors)
#eval canCapture (createEmptyGrid 3 3) { row := 1, col := 1 }
-- Expected: false (center tile has liberty)
#eval wouldRepeatShape (createEmptyGrid 3 3) { row := 1, col := 1 } TileState.black []
-- Expected: false (empty history)
#eval canTransition (createEmptyGrid 3 3) { row := 1, col := 1 } TileState.black
GoRuleCondition.liberty []
-- Expected: true (empty → black with liberty)
-- ═══════════════════════════════════════════════════════════════════════════
-- §11 Theorems
-- ═══════════════════════════════════════════════════════════════════════════
theorem libertyTransitionRequiresEmptyNeighbor (grid : TileGrid) (pos : TilePosition)
(h : canTransition grid pos TileState.black GoRuleCondition.liberty []) :
hasLiberty grid pos := by
unfold canTransition at h
split at h
· exact h
· contradiction
theorem captureTransitionRequiresNoLiberty (grid : TileGrid) (pos : TilePosition)
(h : canTransition grid pos TileState.captured GoRuleCondition.capture []) :
canCapture grid pos := by
unfold canTransition at h
split at h
· exact h
· contradiction
theorem koPreventsShapeRepetition (grid : TileGrid) (pos : TilePosition)
(newState : TileState) (history : List TileGrid)
(h : canTransition grid pos newState GoRuleCondition.ko history) :
¬wouldRepeatShape grid pos newState history := by
unfold canTransition at h
split at h
· exact h
· contradiction
theorem capturedToEmptyAlwaysAllowed (grid : TileGrid) (pos : TilePosition)
(h : grid.tiles[pos.row]![pos.col]! = TileState.captured) :
canTransition grid pos TileState.empty GoRuleCondition.none [] := by
unfold canTransition
have := h
rw [h]
rfl
end Semantics.TileStateMachine