annotate clojure/com/aurellem/gb_funs.clj @ 84:26f002f2868c

better functional version of earlier code
author Robert McIntyre <rlm@mit.edu>
date Fri, 09 Mar 2012 23:28:07 -0600
parents 95cb2152d7cd
children 3f4fdd270059
rev   line source
rlm@83 1 (ns com.aurellem.gb-funs
rlm@83 2 (:import com.aurellem.gb.Gb)
rlm@83 3 (:import java.io.File)
rlm@83 4 (:import org.apache.commons.io.FileUtils)
rlm@83 5 (:import (java.nio IntBuffer ByteOrder)))
rlm@83 6
rlm@83 7 ;; Savestates
rlm@83 8 (defrecord SaveState [frame data])
rlm@83 9
rlm@83 10 (def ^:dynamic *save-state-cache*
rlm@83 11 (File. "/home/r/proj/pokemon-escape/save-states/"))
rlm@83 12
rlm@83 13 (defn frame->filename [frame]
rlm@83 14 (File. *save-state-cache* (format "%07d.sav" frame)))
rlm@83 15
rlm@83 16 (defn write-save! [^SaveState save]
rlm@83 17 (let [buf (:data save)
rlm@83 18 bytes (byte-array (.limit buf))
rlm@83 19 dest (frame->filename (:frame save))]
rlm@83 20 (.get buf bytes)
rlm@83 21 (FileUtils/writeByteArrayToFile dest bytes)
rlm@83 22 (.rewind buf)
rlm@83 23 save))
rlm@83 24
rlm@83 25 (defn read-save [frame]
rlm@83 26 (let [save (frame->filename frame)]
rlm@83 27 (if (.exists save)
rlm@83 28 (let [buf (Gb/saveBuffer)
rlm@83 29 bytes (FileUtils/readFileToByteArray save)]
rlm@83 30 (.put buf bytes)
rlm@83 31 (.flip buf)
rlm@83 32 (SaveState. frame buf)))))
rlm@83 33 ;;;;;;;;;;;;;;;;
rlm@83 34
rlm@83 35 ;; Gameboy management
rlm@83 36 (Gb/loadVBA)
rlm@83 37
rlm@83 38 (def yellow-rom-image
rlm@83 39 (File. "/home/r/proj/pokemon-escape/roms/yellow.gbc"))
rlm@83 40
rlm@83 41 (def yellow-save-file
rlm@83 42 (File. "/home/r/proj/pokemon-escape/roms/yellow.sav"))
rlm@83 43
rlm@83 44 (def on? (atom nil))
rlm@83 45
rlm@83 46 (defn shutdown! [] (Gb/shutdown) (reset! on? false))
rlm@83 47
rlm@83 48 (defn restart! []
rlm@83 49 (shutdown!)
rlm@83 50 (.delete yellow-save-file)
rlm@83 51 (Gb/startEmulator (.getCanonicalPath yellow-rom-image))
rlm@83 52 (reset! on? true))
rlm@83 53
rlm@83 54 ;;; The first state!
rlm@83 55 (defn gen-root! []
rlm@83 56 (restart!)
rlm@83 57 (write-save! (SaveState. 0 (Gb/saveState))))
rlm@83 58
rlm@83 59 (defn root []
rlm@83 60 (if (.exists (frame->filename 0))
rlm@83 61 (read-save 0)
rlm@83 62 (gen-root!)))
rlm@83 63
rlm@83 64 ;;;; Press Buttons
rlm@83 65
rlm@83 66 (def button-code
rlm@83 67 {;; main buttons
rlm@83 68 :a 0x0001
rlm@83 69 :b 0x0002
rlm@83 70
rlm@83 71 ;; directional pad
rlm@83 72 :r 0x0010
rlm@83 73 :l 0x0020
rlm@83 74 :u 0x0040
rlm@83 75 :d 0x0080
rlm@83 76
rlm@83 77 ;; meta buttons
rlm@83 78 :select 0x0004
rlm@83 79 :start 0x0008
rlm@83 80
rlm@83 81 ;; pseudo-buttons
rlm@84 82 :restart 0x0800 ; hard reset
rlm@83 83 :listen -1 ; listen for user input
rlm@83 84 })
rlm@83 85
rlm@83 86 (defn button-mask [buttons]
rlm@83 87 (reduce bit-or 0x0000 (map button-code buttons)))
rlm@83 88
rlm@83 89 (def current-state (atom nil))
rlm@83 90
rlm@84 91
rlm@84 92 (defn set-state! [^SaveState state]
rlm@84 93 (if (not @on?) (restart!))
rlm@84 94 (if (not= @current-state state)
rlm@84 95 (Gb/loadState (:data state)))
rlm@84 96 (reset! current-state state))
rlm@84 97
rlm@84 98 (defrecord Move [keys state])
rlm@84 99
rlm@83 100 (defn step
rlm@83 101 ([^SaveState state buttons]
rlm@84 102 (set-state! state)
rlm@83 103 (Gb/step (button-mask buttons))
rlm@83 104 (reset! current-state
rlm@84 105 (SaveState. (inc (:frame state))(Gb/saveState))))
rlm@83 106 ([^SaveState state]
rlm@83 107 (step state [:listen]))
rlm@83 108 ([] (step (if @current-state @current-state (root)))))
rlm@84 109
rlm@84 110 (defn move
rlm@84 111 [^Move move buttons]
rlm@84 112 (Move. (step (:state move) buttons) buttons))
rlm@84 113
rlm@84 114
rlm@84 115 (defn play
rlm@84 116 ([state n]
rlm@84 117 (reduce (fn [s _] (step s)) state (range n)))
rlm@84 118 ([state]
rlm@84 119 (dorun (iterate step state))))
rlm@84 120 ;;;;;;;;;;;
rlm@84 121
rlm@84 122
rlm@84 123 ;;;;;;;;;;;;;;; CPU data
rlm@84 124
rlm@84 125
rlm@84 126
rlm@84 127 (defn cpu-data [size arr-fn]
rlm@84 128 (let [store (int-array size)]
rlm@84 129 (fn [state] (set-state! state) (arr-fn store) store)))
rlm@84 130
rlm@84 131 (def ram
rlm@84 132 (cpu-data (Gb/getRAMSize) #(Gb/getRAM %)))
rlm@84 133
rlm@84 134 (def rom
rlm@84 135 (cpu-data (Gb/getROMSize) #(Gb/getROM %)))
rlm@84 136
rlm@84 137 (def working-ram
rlm@84 138 (cpu-data Gb/WRAM_SIZE #(Gb/getWRAM %)))
rlm@84 139
rlm@84 140 (def video-ram
rlm@84 141 (cpu-data Gb/VRAM_SIZE #(Gb/getVRAM %)))
rlm@84 142
rlm@84 143 (def registers
rlm@84 144 (cpu-data Gb/NUM_REGISTERS #(Gb/getRegisters %)))
rlm@84 145
rlm@84 146 ;; TODO add register names
rlm@84 147
rlm@84 148 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
rlm@84 149
rlm@84 150 (defn AF [state]
rlm@84 151 (nth (registers state) 2))
rlm@84 152
rlm@84 153 (defn BC [state]
rlm@84 154 (nth (registers state) 3))
rlm@84 155
rlm@84 156
rlm@84 157
rlm@84 158