rlm@313: (ns com.aurellem.run.util rlm@314: (:use (com.aurellem.gb util gb-driver vbm characters saves)) rlm@313: (:import [com.aurellem.gb.gb_driver SaveState])) rlm@313: rlm@313: (def ↑ [:u]) rlm@313: (def ↓ [:d]) rlm@313: (def ← [:l]) rlm@313: (def → [:r]) rlm@313: rlm@313: (defn first-difference rlm@313: [base alt difference-metric [moves root :as script]] rlm@313: (loop [branch-point root rlm@313: actions moves] rlm@313: (let [base-branch (step branch-point base) rlm@313: base-val (difference-metric base-branch) rlm@313: alt-branch (step branch-point alt) rlm@313: alt-val (difference-metric alt-branch)] rlm@313: (if (not= base-val alt-val) rlm@313: [(conj actions alt) alt-branch] rlm@313: (recur base-branch (conj actions base)))))) rlm@313: rlm@313: (defn repeat-until-different rlm@314: [buttons metric [moves root :as script]] rlm@313: (let [baseline (metric root)] rlm@313: (loop [actions (vec moves) rlm@313: state root] rlm@313: (let [new-state (step state buttons) rlm@313: new-actions (conj actions buttons)] rlm@313: (if (not= (metric new-state) baseline) rlm@313: [new-actions new-state] rlm@313: (recur new-actions new-state)))))) rlm@313: rlm@316: rlm@316: (defn binary-search [metric] rlm@316: (let [baseline (metric 0)] rlm@316: (loop [low 1 rlm@316: high 2] rlm@316: (let [low-val (metric low) rlm@316: high-val (metric high)] rlm@316: (println low high) rlm@316: (cond rlm@316: ;; base case rlm@316: (and (= low (dec high)) rlm@316: (not= low-val high-val)) rlm@316: high rlm@316: ;; exponential growth rlm@316: (= baseline high-val low-val) rlm@316: (recur high (* high 2)) rlm@316: rlm@316: ;; binary search rlm@316: (and (= baseline low-val) rlm@316: (not= baseline high-val)) rlm@316: (let [test (int (/ (+ low high) 2)) rlm@316: test-val (metric test)] rlm@316: (if (= test-val baseline) rlm@316: (recur test high) rlm@316: (recur low test)))))))) rlm@316: rlm@316: (defn delayed-difference rlm@316: [base alt delay difference-metric [moves root :as script]] rlm@316: (let [generator rlm@316: (memoize rlm@316: (fn [n] rlm@316: (run-moves rlm@316: root rlm@316: (repeat n base)))) rlm@316: len rlm@316: (binary-search rlm@316: (fn [n] rlm@316: (= (difference-metric rlm@316: (run-moves rlm@316: (generator n) rlm@316: (concat [alt] (repeat delay base)))) rlm@316: (difference-metric rlm@316: (run-moves rlm@316: (generator n) rlm@316: (repeat (inc delay) base)))))) rlm@316: new-moves (concat moves (repeat len base) [alt]) rlm@316: new-state (run-moves (generator len) [alt])] rlm@316: [new-moves new-state])) rlm@316: rlm@313: (def x-position-address 0xD361) rlm@313: (def y-position-address 0xD362) rlm@313: rlm@313: (defn x-position rlm@313: ([^SaveState state] rlm@313: (aget (memory state) x-position-address)) rlm@313: ([] (x-position @current-state))) rlm@313: rlm@313: (defn y-position rlm@313: ([^SaveState state] rlm@313: (aget (memory state) y-position-address)) rlm@313: ([] (y-position @current-state))) rlm@313: rlm@313: (defn move rlm@313: [dir script] rlm@313: (let [current-position-fn rlm@313: (cond (#{← →} dir) x-position rlm@313: (#{↑ ↓} dir) y-position)] rlm@313: (repeat-until-different dir current-position-fn script))) rlm@313: rlm@313: (defn walk rlm@313: "Move the character along the given directions." rlm@313: [directions script] rlm@313: (reduce (fn [script dir] rlm@313: (move dir script)) script directions)) rlm@313: rlm@313: (defn search-string rlm@314: [^SaveState state string] rlm@313: (let [codes rlm@313: (str->character-codes string) rlm@313: codes-length (count codes) rlm@314: mem (vec (memory state)) rlm@313: mem-length (count mem)] rlm@313: (loop [idx 0] rlm@313: (if (< (- mem-length idx) codes-length) rlm@313: nil rlm@313: (if (= (subvec mem idx (+ idx codes-length)) rlm@313: codes) rlm@313: idx rlm@313: (recur (inc idx))))))) rlm@313: rlm@314: (def text-address 0x9DC1) rlm@314: rlm@314: (defn displayed-text rlm@314: ([^SaveState state] rlm@314: (character-codes->str rlm@314: (subvec (vec (memory state)) rlm@314: text-address rlm@314: (+ text-address 82)))) rlm@314: ([] (displayed-text @current-state))) rlm@314: rlm@314: (defn scroll-text rlm@314: ([script] rlm@314: (delayed-difference rlm@314: [:b] [:a :b] 25 displayed-text script)) rlm@314: ([n script] rlm@314: (reduce (fn [script _] rlm@314: (scroll-text script)) rlm@314: script rlm@314: (range n)))) rlm@314: rlm@313: (defn do-nothing [n script] rlm@313: (->> script rlm@313: (play-moves rlm@313: (repeat n [])))) rlm@313: rlm@313: rlm@313: (defn critical-hit rlm@313: "Put the cursor over the desired attack. This program will rlm@313: determine the appropriate amount of blank frames to rlm@313: insert before pressing [:a] to ensure that the attack is rlm@313: a critical hit." rlm@313: [script] rlm@313: (loop [blanks 6] rlm@313: (let [new-script rlm@313: (->> script rlm@313: (play-moves rlm@313: (concat (repeat blanks []) rlm@313: [[:a][]])))] rlm@313: (if (let [future-state rlm@313: (run-moves (second new-script) rlm@313: (repeat 400 [])) rlm@313: rlm@313: result (search-string (memory future-state) rlm@313: "Critical")] rlm@313: (if result rlm@313: (println "critical hit with" blanks "blank frames")) rlm@313: result) rlm@313: new-script rlm@313: (recur (inc blanks)))))) rlm@313: rlm@313: (defn move-thru-grass rlm@313: [direction script] rlm@313: (loop [blanks 0] rlm@313: (let [new-script rlm@313: (->> script rlm@313: (play-moves (repeat blanks [])) rlm@313: (move direction)) rlm@313: rlm@313: future-state rlm@313: (run-moves (second new-script) rlm@313: (repeat 600 [])) rlm@313: rlm@313: result (search-string (memory future-state) rlm@313: "Wild")] rlm@313: (if (nil? result) rlm@313: (do rlm@313: (if (< 0 blanks) rlm@313: (do rlm@313: (println "avoided pokemon with" rlm@313: blanks "blank frames"))) rlm@313: new-script) rlm@313: (recur (inc blanks)))))) rlm@313: rlm@313: (defn walk-thru-grass rlm@313: [directions script] rlm@313: (reduce (fn [script direction] rlm@313: (move-thru-grass direction script)) rlm@313: script directions)) rlm@313: rlm@313: (defn slowly rlm@313: [delay moves script] rlm@313: (reduce rlm@313: (fn [script move] rlm@313: (->> script rlm@313: (do-nothing delay) rlm@313: (play-moves (vector move)))) rlm@313: script moves)) rlm@313: rlm@313: (defn multiple-times rlm@313: ([n command args script] rlm@313: (reduce (fn [script _] rlm@313: (apply command (concat args [script]))) rlm@313: script rlm@313: (range n))) rlm@313: ([n command script] rlm@313: (multiple-times n command [] script)))