Mercurial > vba-clojure
changeset 420:acc3d1ad24e8
Found HP restored by SODA POP, FRESH WATER, LEMONADE; also found number of steps for REPEL, SUPER REPEL, MAX REPEL.
author | Dylan Holmes <ocsenave@gmail.com> |
---|---|
date | Sat, 14 Apr 2012 09:27:49 -0500 |
parents | 4901ba2d3860 |
children | 13165fb5852b |
files | clojure/com/aurellem/gb/hxc.clj org/rom.org |
diffstat | 2 files changed, 668 insertions(+), 19 deletions(-) [+] |
line wrap: on
line diff
1.1 --- a/clojure/com/aurellem/gb/hxc.clj Sat Apr 14 05:20:28 2012 -0500 1.2 +++ b/clojure/com/aurellem/gb/hxc.clj Sat Apr 14 09:27:49 2012 -0500 1.3 @@ -184,7 +184,8 @@ 1.4 1.5 1.6 (defn hxc-pokedex-names 1.7 - "The names of the pokemon in hardcoded pokedex order. List begins at 1.8 + "The names of the pokemon in hardcoded pokedex order. List of the 1.9 + pokedex numbers of each pokemon (in internal order) begins at 1.10 ROM@410B1. See also, hxc-pokenames." 1.11 ([] (hxc-pokedex-names 1.12 com.aurellem.gb.gb-driver/original-rom)) 1.13 @@ -350,10 +351,9 @@ 1.14 1.15 (def hxc-places 1.16 "The hardcoded place names in memory. List begins at 1.17 -ROM@71500. [Cinnabar] Mansion seems to be dynamically calculated." 1.18 +ROM@71500. [Cinnabar/Celadon] Mansion seems to be dynamically calculated." 1.19 (hxc-thunk-words 0x71500 560)) 1.20 1.21 - 1.22 (defn hxc-dialog 1.23 "The hardcoded dialogue in memory, including in-game alerts. Dialog 1.24 seems to be separated by 0x57 instead of 0x50 (END). Begins at ROM@98000." 1.25 @@ -923,25 +923,335 @@ 1.26 ;; note: 1195C-6A says ABLE#NOT ABLE#, but so does 119C0-119CE. 1.27 ;; The first instance is for Machines; the second, for stones. 1.28 1.29 -;; 0x251A (in indexable mem): image decompression routine seems to begin here. 1.30 +;; note: according to 1.31 +;; http://www.upokecenter.com/games/rby/guides/rgbtrainers.php 1.32 +;; the amount of money given by a trainer is equal to the 1.33 +;; base money times the level of the last Pokemon on that trainer's 1.34 +;; list. Other sources say it's the the level of the last pokemon 1.35 +;; /defeated/. 1.36 + 1.37 +;; todo: find base money. 1.38 + 1.39 + 1.40 +;; note: 0xDFEA (in indexable mem) is the dex# of the currently-viewed Pokemon in 1.41 + ;; in the pokedex. It's used for other purposes if there is none. 1.42 + 1.43 +;; note: 0x9D35 (index.) switches from 0xFF to 0x00 temporarily when 1.44 +;; you walk between areas. 1.45 + 1.46 +;; note: 0xD059 (index.) is the special battle type of your next battle: 1.47 +;; - 00 is a usual battle 1.48 +;; - 01 is a pre-scripted OLD MAN battle which always fails to catch the 1.49 +;; target Pokemon. 1.50 +;; - 02 is a safari zone battle 1.51 +;; - 03 obligates you to run away. (unused) 1.52 +;; - 04 is a pre-scripted OAK battle, which (temporarily) causes the 1.53 +;; enemy Pokemon to cry PIKAAA, and which always catches the target 1.54 +;; Pokemon. The target Pokemon is erased after the battle. 1.55 +;; - 05+ are glitch states in which you are sort of the Pokemon. 1.56 + 1.57 + 1.58 +;; note: 0x251A (in indexable mem): image decompression routine seems to begin here. 1.59 + 1.60 +;; note: 0x4845 (index): vending inventory is loaded here. possibly 1.61 + ;; other things, too. 1.62 +(comment 1.63 + ;; temporarily intercept/adjust what pops out of the vending 1.64 + ;; machine. 1.65 + ;; (and how much it costs) 1.66 + 1.67 + ;; located at 0x4845 1.68 + ;; not to be confused with shop inventory, 0xCF7B 1.69 + (do 1.70 + (step (read-state "vend-menu")) 1.71 + (write-memory! (rewrite-memory (vec(memory)) 0x4845 [2 0 1 0])) 1.72 + (step @current-state [:a]) 1.73 + (step @current-state []) 1.74 + (nstep @current-state 200) )) 1.75 1.76 1.77 ;; Note: There are two tile tables, one from 8000-8FFF, the other from 1.78 ;; 8800-97FF. The latter contains symbols, possibly map tiles(?), with some japanese chars and stuff at the end. 1.79 (defn print-pixel-letters! 1.80 "The pixel tiles representing letters. Neat!" 1.81 - ([] (print-pixel-letters! (read-state "oak-speaks"))) 1.82 - ([state] 1.83 - (map 1.84 - (comp 1.85 - println 1.86 - (partial map #(if (zero? %) \space 0)) 1.87 - #(if (< (count %) 8) 1.88 - (recur (cons 0 %)) 1.89 - %) 1.90 - reverse bit-list) 1.91 + ([] (print-pixel-letters! (read-state "oak-speaks"))) 1.92 +([state] 1.93 + (map 1.94 + (comp 1.95 + println 1.96 + (partial map #(if (zero? %) \space 0)) 1.97 + #(if (< (count %) 8) 1.98 + (recur (cons 0 %)) 1.99 + %) 1.100 + reverse bit-list) 1.101 + 1.102 + (take 0xFFF (drop 0x8800 (memory state)))))) 1.103 + 1.104 + 1.105 +;; (defn test-2 [] 1.106 +;; (loop [n 0 1.107 +;; pc-1 (pc-trail (-> state-defend (tick) (step [:a]) (step [:a]) (step []) (nstep 100)) 100000) 1.108 +;; pc-2 (pc-trail (-> state-speed (tick) (step [:a]) (step [:a]) 1.109 +;; (step []) (nstep 100)) 100000)] 1.110 +;; (cond (empty? (drop n pc-1)) [pc-1 n] 1.111 +;; (not= (take 10 (drop n pc-1)) (take 10 pc-2)) 1.112 +;; (recur pc-1 pc-2 (inc n)) 1.113 +;; :else 1.114 +;; [(take 1000 pc-2) n]))) 1.115 + 1.116 + 1.117 + 1.118 + 1.119 +(defn test-3 1.120 + "Explore trainer data" 1.121 + ([] (test-3 0x3A289)) 1.122 + ([start] 1.123 + (let [pokenames (vec(hxc-pokenames-raw))] 1.124 + (println 1.125 + (reduce 1.126 + str 1.127 + (map 1.128 + (fn [[adr lvl pkmn]] 1.129 + (str (format "%-11s %4d %02X %02X \t %05X\n" 1.130 + 1.131 + (cond 1.132 + (zero? lvl) "+" 1.133 + (nil? (get pokenames (dec pkmn))) 1.134 + "-" 1.135 + :else 1.136 + (get pokenames (dec pkmn))) 1.137 + lvl 1.138 + pkmn 1.139 + lvl 1.140 + adr 1.141 + ))) 1.142 + (map cons 1.143 + (take-nth 2 (drop start (range))) 1.144 + (partition 2 1.145 + (take 400;;703 1.146 + (drop 1.147 + start 1.148 + ;; 0x3A75D 1.149 + (rom))))))))))) 1.150 + 1.151 +(defn search-memory* [mem codes k] 1.152 + (loop [index 0 1.153 + index-next 1 1.154 + start-match 0 1.155 + to-match codes 1.156 + matches []] 1.157 + (cond 1.158 + (>= index (count mem)) matches 1.159 + 1.160 + (empty? to-match) 1.161 + (recur 1.162 + index-next 1.163 + (inc index-next) 1.164 + index-next 1.165 + codes 1.166 + (conj matches 1.167 + [(hex start-match) (take k (drop start-match mem))]) 1.168 + ) 1.169 + 1.170 + (or (= (first to-match) \_) ;; wildcard 1.171 + (= (first to-match) (nth mem index))) 1.172 + (recur 1.173 + (inc index) 1.174 + index-next 1.175 + start-match 1.176 + (rest to-match) 1.177 + matches) 1.178 + 1.179 + :else 1.180 + (recur 1.181 + index-next 1.182 + (inc index-next) 1.183 + index-next 1.184 + codes 1.185 + matches)))) 1.186 1.187 - (take 0xFFF (drop 0x88000 (memory state)))))) 1.188 + 1.189 +(defn search-pattern [ptn coll] 1.190 + (loop 1.191 + [index 0 1.192 + to-match ptn 1.193 + binds {} 1.194 + 1.195 + next-index 1 1.196 + match-start 0 1.197 + matches []] 1.198 + 1.199 + (cond 1.200 + (>= index (count coll)) matches 1.201 + (empty? to-match) 1.202 + (recur 1.203 + next-index 1.204 + ptn 1.205 + {} 1.206 + (inc next-index) 1.207 + next-index 1.208 + (conj match-start 1.209 + [(hex match-start) binds])) 1.210 + 1.211 + :else 1.212 + (let [k (first to-match) 1.213 + v (nth coll index)] 1.214 + (cond 1.215 + (= k \_) ;; wildcard 1.216 + (recur 1.217 + (inc index) 1.218 + (rest to-match) 1.219 + binds 1.220 + 1.221 + next-index 1.222 + match-start 1.223 + matches) 1.224 + 1.225 + (keyword? k) 1.226 + (if (binds k) 1.227 + (if (= (binds k) v) 1.228 + 1.229 + ;; consistent bindings 1.230 + (recur 1.231 + (inc index) 1.232 + (rest to-match) 1.233 + binds 1.234 + 1.235 + next-index 1.236 + match-start 1.237 + matches) 1.238 + 1.239 + ;; inconsistent bindings 1.240 + (recur 1.241 + next-index 1.242 + ptn 1.243 + {} 1.244 + (inc next-index) 1.245 + next-index 1.246 + matches)) 1.247 + 1.248 + (if ((set (vals binds)) v) 1.249 + ;; bindings are not unique 1.250 + (recur 1.251 + next-index 1.252 + ptn 1.253 + {} 1.254 + (inc next-index) 1.255 + next-index 1.256 + matches) 1.257 + 1.258 + ;; bindings are unique 1.259 + (recur 1.260 + (inc index) 1.261 + (rest to-match) 1.262 + (assoc binds k v) 1.263 + 1.264 + next-index 1.265 + match-start 1.266 + matches))) 1.267 + 1.268 + :else ;; k is just a number 1.269 + (if (= k v) 1.270 + (recur 1.271 + (inc index) 1.272 + (rest to-match) 1.273 + binds 1.274 + 1.275 + next-index 1.276 + match-start 1.277 + matches) 1.278 + 1.279 + (recur 1.280 + next-index 1.281 + ptn 1.282 + {} 1.283 + (inc next-index) 1.284 + next-index 1.285 + matches))))))) 1.286 + 1.287 + 1.288 + 1.289 + 1.290 + 1.291 + 1.292 + 1.293 + 1.294 + 1.295 +(defn search-pattern* [ptn coll] 1.296 + (loop 1.297 + [ 1.298 + binds {} 1.299 + index 0 1.300 + index-next 1 1.301 + start-match 0 1.302 + to-match ptn 1.303 + matches []] 1.304 + 1.305 + (cond 1.306 + (>= index (count coll)) matches 1.307 + (empty? to-match) 1.308 + (recur 1.309 + {} 1.310 + index-next 1.311 + (inc index-next) 1.312 + index-next 1.313 + ptn 1.314 + (conj matches 1.315 + [(hex start-match) binds])) 1.316 + 1.317 + :else 1.318 + (let [k (first to-match) 1.319 + v (nth coll index)] 1.320 + (cond 1.321 + (= k \_) ;; wildcard 1.322 + (recur 1.323 + binds 1.324 + (inc index) 1.325 + index-next 1.326 + start-match 1.327 + (rest to-match) 1.328 + matches) 1.329 + 1.330 + (keyword? k) 1.331 + (if (binds k) 1.332 + (if (= (binds k) v) 1.333 + (recur 1.334 + binds 1.335 + (inc index) 1.336 + index-next 1.337 + start-match 1.338 + (rest to-match) 1.339 + matches) 1.340 + (recur 1.341 + {} 1.342 + index-next 1.343 + (inc index-next) 1.344 + index-next 1.345 + ptn 1.346 + matches)) 1.347 + (if 1.348 + ;; every symbol must be bound to a different thing. 1.349 + ((set (vals binds)) v) 1.350 + (recur 1.351 + {} 1.352 + index-next 1.353 + (inc index-next) 1.354 + index-next 1.355 + ptn 1.356 + matches) 1.357 + (recur 1.358 + (assoc binds k v) 1.359 + (inc index) 1.360 + index-next 1.361 + start-match 1.362 + (rest to-match) 1.363 + matches)))))))) 1.364 + 1.365 + 1.366 + 1.367 + 1.368 +;; look for the rainbow badge in memory 1.369 +(println (reduce str (map #(str (first %) "\t" (vec(second %)) "\n") (search-memory (rom) [221] 10)))) 1.370 1.371 1.372 (comment
2.1 --- a/org/rom.org Sat Apr 14 05:20:28 2012 -0500 2.2 +++ b/org/rom.org Sat Apr 14 09:27:49 2012 -0500 2.3 @@ -1094,7 +1094,7 @@ 2.4 #+begin_src clojure 2.5 (def hxc-places 2.6 "The hardcoded place names in memory. List begins at 2.7 -ROM@71500. [Cinnabar/Cerulean] Mansion seems to be dynamically calculated." 2.8 +ROM@71500. [Cinnabar/Celadon] Mansion seems to be dynamically calculated." 2.9 (hxc-thunk-words 0x71500 560)) 2.10 #+end_src 2.11 2.12 @@ -1148,9 +1148,111 @@ 2.13 2.14 2.15 2.16 +** Map data 2.17 + 2.18 +# http://www.pokecommunity.com/showthread.php?t=235311 2.19 +# http://datacrystal.romhacking.net/wiki/Pokemon_Red/Blue:Notes 2.20 + 2.21 +#+name map 2.22 +#+begin_src clojure :exports both :results output 2.23 +(ns com.aurellem.gb.hxc 2.24 + (:use (com.aurellem.gb assembly characters gb-driver util mem-util 2.25 + constants)) 2.26 + (:import [com.aurellem.gb.gb_driver SaveState])) 2.27 + 2.28 + 2.29 +(defn parse-header-tileset 2.30 + [[bank# ;; memory bank for blocks & tileset 2.31 + 2.32 + blocks-lo ;; structure 2.33 + blocks-hi 2.34 + 2.35 + tileset-lo ;; style 2.36 + tileset-hi 2.37 + 2.38 + collision-lo ;; collision info 2.39 + collision-hi 2.40 + 2.41 + talk-here-1 ;; positions of up to three 2.42 + talk-here-2 ;; talk-over-countertop tiles 2.43 + talk-here-3 ;; --- 0xFF if unused. 2.44 + 2.45 + grass ;; grass tile --- 0xFF if unused 2.46 + 2.47 + animation-flags ;; settings for animation 2.48 + & _]] 2.49 + 2.50 + [bank# 2.51 + 2.52 + blocks-lo ;; structure 2.53 + blocks-hi 2.54 + 2.55 + tileset-lo ;; style 2.56 + tileset-hi 2.57 + 2.58 + collision-lo ;; collision info 2.59 + collision-hi 2.60 + 2.61 + talk-here-1 ;; positions of up to three 2.62 + talk-here-2 ;; talk-over-countertop tiles 2.63 + talk-here-3 ;; --- 0xFF if unused. 2.64 + 2.65 + grass ;; grass tile --- 0xFF if unused 2.66 + 2.67 + animation-flags ;; settings for animation 2.68 + ]) 2.69 + 2.70 + 2.71 + 2.72 +(defn parse-header-map 2.73 + [start] 2.74 + 2.75 + (let [connection-size 11 2.76 + 2.77 + [tileset-index 2.78 + map-height 2.79 + map-width 2.80 + layout-lo 2.81 + layout-hi 2.82 + text-lo 2.83 + text-hi 2.84 + script-lo 2.85 + script-hi 2.86 + adjacency-flags ;; x x x x N S W E 2.87 + & etc] 2.88 + (drop start (rom)) 2.89 + 2.90 + [east? west? south? north?] 2.91 + (bit-list adjacency-flags) 2.92 + 2.93 + [connections object-data] 2.94 + (split-at 2.95 + (* connection-size (+ east? west? south? north?)) 2.96 + etc) 2.97 + 2.98 + connections 2.99 + (partition connection-size connections) 2.100 + 2.101 + 2.102 + 2.103 + 2.104 + ] 2.105 + (ptr->offset 2.106 + 3 2.107 + (low-high layout-lo layout-hi)) 2.108 + 2.109 + 2.110 + )) 2.111 +#+end_src 2.112 + 2.113 +#+results: 2.114 +: 2.115 + 2.116 + 2.117 2.118 * Appendices 2.119 ** Mapping the ROM 2.120 +# D3AD: Script:Use Pokeball? 2.121 2.122 | ROM address (hex) | Description | Format | Example | 2.123 |-----------------------+-----------------+-----------------+-----------------| 2.124 @@ -1174,11 +1276,19 @@ 2.125 | 0822E-082F? | Pointers to background music, part I. | | | 2.126 | 0CB95- | Pointers to lists of wild pokemon to encounter in each region. These lists begin at 04D89, see above. | Each pointer is a low-byte, high-byte pair. | The first entry is 0x89 0x4D, corresponding to the address 0x4D89, the location of the first list of wild Pok\eacute{}mon (see 04D89, above). | 2.127 |-----------------------+-----------------+-----------------+-----------------| 2.128 -| 0DADB. | Amount of HP restored by Hyper Potion. | The HP consists of a single byte. TODO: Discover what the surrounding data does, and find the data for the amount of HP restored by other items: Fresh Water (50HP), Soda (60HP), Lemonade(80HP). | 200 | 2.129 +| 0DACB. | Amount of HP restored by Soda Pop | The HP consists of a single numerical byte. | 60 | 2.130 +| 0DACF. | Amount of HP restored by Lemonade | " | 80 | 2.131 +| 0DAD5. | Amount of HP restored by Fresh Water | " | 50 | 2.132 +| 0DADB. | Amount of HP restored by Hyper Potion. | " | 200 | 2.133 | 0DAE0. | Amount of HP restored by Super Potion. | " | 50 | 2.134 | 0DAE3. | Amount of HP restored by Potion. | " | 20 | 2.135 |-----------------------+-----------------+-----------------+-----------------| 2.136 | 0DD4D-DD72 | Names of permanent stats. | Variable-length strings separated by 0x50. | #HEALTH#ATTACK#DEFENSE#SPEED#SPECIAL# | 2.137 +|-----------------------+-----------------+-----------------+-----------------| 2.138 +| 0DE2F. | Duration of Repel. | A single byte, representing the number of steps you can take before Super Repel wears off. | 100 | 2.139 +| 0DF39. | Duration of Super Repel. | " | 200 | 2.140 +| 0DF3E. | Duration of Max Repel. | " | 250 | 2.141 +|-----------------------+-----------------+-----------------+-----------------| 2.142 | 1164B- | Terminology for the Pok\eacute{}mon menu. | Contiguous, variable-length strings. | TYPE1[newline]TYPE2[newline] *№*,[newline]OT,[newline][0x50]STATUS,[0x50]OK | 2.143 | 116DE- | Terminology for permanent stats in the Pok\eacute{}mon menu. | Contiguous, variable-length strings. | ATTACK[newline]DEFENSE[newline]SPEED[newline]SPECIAL[0x50] | 2.144 | 11852- | Terminology for current stats in the Pok\eacute{}mon menu. | Contiguous, variable-length strings. | EXP POINTS[newline]LEVEL UP[0x50] | 2.145 @@ -1214,6 +1324,9 @@ 2.146 | 41072- | Pok\eacute{} placeholder species, "???" | | | 2.147 |-----------------------+-----------------+-----------------+-----------------| 2.148 | 410B1-4116F | A conversion table between internal order and Pokedex order. | 190 bytes, corresponding to the Pok\eacute{}dex numbers of the 190 Pok\eacute{}mon listed in internal order. All =MISSINGNO.= are assigned a Pok\eacute{}dex number of 0. | The first few entries are (112 115 32 35 21 100 34 80 2 ...), which are the Pok\eacute{}dex numbers of Rhydon, Kangaskhan, Nidoran(m), Clefairy, Spearow, Voltorb, Nidoking, Slobrow, and Ivysaur. | 2.149 +|-----------------------+-----------------+-----------------+-----------------| 2.150 +| 509B4-509E0 | Saffron City's adjacency info. | Four adjacency lists, each 11 bytes long. (For more info on adjacency lists a.k.a. connection data, see [[http://datacrystal.romhacking.net/wiki/Pokemon_Red/Blue:Notes][here]]) | The first adjacency list is (0x10 0x70 0x46 0xF0 0xC6 0x0A 0x0A 0x23 0xF6 0x09 0xC8) | 2.151 +|-----------------------+-----------------+-----------------+-----------------| 2.152 | 527BA-527DB | The costs and kinds of prizes from Celadon Game Corner. | The following pattern repeats three times, once per window[fn::For the first two prize lists, ids are interpreted as Pok\eacute{}mon ids. For the last prize list, ids are (somehow) interpreted as item ids.]: Internal ids / 0x50 / Prices (two bytes of BCD)/ 0x50. | (0x94 0x52 0x65 0x50) Abra Vulpix Wigglytuff (0x02 0x30 0x10 0x00 0x26 0x80) 230C, 1000C, 2680C | 2.153 | 5DE10-5DE30 | Abbreviations for status ailments. | Fixed-length strings, probably[fn::Here's something strange: all of the status messages start with 0x7F and end with 0x4F \mdash{}except PAR, which ends with 0x50.]. The last entry is QUIT##. | [0x7F] *SLP* [0x4E][0x7F] *PSN* [0x4E][0x7F] *PAR* [0x50][0x7F]... | 2.154 |-----------------------+-----------------+-----------------+-----------------| 2.155 @@ -1770,6 +1883,22 @@ 2.156 2.157 ;; note: 0x251A (in indexable mem): image decompression routine seems to begin here. 2.158 2.159 +;; note: 0x4845 (index): vending inventory is loaded here. possibly 2.160 + ;; other things, too. 2.161 +(comment 2.162 + ;; temporarily intercept/adjust what pops out of the vending 2.163 + ;; machine. 2.164 + ;; (and how much it costs) 2.165 + 2.166 + ;; located at 0x4845 2.167 + ;; not to be confused with shop inventory, 0xCF7B 2.168 + (do 2.169 + (step (read-state "vend-menu")) 2.170 + (write-memory! (rewrite-memory (vec(memory)) 0x4845 [2 0 1 0])) 2.171 + (step @current-state [:a]) 2.172 + (step @current-state []) 2.173 + (nstep @current-state 200) )) 2.174 + 2.175 2.176 ;; Note: There are two tile tables, one from 8000-8FFF, the other from 2.177 ;; 8800-97FF. The latter contains symbols, possibly map tiles(?), with some japanese chars and stuff at the end. 2.178 @@ -1870,8 +1999,218 @@ 2.179 index-next 2.180 codes 2.181 matches)))) 2.182 - 2.183 - 2.184 + 2.185 + 2.186 +(def script-use-ball 2.187 + [0xFA ;; ld A, nn 2.188 + \_ 2.189 + \_ 2.190 + 0xA7 ;; and A 2.191 + 0xCA ;; JP Z 2.192 + \_ 2.193 + \_ 2.194 + 0x3D ;; dec A 2.195 + 0xC2 ;; JP NZ 2.196 + \_ 2.197 + \_ 2.198 + 0xFA ;; LD A 2.199 + \_ 2.200 + \_ 2.201 + ]) 2.202 + 2.203 + 2.204 + 2.205 +(defn search-pattern [ptn coll] 2.206 + (loop 2.207 + [index 0 2.208 + to-match ptn 2.209 + binds {} 2.210 + 2.211 + next-index 1 2.212 + match-start 0 2.213 + matches []] 2.214 + 2.215 + (cond 2.216 + (>= index (count coll)) matches 2.217 + (empty? to-match) 2.218 + (recur 2.219 + next-index 2.220 + ptn 2.221 + {} 2.222 + (inc next-index) 2.223 + next-index 2.224 + (conj match-start 2.225 + [(hex match-start) binds])) 2.226 + 2.227 + :else 2.228 + (let [k (first to-match) 2.229 + v (nth coll index)] 2.230 + (cond 2.231 + (= k \_) ;; wildcard 2.232 + (recur 2.233 + (inc index) 2.234 + (rest to-match) 2.235 + binds 2.236 + 2.237 + next-index 2.238 + match-start 2.239 + matches) 2.240 + 2.241 + (keyword? k) 2.242 + (if (binds k) 2.243 + (if (= (binds k) v) 2.244 + (recur 2.245 + (inc index) 2.246 + (rest to-match) 2.247 + binds 2.248 + next-index 2.249 + match-start 2.250 + matches) 2.251 + 2.252 + (recur 2.253 + next-index 2.254 + ptn 2.255 + {} 2.256 + (inc next-index) 2.257 + next-index 2.258 + matches)) 2.259 + 2.260 + ;; ;; consistent bindings 2.261 + ;; (recur 2.262 + ;; (inc index) 2.263 + ;; (rest to-match) 2.264 + ;; binds 2.265 + 2.266 + ;; next-index 2.267 + ;; match-start 2.268 + ;; matches) 2.269 + 2.270 + ;; ;; inconsistent bindings 2.271 + ;; (recur 2.272 + ;; next-index 2.273 + ;; ptn 2.274 + ;; {} 2.275 + ;; (inc next-index) 2.276 + ;; next-index 2.277 + ;; matches)) 2.278 + 2.279 + (if ((set (vals binds)) v) 2.280 + ;; bindings are not unique 2.281 + (recur 2.282 + next-index 2.283 + ptn 2.284 + {} 2.285 + (inc next-index) 2.286 + next-index 2.287 + matches) 2.288 + 2.289 + ;; bindings are unique 2.290 + (recur 2.291 + (inc index) 2.292 + (rest to-match) 2.293 + (assoc binds k v) 2.294 + 2.295 + next-index 2.296 + match-start 2.297 + matches))) 2.298 + 2.299 + :else ;; k is just a number 2.300 + (if (= k v) 2.301 + (recur 2.302 + (inc index) 2.303 + (rest to-match) 2.304 + binds 2.305 + 2.306 + next-index 2.307 + match-start 2.308 + matches) 2.309 + 2.310 + (recur 2.311 + next-index 2.312 + ptn 2.313 + {} 2.314 + (inc next-index) 2.315 + next-index 2.316 + matches))))))) 2.317 + 2.318 + 2.319 + 2.320 + 2.321 + 2.322 + 2.323 + 2.324 + 2.325 + 2.326 +(defn search-pattern* [ptn coll] 2.327 + (loop 2.328 + [ 2.329 + binds {} 2.330 + index 0 2.331 + index-next 1 2.332 + start-match 0 2.333 + to-match ptn 2.334 + matches []] 2.335 + 2.336 + (cond 2.337 + (>= index (count coll)) matches 2.338 + (empty? to-match) 2.339 + (recur 2.340 + {} 2.341 + index-next 2.342 + (inc index-next) 2.343 + index-next 2.344 + ptn 2.345 + (conj matches 2.346 + [(hex start-match) binds])) 2.347 + 2.348 + :else 2.349 + (let [k (first to-match) 2.350 + v (nth coll index)] 2.351 + (cond 2.352 + (= k \_) ;; wildcard 2.353 + (recur 2.354 + binds 2.355 + (inc index) 2.356 + index-next 2.357 + start-match 2.358 + (rest to-match) 2.359 + matches) 2.360 + 2.361 + (keyword? k) 2.362 + (if (binds k) 2.363 + (if (= (binds k) v) 2.364 + (recur 2.365 + binds 2.366 + (inc index) 2.367 + index-next 2.368 + start-match 2.369 + (rest to-match) 2.370 + matches) 2.371 + (recur 2.372 + {} 2.373 + index-next 2.374 + (inc index-next) 2.375 + index-next 2.376 + ptn 2.377 + matches)) 2.378 + (if 2.379 + ;; every symbol must be bound to a different thing. 2.380 + ((set (vals binds)) v) 2.381 + (recur 2.382 + {} 2.383 + index-next 2.384 + (inc index-next) 2.385 + index-next 2.386 + ptn 2.387 + matches) 2.388 + (recur 2.389 + (assoc binds k v) 2.390 + (inc index) 2.391 + index-next 2.392 + start-match 2.393 + (rest to-match) 2.394 + matches)))))))) 2.395 + 2.396 2.397 2.398