comparison clojure/com/aurellem/gb_driver.clj @ 87:e8855121f413

collect cruft, rename other files
author Robert McIntyre <rlm@mit.edu>
date Sat, 10 Mar 2012 14:48:17 -0600
parents 95cb2152d7cd
children 65c2854c5875
comparison
equal deleted inserted replaced
86:9864032ef3c8 87:e8855121f413
1 (ns com.aurellem.gb-driver 1 (ns com.aurellem.gb-driver
2 (:import com.aurellem.gb.Gb) 2 (:import com.aurellem.gb.Gb)
3 (:import java.io.File) 3 (:import java.io.File)
4 (:import org.apache.commons.io.FileUtils) 4 (:import org.apache.commons.io.FileUtils)
5 (:import (java.nio IntBuffer ByteOrder))) 5 (:import (java.nio IntBuffer ByteOrder)))
6 6
7 (Gb/loadVBA) 7 ;; Savestates
8 8 (defrecord SaveState [frame data])
9 (def ^:dynamic *max-history* 2e4)
10
11 (def ^:dynamic *backup-saves-to-disk* true)
12
13 (def ^:dynamic *save-history* true)
14 9
15 (def ^:dynamic *save-state-cache* 10 (def ^:dynamic *save-state-cache*
16 (File. "/home/r/proj/pokemon-escape/save-states/")) 11 (File. "/home/r/proj/pokemon-escape/save-states/"))
12
13 (defn frame->filename [frame]
14 (File. *save-state-cache* (format "%07d.sav" frame)))
15
16 (defn write-save! [^SaveState save]
17 (let [buf (:data save)
18 bytes (byte-array (.limit buf))
19 dest (frame->filename (:frame save))]
20 (.get buf bytes)
21 (FileUtils/writeByteArrayToFile dest bytes)
22 (.rewind buf)
23 save))
24
25 (defn read-save [frame]
26 (let [save (frame->filename frame)]
27 (if (.exists save)
28 (let [buf (Gb/saveBuffer)
29 bytes (FileUtils/readFileToByteArray save)]
30 (.put buf bytes)
31 (.flip buf)
32 (SaveState. frame buf)))))
33 ;;;;;;;;;;;;;;;;
34
35 ;; Gameboy management
36 (Gb/loadVBA)
17 37
18 (def yellow-rom-image 38 (def yellow-rom-image
19 (File. "/home/r/proj/pokemon-escape/roms/yellow.gbc")) 39 (File. "/home/r/proj/pokemon-escape/roms/yellow.gbc"))
20 40
21 (def yellow-save-file 41 (def yellow-save-file
22 (File. "/home/r/proj/pokemon-escape/roms/yellow.sav")) 42 (File. "/home/r/proj/pokemon-escape/roms/yellow.sav"))
23 43
24 (def current-frame (atom 0)) 44 (def on? (atom nil))
25 45
26 (defn vba-init [] 46 (defn shutdown! [] (Gb/shutdown) (reset! on? false))
27 (reset! current-frame 0) 47
48 (defn restart! []
49 (shutdown!)
28 (.delete yellow-save-file) 50 (.delete yellow-save-file)
29 (Gb/startEmulator (.getCanonicalPath yellow-rom-image))) 51 (Gb/startEmulator (.getCanonicalPath yellow-rom-image))
52 (reset! on? true))
30 53
31 (defn shutdown [] (Gb/shutdown)) 54 ;;; The first state!
55 (defn gen-root! []
56 (restart!)
57 (write-save! (SaveState. 0 (Gb/saveState))))
32 58
33 (defn reset [] (shutdown) (vba-init)) 59 (defn root []
60 (if (.exists (frame->filename 0))
61 (read-save 0)
62 (gen-root!)))
63
64 ;;;; Press Buttons
65
66 (def button-code
67 {;; main buttons
68 :a 0x0001
69 :b 0x0002
70
71 ;; directional pad
72 :r 0x0010
73 :l 0x0020
74 :u 0x0040
75 :d 0x0080
76
77 ;; meta buttons
78 :select 0x0004
79 :start 0x0008
80
81 ;; pseudo-buttons
82 :restart 0x0800 ; hard reset
83 :listen -1 ; listen for user input
84 })
85
86 (defn button-mask [buttons]
87 (reduce bit-or 0x0000 (map button-code buttons)))
88
89 (def current-state (atom nil))
90
91
92 (defn set-state! [^SaveState state]
93 (assert (:data state) "Not a valid state!")
94 (if (not @on?) (restart!))
95 (if (not= @current-state state)
96 (Gb/loadState (:data state)))
97 (reset! current-state state))
98
99 (defrecord Move [keys state])
100
101 (defn step
102 ([^SaveState state buttons]
103 (set-state! state)
104 (Gb/step (button-mask buttons))
105 (reset! current-state
106 (SaveState. (inc (:frame state))(Gb/saveState))))
107 ([^SaveState state]
108 (step state [:listen]))
109 ([] (step (if @current-state @current-state (root)))))
110
111 (defn move
112 [^Move move buttons]
113 (Move. (step (:state move) buttons) buttons))
114
115
116 (defn play
117 ([^SaveState state n]
118 (reduce (fn [s _] (step s)) state (range n)))
119 ([n]
120 (play @current-state n)))
121
122 (defn play-moves
123 ([moves [prev state]]
124 (set-state! state)
125 (dorun (map (fn [move] (step @current-state move)) moves))
126 [(concat prev moves) @current-state]))
127
128 ;;;;;;;;;;;
129
130
131 ;;;;;;;;;;;;;;; CPU data
132
133
34 134
35 (defn cpu-data [size arr-fn] 135 (defn cpu-data [size arr-fn]
36 (let [store (int-array size)] 136 (let [store (int-array size)]
37 (fn [] (arr-fn store) store))) 137 (fn [state] (set-state! state) (arr-fn store) store)))
38 138
39 (def ram 139 (def ram
40 (cpu-data (Gb/getRAMSize) #(Gb/getRAM %))) 140 (cpu-data (Gb/getRAMSize) #(Gb/getRAM %)))
41 141
42 (def rom 142 (def rom
49 (cpu-data Gb/VRAM_SIZE #(Gb/getVRAM %))) 149 (cpu-data Gb/VRAM_SIZE #(Gb/getVRAM %)))
50 150
51 (def registers 151 (def registers
52 (cpu-data Gb/NUM_REGISTERS #(Gb/getRegisters %))) 152 (cpu-data Gb/NUM_REGISTERS #(Gb/getRegisters %)))
53 153
54 (def button-code 154 ;; TODO add register names
55 {;; main buttons
56 :a 0x0001
57 :b 0x0002
58 155
59 ;; directional pad 156 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
60 :r 0x0010
61 :l 0x0020
62 :u 0x0040
63 :d 0x0080
64 157
65 ;; meta buttons 158 (defn AF [state]
66 :select 0x0004 159 (nth (registers state) 2))
67 :start 0x0008
68 160
69 ;; hard reset -- not really a button 161 (defn BC [state]
70 :reset 0x0800}) 162 (nth (registers state) 3))
71 163
72 (defn button-mask [buttons] 164 (defn DE [state]
73 (reduce bit-or 0x0000 (map button-code buttons))) 165 (nth (registers state) 4))
166
167 ;;;;;;;;;;;;;;;
74 168
75 (defn buttons [mask] 169 (defmacro defn-memo
76 (loop [buttons [] 170 [& forms]
77 masks (seq button-code)] 171 (let [fun-name (first forms)]
78 (if (empty? masks) buttons 172 `(do
79 (let [[button value] (first masks)] 173 (defn ~@forms)
80 (if (not= 0x0000 (bit-and value mask)) 174 (alter-var-root (var ~fun-name) memoize))))
81 (recur (conj buttons button) (rest masks)) 175
82 (recur buttons (rest masks)))))))
83
84 (defrecord SaveState [frame save-data])
85
86 (defn frame [] @current-frame)
87
88 (defn save-state []
89 (SaveState. (frame) (Gb/saveState)))
90
91 (defn load-state [#^SaveState save]
92 (reset! current-frame (:frame save))
93 (Gb/loadState (:save-data save)))
94
95 (def empty-history (sorted-map))
96
97 (def history (atom empty-history))
98
99 (defn frame->disk-save [frame]
100 (File. *save-state-cache*
101 (format "%07d.sav" frame)))
102
103 (defn get-save-from-disk [frame]
104 (let [save (frame->disk-save frame)]
105 (if (.exists save)
106 (let [buf (Gb/saveBuffer)
107 bytes (FileUtils/readFileToByteArray save)]
108 (.put buf bytes)
109 (.flip buf)
110 (SaveState. frame buf)))))
111
112 (defn store-save-to-disk [^SaveState save]
113 (let [buf (:save-data save)
114 bytes (byte-array (.limit buf))
115 dest (frame->disk-save (:frame save))]
116 (.get buf bytes)
117 (FileUtils/writeByteArrayToFile dest bytes)
118 (.rewind buf) dest))
119
120 (defn find-save-state [frame]
121 (let [save (@history frame)]
122 (if (not (nil? save)) save
123 (get-save-from-disk frame))))
124
125 (defn goto [frame]
126 (let [save (find-save-state frame)]
127 (if (nil? save)
128 (println frame "is not in history")
129 (do
130 (reset! current-frame frame)
131 (load-state save)))))
132
133 (defn clear-history [] (reset! history empty-history))
134
135 (defn rewind
136 ([] (rewind 1))
137 ([n] (goto (- @current-frame n))))
138
139 (defn backup-state
140 ([] (backup-state (frame)))
141 ([frame]
142 (let [save (save-state)]
143 (swap! history #(assoc % frame save))
144 ;;(store-save-to-disk save)
145 (if (> (count @history) *max-history*)
146 (swap! history #(dissoc % (first (first %))))))))
147
148 (defn advance []
149 (if *save-history*
150 (backup-state @current-frame))
151 (swap! current-frame inc))
152
153 (defn step
154 ([] (advance) (Gb/step))
155 ([mask-or-buttons]
156 (advance)
157 (if (number? mask-or-buttons)
158 (Gb/step mask-or-buttons)
159 (Gb/step (button-mask mask-or-buttons)))))
160
161 (defn play-moves
162 ([start moves]
163 (goto start)
164 (dorun (map step moves))
165 (backup-state)
166 (frame))
167 ([moves]
168 (dorun (map step moves))
169 (backup-state)
170 (frame)))
171
172 (defn play
173 ([] (play Integer/MAX_VALUE))
174 ([n] (dorun (dotimes [_ n] (step)))))
175
176 (defmacro without-saves [& forms]
177 `(binding [*save-history* false]
178 ~@forms))
179
180
181 (require '(clojure [zip :as zip]))
182
183
184
185
186 (defn tree->str [original]
187 (loop [s ".\n" loc (zip/down (zip/seq-zip (seq original)))]
188 (if (zip/end? loc) s
189 (let [d (count (zip/path loc))
190 rep
191 (str
192 s
193 (if (and (zip/up loc)
194 (> (count (-> loc zip/up zip/rights)) 0))
195 "|" "")
196 (apply str (repeat (dec d) " "))
197 (if (= (count (zip/rights loc)) 0)
198 "`-- "
199 "|-- ")
200 (zip/node loc)
201 "\n")]
202 (recur rep (zip/next loc))))))
203
204
205
206