changeset 329:a452deec2882

improved efficiency of delayed-difference
author Robert McIntyre <rlm@mit.edu>
date Fri, 06 Apr 2012 07:22:18 -0500
parents 35960b03693f
children ecff37d22293
files clojure/com/aurellem/run/bootstrap_0.clj clojure/com/aurellem/run/title.clj clojure/com/aurellem/run/util.clj moves/cor-checkpoint.vbm save-states/cor-checkpoint.sav
diffstat 5 files changed, 140 insertions(+), 202 deletions(-) [+]
line wrap: on
line diff
     1.1 --- a/clojure/com/aurellem/run/bootstrap_0.clj	Thu Apr 05 15:05:08 2012 -0500
     1.2 +++ b/clojure/com/aurellem/run/bootstrap_0.clj	Fri Apr 06 07:22:18 2012 -0500
     1.3 @@ -368,6 +368,7 @@
     1.4  
     1.5  (defn item-quantity-selected
     1.6    ([^SaveState state]
     1.7 +     (println "items:" (aget (memory state) item-quantity-selected-address))
     1.8       (aget (memory state) item-quantity-selected-address))
     1.9    ([] (item-quantity-selected @current-state)))
    1.10  
    1.11 @@ -393,162 +394,39 @@
    1.12          difference (- n current-position)]
    1.13      (println difference)
    1.14      (set-cursor-relative difference script)))
    1.15 -  
    1.16 -(defn buy-item
    1.17 -  "Assumes that the main item-screen is up, and buys
    1.18 -   quantity of the nth item in the list, assuming that you
    1.19 -   have enough money."
    1.20 -  [n quantity script]
    1.21 -  (if (= 0  quantity)
    1.22 -    script
    1.23 -    (let [after-initial-pause
    1.24 -          (do-nothing 20  script)
    1.25 -          move-to-item
    1.26 -          (reduce (fn [script _]
    1.27 -                    (->> script
    1.28 -                         (play-moves [[:d]])
    1.29 -                         (do-nothing 3)))
    1.30 -                  after-initial-pause
    1.31 -                  (range n))
    1.32 -          select-item
    1.33 -          (play-moves [[:a]] move-to-item)
    1.34 -          request-items
    1.35 -          (reduce (fn [script _]
    1.36 -                    (->> script
    1.37 -                         (play-moves [[:u]])
    1.38 -                         (do-nothing 1)))
    1.39 -                  select-item
    1.40 -                  (range (dec quantity)))
    1.41 -          buy-items
    1.42 -          (->> request-items
    1.43 -               (do-nothing 10)
    1.44 -               (play-moves [[:a]])
    1.45 -               (scroll-text)
    1.46 -               (scroll-text)
    1.47 -               (do-nothing 10)
    1.48 -               (play-moves [[:a]])
    1.49 -               (scroll-text))]
    1.50 -      buy-items)))
    1.51 +
    1.52 +(defn set-quantity
    1.53 +  "Set the quantity of an item to buy or sell to the desired value
    1.54 +  using the fewest possible button presses."
    1.55 +  [total-quantity desired-quantity [moves state :as script]]
    1.56 +  (let [current-quantity (item-quantity-selected state)
    1.57 +        loop-point (if (> total-quantity 99) 0xFF 99)
    1.58 +        distance (- desired-quantity current-quantity)
    1.59 +        loop-distance (int(* -1 (Math/signum (float distance))
    1.60 +                             (- loop-point (Math/abs distance))))
    1.61 +        best-path (first (sort-by #(Math/abs %)
    1.62 +                                  [distance loop-distance]))
    1.63 +        direction (if (< 0 best-path) ↑ ↓)]
    1.64 +    (println "best-path" best-path)
    1.65 +    (reduce
    1.66 +     (fn [script _]
    1.67 +       (delayed-difference [] direction 200 item-quantity-selected
    1.68 +                               script))
    1.69       
    1.70 +     script
    1.71 +     (range (Math/abs best-path)))))
    1.72  
    1.73 -(defn buy-items
    1.74 -  "Given a list of [item-no quantity], buys the quantity
    1.75 -   from the shop's list. Assumes that the item list is
    1.76 -   already up."
    1.77 -  [item-pairs script]
    1.78 -  (let [item-lookup (into {0 0 1 0 2 0 3 0 4 0} item-pairs)
    1.79 -        initial-purchase
    1.80 -        (->> script
    1.81 -             (buy-item 0 (item-lookup 0))
    1.82 -             (buy-item 1 (item-lookup 1))
    1.83 -             (buy-item 2 (item-lookup 2)))]
    1.84 -    (cond
    1.85 -      (and
    1.86 -       (not= 0 (item-lookup 3))
    1.87 -       (not= 0 (item-lookup 4)))
    1.88 -      (->> initial-purchase
    1.89 -           (do-nothing 20)
    1.90 -           (play-moves [[:d]])
    1.91 -           (do-nothing 3)
    1.92 -           (play-moves [[:d]])
    1.93 -           (do-nothing 3)
    1.94 -           (play-moves [[:d]])
    1.95 -           (do-nothing 10)
    1.96 -           (buy-item 0 (item-lookup 3))
    1.97 -           (do-nothing 20)
    1.98 -           (play-moves [[:d]])
    1.99 -           (do-nothing 3)
   1.100 -           (play-moves [[:d]])
   1.101 -           (do-nothing 3)
   1.102 -           (play-moves [[:d]])
   1.103 -           (do-nothing 10)
   1.104 -           (buy-item 0 (item-lookup 4)))
   1.105 -      (and (= 0 (item-lookup 3))
   1.106 -           (not= 0 (item-lookup 4)))
   1.107 -      (->> initial-purchase
   1.108 -           (do-nothing 20)
   1.109 -           (play-moves [[:d]])
   1.110 -           (do-nothing 3)
   1.111 -           (play-moves [[:d]])
   1.112 -           (do-nothing 3)
   1.113 -           (play-moves [[:d]])
   1.114 -           (do-nothing 10)
   1.115 -           (play-moves [[:d]])
   1.116 -           (do-nothing 10)
   1.117 -           (buy-item 0 (item-lookup 4)))
   1.118 -      (and (not= 0 (item-lookup 3))
   1.119 -           (= 0 (item-lookup 4)))
   1.120 -      (->> initial-purchase
   1.121 -           (do-nothing 20)
   1.122 -           (play-moves [[:d]])
   1.123 -           (do-nothing 3)
   1.124 -           (play-moves [[:d]])
   1.125 -           (do-nothing 3)
   1.126 -           (play-moves [[:d]])
   1.127 -           (do-nothing 10)
   1.128 -           (buy-item 0 (item-lookup 3)))
   1.129 -      (and (= 0 (item-lookup 3))
   1.130 -           (= 0 (item-lookup 4)))
   1.131 -      initial-purchase)))
   1.132 -
   1.133 -
   1.134 -(defn test-buy-items
   1.135 -  ([] (test-buy-items
   1.136 -       (walk-to-counter)))
   1.137 -  ([script]
   1.138 -     (->> [(first script) (set-money (second script)
   1.139 -                                     999999)]
   1.140 -          (play-moves
   1.141 -           [[] [:a] []])
   1.142 -          (scroll-text)
   1.143 -          (do-nothing 100)
   1.144 -          (play-moves [[:a]])
   1.145 -          (do-nothing 100)
   1.146 -          (buy-items
   1.147 -           [[0 1]
   1.148 -            [1 15]
   1.149 -            [2 1]
   1.150 -            [3 20]
   1.151 -            [4 95]
   1.152 -            ]))))
   1.153 -
   1.154 -(defn-memo buy-initial-items
   1.155 -  ([] (buy-initial-items
   1.156 +(defn-memo do-save-corruption
   1.157 +  ([] (do-save-corruption
   1.158         (walk-to-counter)))
   1.159    ([script]
   1.160       (->> script
   1.161 -          (play-moves
   1.162 -           [[] [:a] []])
   1.163 -          (scroll-text)
   1.164 -          (do-nothing 100)
   1.165 +          (first-difference [] [:start] AF)
   1.166 +          (set-cursor 4)
   1.167 +          (do-nothing 5)
   1.168            (play-moves [[:a]])
   1.169 -          (do-nothing 100)
   1.170 -          (buy-items
   1.171 -           [[0 1]
   1.172 -            [1 1]
   1.173 -            [2 1]
   1.174 -            [3 1]
   1.175 -            [4 1]])
   1.176 -          (do-nothing 100)
   1.177 -          (play-moves [[:b]])
   1.178 -          (do-nothing 100)
   1.179 -          (play-moves [[:b]])
   1.180 -          (do-nothing 100)
   1.181 -          (play-moves [[:b] []])
   1.182 -          (first-difference [:b] [:b :start] AF))))
   1.183 -
   1.184 -
   1.185 -(defn-memo do-save-corruption
   1.186 -  ([] (do-save-corruption
   1.187 -       (buy-initial-items)))
   1.188 -  ([script]
   1.189 -     (->> script
   1.190 -          (first-difference [] [:d] AF)
   1.191 -          (play-moves [[] [] [] [:d]
   1.192 -                       [] [] [] [:d]
   1.193 -                       [] [] [] [:d]
   1.194 -                       [] [] [:a]])
   1.195 -          scroll-text
   1.196 +          (play-moves (repeat 85 [:b]))
   1.197 +          (play-moves [[:a]])
   1.198            (play-moves
   1.199             ;; this section is copied from speedrun-2942 and corrupts
   1.200             ;; the save so that the total number of pokemon is set to
   1.201 @@ -558,25 +436,59 @@
   1.202              [] [] [] [] [] [] [] [] [] [] [] [:select] [:restart]])
   1.203            (title)
   1.204            (first-difference [] [:start] AF)
   1.205 -          (first-difference [] [:a] AF)
   1.206 -          (first-difference [:a] [:a :start] AF))))
   1.207 +          (first-difference [] [:a] AF))))
   1.208 +          
   1.209 +(defn gen-corrupted-checkpoint! []
   1.210 +  (let [[cor-moves cor-save] (do-save-corruption)]
   1.211 +    (write-moves! cor-moves "cor-checkpoint")
   1.212 +    (write-state! cor-save "cor-checkpoint")))
   1.213 +
   1.214 +(defn corrupted-checkpoint []
   1.215 +  [(read-moves "cor-checkpoint")
   1.216 +   (read-state "cor-checkpoint")])
   1.217  
   1.218  (def menu do-nothing )
   1.219  
   1.220  (defn-memo corrupt-item-list
   1.221 +  "Corrupt the num-of-items variable by switching a corrupted pokemon
   1.222 +   into out-of-bounds memory."
   1.223    ([] (corrupt-item-list
   1.224 -       (do-save-corruption)))
   1.225 +       (corrupted-checkpoint)))
   1.226    ([script]
   1.227       (->> script
   1.228 -          (do-nothing 200)
   1.229 -          (menu [↓ [:a]])               ; select "POKEMON" from
   1.230 -                                        ; from main menu
   1.231 -          (menu [↓ ↓ ↓ ↓ ↓ ↓            ; go to 6th pokemon
   1.232 -                 [:a] ↓ [:a]            ; select "switch"
   1.233 -                 ↓ ↓ ↓ [:a]])           ; switch with 9th "pokemon"
   1.234 -                 
   1.235 -          (do-nothing 1))))
   1.236 -                     
   1.237 +          (first-difference [:a] [:a :start] AF)
   1.238 +          (set-cursor 1)                    ; select "POKEMON" from
   1.239 +          (first-difference [] [:a] AF)     ; from main menu
   1.240 +          (set-cursor 5)                    ; select 6th pokemon
   1.241 +          (first-difference [] [:a] AF)
   1.242 +          (set-cursor 1)
   1.243 +          (first-difference [] [:a] AF)     
   1.244 +          (repeat-until-different [] list-offset) 
   1.245 +          (set-cursor 9)
   1.246 +          (first-difference [] [:a] AF)     ; switch 6th with 10th
   1.247 +          (first-difference [] [:b] AF)
   1.248 +          (first-difference [] [:b] AF))))
   1.249 +
   1.250 +(defn get-lots-of-money
   1.251 +  "Sell 0xFE cancel buttons to make a tremendous amount of money."
   1.252 +  ([] (get-lots-of-money (corrupt-item-list)))
   1.253 +  ([script]
   1.254 +     (->> script
   1.255 +          (first-difference [] [:a] AF)
   1.256 +          (repeat-until-different [] list-offset)
   1.257 +          (set-cursor 1)
   1.258 +          (first-difference [] [:a] AF)
   1.259 +          (repeat-until-different [] list-offset)
   1.260 +          (first-difference [] [:a] AF)
   1.261 +          (set-quantity 0xFF 0xFE)
   1.262 +          (do-nothing 1)
   1.263 +          )))
   1.264 +
   1.265 +
   1.266 +
   1.267 +
   1.268 +(def buy-items do-nothing)
   1.269 +
   1.270  (defn-memo get-burn-heals
   1.271    ([] (get-burn-heals
   1.272         (corrupt-item-list)))
     2.1 --- a/clojure/com/aurellem/run/title.clj	Thu Apr 05 15:05:08 2012 -0500
     2.2 +++ b/clojure/com/aurellem/run/title.clj	Fri Apr 06 07:22:18 2012 -0500
     2.3 @@ -13,7 +13,7 @@
     2.4            (first-difference [] [:a] AF)
     2.5            (first-difference [] [:start] AF))))
     2.6  
     2.7 -(defn-memo oak
     2.8 +(defn oak
     2.9    ([] (oak (title)))
    2.10    ([script]
    2.11       (->> script
     3.1 --- a/clojure/com/aurellem/run/util.clj	Thu Apr 05 15:05:08 2012 -0500
     3.2 +++ b/clojure/com/aurellem/run/util.clj	Fri Apr 06 07:22:18 2012 -0500
     3.3 @@ -38,50 +38,76 @@
     3.4            (recur new-actions new-state))))))
     3.5  
     3.6  (defn binary-search [metric]
     3.7 -  (let [baseline (metric 0)]
     3.8 -    (loop [low 1
     3.9 -           high 2]
    3.10 -      (let [low-val (metric low)
    3.11 -            high-val (metric high)]
    3.12 -        (println low high)
    3.13 -        (cond
    3.14 -          ;; base case
    3.15 -          (and (= low (dec high))
    3.16 -               (not= low-val high-val))
    3.17 -          high
    3.18 -          ;; exponential growth
    3.19 -          (= baseline high-val low-val)
    3.20 -          (recur high (* high 2))
    3.21 -
    3.22 -          ;; binary search
    3.23 -          (and (= baseline low-val)
    3.24 -               (not= baseline high-val))
    3.25 -          (let [test (int (/ (+ low high) 2))
    3.26 -                test-val (metric test)]
    3.27 -            (if (= test-val baseline)
    3.28 -              (recur test high)
    3.29 -              (recur low test))))))))
    3.30 +  (loop [low 0
    3.31 +         high 1]
    3.32 +    (let [low-val (metric low)
    3.33 +          high-val (metric high)]
    3.34 +      (println "(" low high ")")
    3.35 +      (cond
    3.36 +       ;; base case
    3.37 +       (and (= low (dec high))
    3.38 +            (not= low-val high-val))
    3.39 +       high
    3.40 +       ;; exponential growth
    3.41 +       (= high-val low-val)
    3.42 +       (recur high (* high 2))
    3.43 +       
    3.44 +       ;; binary search
    3.45 +       (not= low-val high-val)
    3.46 +       (let [test (int (/ (+ low high) 2))
    3.47 +             test-val (metric test)]
    3.48 +         (if (= test-val low-val)
    3.49 +           (recur test high)
    3.50 +           (recur low test)))))))
    3.51  
    3.52  
    3.53  (defn delayed-difference
    3.54 +  "determine the shortest sequence of the form:
    3.55 +
    3.56 +   sequence = (concat (repeat n base) alt)
    3.57 +    which will cause difference-metric
    3.58 +   to yield a different value between.
    3.59 +
    3.60 +   (concat sequence (repeat delay base))
    3.61 +   and
    3.62 +   (repeat (+ n 1 delay base))
    3.63 +
    3.64 +   This search function is good for finding the optimum keypresses
    3.65 +   whose effect on the game is not revealed until several frames after
    3.66 +   those keys have been pressed (such as scrolling text)."
    3.67    [base alt delay difference-metric [moves root :as script]]
    3.68 -  (let [generator
    3.69 -        (memoize
    3.70 -         (fn gen [n] 
    3.71 -           (run-moves
    3.72 +  (let [states-cache (atom {})
    3.73 +        generator 
    3.74 +        ;; (memoize  ;; 32947 msecs
    3.75 +        ;;  (fn gen [n] 
    3.76 +        ;;    (run-moves
    3.77 +        ;;     root
    3.78 +        ;;     (repeat n base))))
    3.79 +
    3.80 +        (fn gen [n]  ;; 21150 msecs
    3.81 +          (if (= 0 n)
    3.82              root
    3.83 -            (repeat n base))))
    3.84 +            (if-let [cached (@states-cache n)]
    3.85 +              cached
    3.86 +              (do (swap!
    3.87 +                   states-cache
    3.88 +                   #(assoc % n
    3.89 +                           (run-moves
    3.90 +                            (gen (dec n))
    3.91 +                            [base])))
    3.92 +                  (gen n)))))
    3.93 +            
    3.94          len
    3.95          (binary-search
    3.96 -         (memoize (fn [n]
    3.97 -           (= (difference-metric
    3.98 -               (run-moves
    3.99 -                (generator n)
   3.100 -                (concat [alt] (repeat delay base))))
   3.101 -              (difference-metric
   3.102 -               (run-moves
   3.103 -                (generator n)
   3.104 -                (repeat (inc delay) base)))))))
   3.105 +         (memoize
   3.106 +          (fn [n]
   3.107 +            (if (= n 0) true
   3.108 +                (=(difference-metric
   3.109 +                   (run-moves
   3.110 +                    (generator n)
   3.111 +                    (concat [alt] (repeat delay base))))
   3.112 +                  (difference-metric
   3.113 +                    (generator (+ n 1 delay))))))))
   3.114          new-moves (concat moves (repeat len base) [alt])
   3.115          new-state (run-moves (generator len) [alt])]
   3.116      [new-moves new-state]))
   3.117 @@ -135,8 +161,8 @@
   3.118    ([^SaveState state]
   3.119       (character-codes->str
   3.120        (subvec (vec (memory state))
   3.121 -              text-address
   3.122 -              (+ text-address 82))))
   3.123 +              (+ text-address 0)
   3.124 +              (+ text-address  90))))
   3.125    ([] (displayed-text @current-state)))
   3.126  
   3.127  (defn scroll-text
     4.1 Binary file moves/cor-checkpoint.vbm has changed
     5.1 Binary file save-states/cor-checkpoint.sav has changed