Add WhereMyRomba.agda
This commit is contained in:
148
WhereMyRomba.agda
Normal file
148
WhereMyRomba.agda
Normal file
@@ -0,0 +1,148 @@
|
||||
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
|
||||
Reference in New Issue
Block a user