even more gruesome refactoring

This commit is contained in:
Richard Harrington 2013-08-02 17:48:32 -04:00
parent 9112c82dc6
commit 134d5ac439
2 changed files with 100 additions and 53 deletions

View File

@ -10,21 +10,28 @@
(-> op read-string eval))) (-> op read-string eval)))
op-commands))) op-commands)))
(defn init-register [reg-name read write data] (defn init-register [reg-name read-func write-func data]
{reg-name {:read read "the read function should take a world and return a value.
:write write the write function should take a world and a value and return
:data data}}) a new world."
{reg-name {:read read-func
:write write-func
:val data}})
(defn default-read [data world] (defn read-register
data) "wrapper for the read function in each register. takes a register
and also takes world state, because
some of those functions may need access to the world state.
returns a numeric value."
[{read :read} world]
(read world))
(defn default-write [robot data] (defn write-register
(assoc-in robot [:brain :registers reg-name] data)) "wrapper for the write function in each register.
takes a register, a robot, a world, and the data to write.
(def default-data 0) returns a full world."
[{write :write} world data]
(defn default-register [reg-name] (write world data))
(init-register reg-name default-read default-write default-data))
(defn init-brain (defn init-brain
"initialize the brain (meaning all the internal state variables that go along "initialize the brain (meaning all the internal state variables that go along
@ -38,22 +45,6 @@
:program program :program program
:registers (into {} (concat (map default-register reg-names) registers))}) :registers (into {} (concat (map default-register reg-names) registers))})
(defn read-register
"wrapper for the read function in each register. takes a register
and also takes world state, because
some of those functions may need access to the world state.
returns a numeric value."
[{:keys [read data] :as register} world]
(read data world))
(defn write-register
"wrapper for the write function in each register.
takes a robot, a register, and the data to write.
returns a full robot (brain and external properties as well).
TODO: implement extra flag to indicate if we've fired a shot."
[robot {write :write :as register} data]
(write robot data))
(defn resolve-arg [{arg-val :val arg-type :type} registers labels world] (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)."
@ -63,38 +54,38 @@
:register (read-register (registers arg-val) world) :register (read-register (registers arg-val) world)
nil)) nil))
(defn tick-brain (defn step-brain
"takes a full robot. Only the internal state (the brain) will be "takes a robot index and a world. Returns a world.
different when we pass it back, for all of the operations except 'TO',
which may alter the external state of the robot as well. (And for the time
being, shots fired will be indicated with a flag in the robot.)
Also takes a 'world' parameter, which may contain information that some of the Read functions may or may not need anything except the brain.
registers' read functions may need. Will not be passed out in the return value.
TODO: Figure out a way to have this function not know about the external robot stuff, Only the brain (the internal state of the robot)
will be different when we pass it back, for all of the operations
except 'TO', which may also alter the external state of the robot, or the wider world.
TODO: Figure out a way to have this function not know about the external stuff,
like that the name of the field leading to the brain is :brain." like that the name of the field leading to the brain is :brain."
[robot world] [robot-idx world]
(let [brain (:brain robot) (let [{brain :brain :as robot} ((:robots world) robot-idx)
{:keys [acc instr-ptr call-stack registers program]} brain {:keys [acc instr-ptr call-stack registers program]} brain
[{command :val} arg] ((:instrs program) instr-ptr) [{command :val} arg] ((:instrs program) instr-ptr)
resolve #(resolve-arg % registers (:labels program) world) resolve #(resolve-arg % registers (:labels program) world)
return-robot #(assoc robot :brain (into brain %))] into-world-brain #(assoc-in world [:robots robot-idx :brain] (into brain %))]
(case command (case command
"GOTO" (return-robot {:instr-ptr (resolve arg)}) "GOTO" (into-world-brain {:instr-ptr (resolve arg)})
"GOSUB" (return-robot {:instr-ptr (resolve arg) "GOSUB" (into-world-brain {:instr-ptr (resolve arg)
:call-stack (conj call-stack (inc instr-ptr))}) :call-stack (conj call-stack (inc instr-ptr))})
"ENDSUB" (return-robot {:instr-ptr (peek call-stack) "ENDSUB" (into-world-brain {:instr-ptr (peek call-stack)
:call-stack (pop call-stack)}) :call-stack (pop call-stack)})
("IF", ",") (return-robot {:instr-ptr (inc instr-ptr) ("IF", ",") (into-world-brain {:instr-ptr (inc instr-ptr)
:acc (resolve arg)}) :acc (resolve arg)})
("+" "-" "*" "/") (return-robot {:instr-ptr (inc instr-ptr) ("+" "-" "*" "/") (into-world-brain {: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))
(return-robot {:instr-ptr (inc instr-ptr)}) (into-world-brain {:instr-ptr (inc instr-ptr)})
(return-robot {:instr-ptr (+ instr-ptr 2)})) (into-world-brain {:instr-ptr (+ instr-ptr 2)}))
"TO" (write-register (return-robot {:instr-ptr (inc instr-ptr)}) "TO" (write-register (into-world-brain {:instr-ptr (inc instr-ptr)})
(registers (:val arg)) (registers (:val arg))
acc)))) acc))))

View File

@ -20,6 +20,62 @@
; A BIT CLEARER. THE NAMES CAN BE SHORTENED QUITE A BIT, ; A BIT CLEARER. THE NAMES CAN BE SHORTENED QUITE A BIT,
; WHEN LOADED INTO THE MODULES. ; WHEN LOADED INTO THE MODULES.
(defn make-default-read [register]
"takes a register and returns the default version of its :read function,
which ignores the `world` parameter and just returns
the :val field from the register."
(fn [_]
(:val register)))
(defn make-default-write [robot-idx reg-name]
"takes a robot-idx and a reg-name to locate a register, and
returns the default version of that register's :write function,
which takes a world parameter and a data value and returns the
world with the data value assoc'd into it."
(fn [world data]
(assoc-in world [:robots robot-idx :registers reg-name :val] data)))
(def default-data 0)
(defn default-register [robot-idx reg-name]
(init-register
reg-name
(defn init-robot
[program x y]
{:pos-x x
:pos-y y
:veloc-x 0
:veloc-y 0
:accel-x 0
:accel-y 0
:damage 100
:
[let [special-registers
[init-register "X" default-
(defn init-world
"initialize all the variables for a robot world"
[width height programs]
{:width width
:height height
:shells []
:robots (vec (map-indexed (fn [idx program]
{:brain (init-brain
program
reg-names
{(init-register "X"
default-read
default-write
(rand-int width))
(init-register "Y"
default-read
default-write
(rand-int height))})
:icon (str idx)})
programs))})
(defn tick-robot (defn tick-robot
[robot world] [robot world]
(let [ticked (tick-brain robot world)] (let [ticked (tick-brain robot world)]