living on hope

This commit is contained in:
Richard Harrington 2013-08-01 16:13:20 -04:00
parent 08dcf38214
commit 4a8f83ad95

View File

@ -13,23 +13,53 @@
(-> op read-string eval))) (-> op read-string eval)))
op-commands))) op-commands)))
(defn init-internal-state
"initialize all the internal state variables that go along
with the robot program when it's running.
(Optionally, also pass in a hash-map of register names and values,
which will override the defaults)."
[program reg-names & [registers]]
{:registers (into {} (concat
(for [reg-name reg-names]
; default values for :read, :write and :data. (TODO: move these into a higher-level module)
; NOTE: the default version of the :read function does not need the world-state parameter.
[reg-name {:read (fn [data _] data)
:write (fn [robot data]
(assoc-in robot [:internal-state :registers reg-name] data))
:data 0}])
registers))
:program program
:acc 0
:instr-ptr 0
:call-stack []})
(defn read-register
"returns a numeric value"
[{:keys [read data] :as register} world]
(read data world))
(defn write-register
"returns a full robot state, including its external state and its internal brain state.
TODO: implement extra flag to indicate if we've fired a shot."
[robot {write :write :as register} data]
(write robot data))
(defn resolve-register [registers reg] (defn resolve-register [registers reg]
(case reg (case reg
"RANDOM" (rand-int (registers reg)) "RANDOM" (rand-int (registers reg))
"DATA" (registers (reg-names (registers "INDEX"))) "DATA" (registers (reg-names (registers "INDEX")))
(registers reg))) (registers reg)))
(defn resolve-arg [{arg-val :val arg-type :type} registers labels] (defn resolve-arg [{arg-val :val arg-type :type} registers labels world]
"resolves an instruction argument to a numeric value "resolves an instruction argument to a numeric value
(either an arithmetic or logical comparison operand, or an instruction pointer)." (either an arithmetic or logical comparison operand, or an instruction pointer).
If it's reading from a register, uses that register's :read function."
(case arg-type (case arg-type
:label (labels arg-val) :label (labels arg-val)
:number arg-val :number arg-val
:register (resolve-register registers arg-val) :register (read-register (registers arg-val) world)
nil)) nil))
(def registers-with-effect-on-world #{"SHOT" "RADAR" "SPEEDX" "SPEEDY"})
(defn tick-robot (defn tick-robot
"takes as input a data structure representing all that the robot's brain "takes as input a data structure representing all that the robot's brain
needs to know about the world: needs to know about the world:
@ -47,36 +77,26 @@
plus an optional :action field, to notify the world if the SHOT, SPEEDX, SPEEDY or RADAR plus an optional :action field, to notify the world if the SHOT, SPEEDX, SPEEDY or RADAR
registers have been pushed to." registers have been pushed to."
[{:keys [acc instr-ptr call-stack registers program] :as state}] [robot world]
(let [[{command :val} {unresolved-arg-val :val :as arg}] ((program :instrs) instr-ptr) (let [internal-state (:internal-state robot)
resolve #(resolve-arg % registers (program :labels))] {:keys [acc instr-ptr call-stack registers program]} internal-state
[{command :val} {unresolved-arg-val :val :as arg}] ((program :instrs) instr-ptr)
resolve #(resolve-arg % registers (program :labels) world)
return-robot #(assoc robot :internal-state (into internal-state %))]
(case command (case command
"GOTO" (into state {:instr-ptr (resolve arg)}) "GOTO" (return-robot {:instr-ptr (resolve arg)})
"GOSUB" (into state {:instr-ptr (resolve arg) "GOSUB" (return-robot {:instr-ptr (resolve arg)
:call-stack (conj call-stack (inc instr-ptr))}) :call-stack (conj call-stack (inc instr-ptr))})
"ENDSUB" (into state {:instr-ptr (peek call-stack) "ENDSUB" (return-robot {:instr-ptr (peek call-stack)
:call-stack (pop call-stack)}) :call-stack (pop call-stack)})
("IF", ",") (into state {:instr-ptr (inc instr-ptr) ("IF", ",") (return-robot {:instr-ptr (inc instr-ptr)
:acc (resolve arg)}) :acc (resolve arg)})
("+" "-" "*" "/") (into state {:instr-ptr (inc instr-ptr) ("+" "-" "*" "/") (return-robot {:instr-ptr (inc instr-ptr)
:acc ((op-map command) acc (resolve arg))}) :acc ((op-map command) acc (resolve arg))})
("=" ">" "<" "#") (if ((op-map command) acc (resolve arg)) ("=" ">" "<" "#") (if ((op-map command) acc (resolve arg))
(into state {:instr-ptr (inc instr-ptr)}) (return-robot {:instr-ptr (inc instr-ptr)})
(into state {:instr-ptr (+ instr-ptr 2)})) (return-robot {:instr-ptr (+ instr-ptr 2)}))
"TO" (let [return-state (into state {:instr-ptr (inc instr-ptr) "TO" (write-register (return-robot {:instr-ptr (inc instr-ptr)})
:registers (into registers {unresolved-arg-val acc})})] (registers unresolved-arg-val)
(if (registers-with-effect-on-world unresolved-arg-val) acc))))
(conj return-state {:action unresolved-arg-val})
return-state)))))
(defn init-robot-state
"initialize all the state variables that go along
with the robot program when it's running.
(Optionally, pass in a hash-map of register names and values)."
[program reg-names & [registers]]
{:program program
:acc 0
:instr-ptr 0
:registers (into (zipmap reg-names (repeat 0))
registers)
:call-stack []})