{-# Language Trustworthy #-}
module Intcode.Machine
(
Machine(..), new,
jmp, addRelBase,
(!), set, memoryList,
)
where
import Data.IntMap (IntMap)
import qualified Data.IntMap as IntMap
import qualified Data.Primitive.PrimArray as P
data Machine = Machine
{ Machine -> Int
pc :: !Int
, Machine -> Int
relBase :: !Int
, Machine -> IntMap Int
memUpdates :: !(IntMap Int)
, Machine -> PrimArray Int
memInitial :: {-# Unpack #-} !(P.PrimArray Int)
}
deriving (Machine -> Machine -> Bool
(Machine -> Machine -> Bool)
-> (Machine -> Machine -> Bool) -> Eq Machine
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: Machine -> Machine -> Bool
== :: Machine -> Machine -> Bool
$c/= :: Machine -> Machine -> Bool
/= :: Machine -> Machine -> Bool
Eq, Eq Machine
Eq Machine =>
(Machine -> Machine -> Ordering)
-> (Machine -> Machine -> Bool)
-> (Machine -> Machine -> Bool)
-> (Machine -> Machine -> Bool)
-> (Machine -> Machine -> Bool)
-> (Machine -> Machine -> Machine)
-> (Machine -> Machine -> Machine)
-> Ord Machine
Machine -> Machine -> Bool
Machine -> Machine -> Ordering
Machine -> Machine -> Machine
forall a.
Eq a =>
(a -> a -> Ordering)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> a)
-> (a -> a -> a)
-> Ord a
$ccompare :: Machine -> Machine -> Ordering
compare :: Machine -> Machine -> Ordering
$c< :: Machine -> Machine -> Bool
< :: Machine -> Machine -> Bool
$c<= :: Machine -> Machine -> Bool
<= :: Machine -> Machine -> Bool
$c> :: Machine -> Machine -> Bool
> :: Machine -> Machine -> Bool
$c>= :: Machine -> Machine -> Bool
>= :: Machine -> Machine -> Bool
$cmax :: Machine -> Machine -> Machine
max :: Machine -> Machine -> Machine
$cmin :: Machine -> Machine -> Machine
min :: Machine -> Machine -> Machine
Ord, Int -> Machine -> ShowS
[Machine] -> ShowS
Machine -> String
(Int -> Machine -> ShowS)
-> (Machine -> String) -> ([Machine] -> ShowS) -> Show Machine
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> Machine -> ShowS
showsPrec :: Int -> Machine -> ShowS
$cshow :: Machine -> String
show :: Machine -> String
$cshowList :: [Machine] -> ShowS
showList :: [Machine] -> ShowS
Show)
indexImage ::
Machine ->
Int ->
Int
indexImage :: Machine -> Int -> Int
indexImage Machine
m Int
i
| Int
i Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
< PrimArray Int -> Int
forall a. Prim a => PrimArray a -> Int
P.sizeofPrimArray PrimArray Int
a, Int
0 Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
<= Int
i = PrimArray Int -> Int -> Int
forall a. Prim a => PrimArray a -> Int -> a
P.indexPrimArray PrimArray Int
a Int
i
| Bool
otherwise = Int
0
where
a :: PrimArray Int
a = Machine -> PrimArray Int
memInitial Machine
m
{-# INLINE indexImage #-}
(!) ::
Machine ->
Int ->
Int
Machine
m ! :: Machine -> Int -> Int
! Int
i = Int -> Int -> IntMap Int -> Int
forall a. a -> Int -> IntMap a -> a
IntMap.findWithDefault (Machine -> Int -> Int
indexImage Machine
m Int
i) Int
i (Machine -> IntMap Int
memUpdates Machine
m)
{-# INLINE (!) #-}
new ::
[Int] ->
Machine
new :: [Int] -> Machine
new [Int]
initialValues = Machine
{ pc :: Int
pc = Int
0
, relBase :: Int
relBase = Int
0
, memUpdates :: IntMap Int
memUpdates = IntMap Int
forall a. IntMap a
IntMap.empty
, memInitial :: PrimArray Int
memInitial = [Int] -> PrimArray Int
forall a. Prim a => [a] -> PrimArray a
P.primArrayFromList [Int]
initialValues
}
set ::
Int ->
Int ->
Machine -> Machine
set :: Int -> Int -> Machine -> Machine
set Int
i Int
v Machine
m
| Int
v Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
== Int
o = Machine
m { memUpdates = IntMap.delete i (memUpdates m) }
| Bool
otherwise = Machine
m { memUpdates = IntMap.insert i v (memUpdates m) }
where
o :: Int
o = Machine -> Int -> Int
indexImage Machine
m Int
i
addRelBase ::
Int ->
Machine -> Machine
addRelBase :: Int -> Machine -> Machine
addRelBase Int
i Machine
mach = Machine
mach { relBase = relBase mach + i }
{-# INLINE addRelBase #-}
jmp ::
Int ->
Machine -> Machine
jmp :: Int -> Machine -> Machine
jmp Int
i Machine
mach = Machine
mach { pc = i }
{-# INLINE jmp #-}
memoryList ::
Machine ->
[Int]
memoryList :: Machine -> [Int]
memoryList Machine
mach
| IntMap Int -> Bool
forall a. IntMap a -> Bool
IntMap.null (Machine -> IntMap Int
memUpdates Machine
mach) = PrimArray Int -> [Int]
forall a. Prim a => PrimArray a -> [a]
P.primArrayToList (Machine -> PrimArray Int
memInitial Machine
mach)
| Bool
otherwise = [Machine
mach Machine -> Int -> Int
! Int
i | Int
i <- [Int
0 .. Int
top]]
where
top :: Int
top = Int -> Int -> Int
forall a. Ord a => a -> a -> a
max (PrimArray Int -> Int
forall a. Prim a => PrimArray a -> Int
P.sizeofPrimArray (Machine -> PrimArray Int
memInitial Machine
mach) Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
1)
((Int, Int) -> Int
forall a b. (a, b) -> a
fst (IntMap Int -> (Int, Int)
forall a. IntMap a -> (Int, a)
IntMap.findMax (Machine -> IntMap Int
memUpdates Machine
mach)))