Public Access
1
0
Files
WhereMyRomba/WhereMyRomba.agda

149 lines
5.4 KiB
Agda
Raw Normal View History

2026-01-02 17:52:40 +01:00
module WhereMyRomba where
open import Function
open import Data.Integer
open import Data.List
open import Data.Product
open import Data.List.Membership.Propositional
open import Data.List.Membership.DecPropositional using (_∈?_)
open import Data.List.Relation.Unary.Any using (here; there)
open import Relation.Nullary.Decidable
open import Relation.Binary.Definitions using (Decidable)
open import Relation.Binary.PropositionalEquality hiding ([_])
-- This lemma simply says that list membership for tuples of integers is decidable.
-- I.e. given a tuple of integers x, and a list of tuples of integers xs, there is an
-- algorithmn that determines wheter or not x is in xs...
lemm : (x : × ) xs Dec (x xs)
lemm = _∈?_ lemm₂
where
lemm₂ : (x y : × ) Dec (x y)
lemm₂ (x₁ , x₂) (y₁ , y₂) with x₁ y₁ | x₂ y₂
... | no h | _ = no λ{ refl h refl}
... | yes _ | no t = no λ{ refl t refl}
... | yes refl | yes refl = yes refl
data Direction : Set where
N : Direction
E : Direction
S : Direction
W : Direction
data Action : Set where
F : Action
L : Action
R : Action
-- This define a datatype for the romba state.
-- It simply consists of a direction and a position, you can use the constructor
-- `` like this: <direction> <position>
-- You can also use 𝒹 and 𝓅 to extract the direction and position.
record RombaState : Set where
constructor
__
field
𝒹 : Direction
𝓅 : ×
open RombaState
move : Direction × ×
move N (x , y) = x , y - + 1
move E (x , y) = x + + 1 , y
move S (x , y) = x , y + + 1
move W (x , y) = x - + 1 , y
turnLeft : Direction Direction
turnLeft N = W
turnLeft E = N
turnLeft S = E
turnLeft W = S
-- Turning right is the same as turning left 3 times :-)
turnRight = turnLeft turnLeft turnLeft
{-
This function is where the important stuff happens, it describes a single movement
of the romba, reacting to possible obstacles.
In this function we encode a basic invariant: The romba is assumed to not be inside
an obstacle! Given this assumption, we also prove that the romba won't end up inside a
wall.
-}
step : Action -- Given an action,
(obstacles : List ( × )) -- a set of obstacles
(s₁ : RombaState) -- a romba state,
𝓅 s₁ obstacles -- and a proof that the romba isn't inside an obstacle.
Σ RombaState (λ s₂ 𝓅 s₂ obstacles) -- Returns a new romba state, and a proof that it still isn't
-- on an obstacle.
{-
With is like a `case .. of`. Here we use the with to check wheter or not moving the
romba in its current direction would place it inside an obstacle, i.e. if it's new
position would be an element in the list of obstacles. This is what we need the
lemma for.
-}
step F obstacles (𝒹 𝓅) h with lemm (move 𝒹 𝓅) obstacles
-- If moving it would not place it inside an obstacle, then we know... well, that
-- moving it would not place it inside an obstacle of course! This the proof that
-- the variable `t` contains.
... | no t = 𝒹 move 𝒹 𝓅 , t
-- Othewise, we simply don't move, and use the fact the we are not currently inside
-- and obstecla to prove that we will not end up inside and obstale (`h`)
... | yes _ = 𝒹 𝓅 , h
step L obstacles (𝒹 𝓅) h = turnLeft 𝒹 𝓅 , h
step R obstacles (𝒹 𝓅) h = turnRight 𝒹 𝓅 , h
-- In romba' and romba we just chain a bunch of `step` calls together.
romba' : (s₁ : RombaState)
(obstacles : List ( × ))
(𝓅 s₁ obstacles)
List Action
Σ RombaState (λ s₂ 𝓅 s₂ obstacles)
romba' s₁ obstacles h [] = s₁ , h
romba' s₁ obstacles h (action actions) =
let
s₂ , t = step action obstacles s₁ h
in
romba' s₂ obstacles t actions
romba : (obstacles : List ( × ))
(+ 0 , + 0) obstacles
List Action
RombaState
romba obstacles h actions = proj₁ (romba' (N (+ 0 , + 0)) obstacles h actions)
-- Examples
-- For example, if the robot starts at (0, 0) and faces north, moving forward would
-- place it at (0, -1)
ex₀ : move N (+ 0 , + 0) (- + 0 , - + 1)
ex₀ = refl
-- For example, if the robot starts at (0, 0) and faces north, moving forward
-- would place it at (0, -1). If it turned right and moved forward again, it
-- would be at (1, -1)
ex₁ : move (turnRight N) (move N (+ 0 , + 0)) (+ 1 , - + 1)
ex₁ = refl
-- Actions: "FRFFRFFRFFRF"
-- Obstacles: No obstacles
-- Expected: (0, 0)
ex₂ : 𝓅 (romba [] (λ()) (F R F F R F F R F F R F [])) (+ 0 , + 0)
ex₂ = refl
-- Actions: "FRFFRFF"
-- Obstacles: (0, -1)
-- Expected: (2, 2)
ex₃ : 𝓅 (romba [ + 0 , - + 1 ] (λ{ (here ()); (there ())}) (F R F F R F F [])) (+ 2 , + 2)
ex₃ = refl
-- Actions: "FRFRRFLF"
-- Obstacles: (0, -1), (1, 0)
-- Expected: (-1, 1)
ex₄ : 𝓅 (romba ((+ 0 , - + 1) (+ 1 , + 0) []) (λ{ (there (here ()))}) (F R F R R F L F [])) (- + 1 , + 1)
ex₄ = refl