2010年6月13日日曜日

ICFP 2009 orbit controller

After setting up the infrastructure (binary reader, vm, visualizer), the controllers will be the part where the actual problems are solved.

For now, I won't solve any of the actual problems, I will just introduce the controller framework to show how it can be done. Here's the code:



(ns orbit-controllers
(:use orbit-plotter orbit-util)
(:import (java.awt Color)))

(def *earth-mass* 6e24)
(def *earth-radius* 6.357e6)

(def *the-earth* (struct orbit-object 0 0 *earth-radius* Color/BLUE))

(defn example-controller
"A controller that only initiliazes the scenario to 1003, returns some random stats and space objects,
but otherwise does nothing and is meant to act as an example of a minimal controller.

A controller is a function that gets called by the vm. The parameters are the inputs from last round
(inputs are what you communicate to the vm, like thrust values) and the outputs (they allow you to
read your x/y coordinates, fuel level, score etc.).
The controller has to return a vector
[new-inputs objects stats]
where new-inputs is a map of the vm input ports you want to write, objects is a name/orbit-object map
of space objects to be plotted by the visualizer, and stats is a list of key-value pairs to be displayed
in the stats table of the visualizer."

[inputs outputs]
(let [new-inputs (if (inputs 0x3e80) inputs (assoc inputs 0x3e80 1003))
objects { :earth *the-earth*
:random-satellite (struct orbit-object *earth-radius* *earth-radius* (/ *earth-radius* 32) Color/YELLOW) }
stats [[ "r" 1.234] ["x" 2.345] ["y" 3.456]]]
[new-inputs objects stats]))

(defn create-hohmann-controller
"Creates a controller for one of the Hohmann scenarios - this is just the framework needed to solve the problem.
So what's missing now is calculation of velocity/position/acceleration to calculate the (at least) 2 thrusts needed."

[scenario]
; close over state used inside the controller
(let [history (atom ())
memory (atom {})
last-update (atom nil)]
(fn [inputs outputs]
(let [delta-x (outputs 2 0) delta-y (outputs 3 0)
new-inputs (if-not (inputs 0x3e80) ; not yet initialized?
(assoc inputs 0x3e80 scenario) ; initialize scenario
(if (zero? (inputs 3 0)) ; currently we are not thrusting (in the y-axis)
(if-not (@memory :last-thrust-x) ; we haven't thrusted yet, so let's do it
(let [thrust-x 1000 thrust-y -1000]
(swap! memory assoc :last-thrust-x thrust-x :last-thrust-y thrust-y)
(assoc (assoc inputs 3 thrust-y) 2 thrust-x))
inputs) ; we have thrusted before - don't change
(assoc (assoc inputs 3 0) 2 0))) ; stop thrusting
now (System/nanoTime)
last @last-update
ups (if last (/ 1e9 (- now last)) -1)
objects { :earth *the-earth*, :satellite (struct orbit-object delta-x delta-y (/ *earth-radius* 64) Color/YELLOW) }
stats (partition 2 [ "r" (hypot delta-x delta-y)
"x" delta-x
"y" delta-y
"ups" ups])]
(reset! last-update now)
[new-inputs objects stats]))))

0 件のコメント:

コメントを投稿

フォロワー