Mercurial > pokemon-types
comparison org/types.org @ 7:d6b8dab05d9d
better explination of dual types
author | Robert McIntyre <rlm@mit.edu> |
---|---|
date | Wed, 02 Nov 2011 06:48:40 -0700 |
parents | 3f26fc68ffbc |
children | 4f9ef752e2f0 |
comparison
equal
deleted
inserted
replaced
6:3f26fc68ffbc | 7:d6b8dab05d9d |
---|---|
1 #+TITLE: Breadth-first Search for Effective Pokemon Types | 1 #+TITLE: Best-First Search for Effective Pokemon Types |
2 #+AUTHOR: Robert McIntyre & Dylan Holmes | 2 #+AUTHOR: Robert McIntyre & Dylan Holmes |
3 #+EMAIL: rlm@mit.edu | 3 #+EMAIL: rlm@mit.edu |
4 #+description: Finding interesting pokemon type combinations through Best-First search in clojure. | |
4 #+SETUPFILE: ../../aurellem/org/setup.org | 5 #+SETUPFILE: ../../aurellem/org/setup.org |
5 #+INCLUDE: ../../aurellem/org/level-0.org | 6 #+INCLUDE: ../../aurellem/org/level-0.org |
6 | 7 |
7 * The Pok\eacute{}mon Type System | 8 * The Pok\eacute{}mon Type System |
8 | 9 |
47 introduction of pok\eacute{}mon Gold and Silver, and has been in use | 48 introduction of pok\eacute{}mon Gold and Silver, and has been in use |
48 ever since. It is called the /Generation II Type System/. | 49 ever since. It is called the /Generation II Type System/. |
49 | 50 |
50 Here are the the definitions of the two type systems. | 51 Here are the the definitions of the two type systems. |
51 | 52 |
52 * The Pok\eacute{}mon Type Systems | 53 * Generation I and II Type System Data |
53 | 54 |
54 ** Generation II Type System | 55 ** Generation II Type System |
55 #+label: pokemon-matchups | 56 #+label: pokemon-matchups |
56 #+tblname: pokemon-table-gen-two | 57 #+tblname: pokemon-table-gen-two |
57 | | normal | fire | water | electric | grass | ice | fighting | poison | ground | flying | psychic | bug | rock | ghost | dragon | dark | steel | | 58 | | normal | fire | water | electric | grass | ice | fighting | poison | ground | flying | psychic | bug | rock | ghost | dragon | dark | steel | |
77 The rows are attack types, while the columns are defense types. To | 78 The rows are attack types, while the columns are defense types. To |
78 see the multiplier for a pokemon attack against a certain type, follow | 79 see the multiplier for a pokemon attack against a certain type, follow |
79 the row for the attack type to the column of the defending type. | 80 the row for the attack type to the column of the defending type. |
80 | 81 |
81 ** Generation I Type System | 82 ** Generation I Type System |
82 #+label: pokemon-matchups-gen-1 +tblname: pokemon-table-gen-one | 83 #+label: pokemon-matchups-gen-1 |
84 #+tblname: pokemon-table-gen-one | |
83 | | normal | fire | water | electric | grass | ice | fighting | poison | ground | flying | psychic | bug | rock | ghost | dragon | | 85 | | normal | fire | water | electric | grass | ice | fighting | poison | ground | flying | psychic | bug | rock | ghost | dragon | |
84 |----------+--------+------+-------+----------+-------+-----+----------+--------+--------+--------+---------+-----+------+-------+--------| | 86 |----------+--------+------+-------+----------+-------+-----+----------+--------+--------+--------+---------+-----+------+-------+--------| |
85 | normal | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | .5 | 0 | 1 | | 87 | normal | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | .5 | 0 | 1 | |
86 | fire | 1 | .5 | .5 | 1 | 2 | 2 | 1 | 1 | 1 | 1 | 1 | 2 | .5 | 1 | .5 | | 88 | fire | 1 | .5 | .5 | 1 | 2 | 2 | 1 | 1 | 1 | 1 | 1 | 2 | .5 | 1 | .5 | |
87 | water | 1 | 2 | .5 | 1 | .5 | 1 | 1 | 1 | 2 | 1 | 1 | 1 | 2 | 1 | .5 | | 89 | water | 1 | 2 | .5 | 1 | .5 | 1 | 1 | 1 | 2 | 1 | 1 | 1 | 2 | 1 | .5 | |
99 | dragon | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 2 | | 101 | dragon | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 2 | |
100 | 102 |
101 | 103 |
102 This is the old table from Generation I. The differences from | 104 This is the old table from Generation I. The differences from |
103 Generation II are: | 105 Generation II are: |
104 - Dark and Steel are missing. | 106 - Dark and Steel types are missing (these were introduced in |
105 - Bug is super-effective against Poison. | 107 Generation II). |
106 - Poison is super-effective against Bug. | 108 - Bug is super-effective against Poison (not-very-effective in |
107 - Bug is regularly effective against Ghost (instead of | 109 Generation II). |
108 super-effective like in Generation II). | 110 - Poison is super-effective against Bug (normal in Generation II). |
109 - Ice is normally effective against Fire, (it's not-very-effective in | 111 - Bug is regularly effective against Ghost (super-effective in |
112 Generation II). | |
113 - Ice is normally effective against Fire, (not-very-effective in | |
110 Generation II). | 114 Generation II). |
111 - Ghost is completely ineffective against Psychic. This is considered | 115 - Ghost is completely ineffective against Psychic. This is considered |
112 to be a programning glitch. | 116 to be a programning glitch. |
113 | 117 |
114 | 118 |
115 | 119 |
116 * Representing the Data | 120 * Representing the Data |
117 | 121 |
118 After creating the Pok\eacute{}mon types namespace, we store the table | 122 After creating the Pok\eacute{}mon types namespace, we store the |
119 of susceptibilities in =pokemon-table-gen-one= and | 123 tables of susceptibilities above in =pokemon-table-gen-one= and |
120 =pokemon-table-gen-two=, each of which is a simple vector of | 124 =pokemon-table-gen-two=, each of which is a simple vector of |
121 vectors. Because a vector of vectors can be cumbersome, we do not | 125 vectors. Because a vector of vectors can be cumbersome, we do not |
122 access the tables directly; instead, we use the derivative structures | 126 access the tables directly; instead, we use the derivative structures |
123 =attack-strengths= and =defense-strengths=, which are functions which | 127 =attack-strengths= and =defense-strengths=, which are functions which |
124 return hash-maps associating each row (respectively column) of the | 128 return hash-maps associating each row (respectively column) of the |
125 table with its corresponding Pok\eacute{}mon type. | 129 table with its corresponding Pok\eacute{}mon type. |
126 | 130 |
127 | 131 |
128 | |
129 #+srcname: header | 132 #+srcname: header |
130 #+begin_src clojure :results silent | 133 #+begin_src clojure :results silent |
131 (ns pokemon.types | 134 (ns pokemon.types |
132 (:use rlm.ns-rlm)) | 135 (:use clojure.set) |
133 (rlm.ns-rlm/ns-clone rlm.light-base) | 136 (:use clojure.contrib.combinatorics) |
134 (use 'clojure.set) | 137 (:use clojure.contrib.math) |
135 #+end_src | 138 (:use clojure.contrib.def) |
136 | 139 (:use rlm.rlm-commands)) |
137 #+srcname: data(pokemon-table-gen-one=pokemon-table-gen-one, pokemon-table-gen-two=pokemon-table-gen-two) | 140 #+end_src |
141 | |
142 #+srcname: data | |
138 #+begin_src clojure :results silent | 143 #+begin_src clojure :results silent |
139 (in-ns 'pokemon.types) | 144 (in-ns 'pokemon.types) |
140 ;; record type strengths as a vector of vectors | 145 ;; record type strengths as a vector of vectors |
146 ;; the variables pokemon-table-gen-one and pokemon-table-gen-two | |
147 ;; are replaced with the tables above when this file is tangled. | |
141 (def pokemon-gen-one pokemon-table-gen-one) | 148 (def pokemon-gen-one pokemon-table-gen-one) |
142 (def pokemon-gen-two pokemon-table-gen-two) | 149 (def pokemon-gen-two pokemon-table-gen-two) |
143 | 150 |
144 (defn type-names [] (vec (doall (map (comp keyword first) pokemon-gen-two)))) | 151 (defn type-names [] (vec (doall (map (comp keyword first) pokemon-gen-two)))) |
145 | 152 |
152 (zipmap (type-names) | 159 (zipmap (type-names) |
153 (map | 160 (map |
154 (apply juxt (map (attack-strengths) (type-names))) | 161 (apply juxt (map (attack-strengths) (type-names))) |
155 (range (count (type-names)))))) | 162 (range (count (type-names)))))) |
156 #+end_src | 163 #+end_src |
164 | |
165 The two statements | |
166 | |
167 #+begin_src clojure :exports code | |
168 (def pokemon-gen-one pokemon-table-gen-one) | |
169 (def pokemon-gen-two pokemon-table-gen-two) | |
170 #+end_src | |
171 | |
172 probably look weird. When the actual source file is created, those | |
173 variables are replaced with the data from the tables above. | |
174 | |
175 See [[../src/pokemon/types.clj][types.clj]] to look at the final tangled output. | |
176 | |
157 | 177 |
158 #+begin_src clojure :results output :exports both | 178 #+begin_src clojure :results output :exports both |
159 (clojure.pprint/pprint pokemon.types/pokemon-gen-two) | 179 (clojure.pprint/pprint pokemon.types/pokemon-gen-two) |
160 #+end_src | 180 #+end_src |
161 | 181 |
178 ("dragon" 1 1 1 1 1 1 1 1 1 1 1 1 1 1 2 1 0.5) | 198 ("dragon" 1 1 1 1 1 1 1 1 1 1 1 1 1 1 2 1 0.5) |
179 ("dark" 1 1 1 1 1 1 0.5 1 1 1 2 1 1 2 1 0.5 0.5) | 199 ("dark" 1 1 1 1 1 1 0.5 1 1 1 2 1 1 2 1 0.5 0.5) |
180 ("steel" 1 0.5 0.5 0.5 1 2 1 1 1 1 1 1 2 1 1 1 0.5)) | 200 ("steel" 1 0.5 0.5 0.5 1 2 1 1 1 1 1 1 2 1 1 1 0.5)) |
181 #+end_example | 201 #+end_example |
182 | 202 |
183 =pokemon-gen-two= is a simple list-of-list data structure. | 203 =pokemon-gen-two= is a simple list-of-lists data structure. |
184 | 204 |
185 #+begin_src clojure :results output :exports both | 205 #+begin_src clojure :results output :exports both |
186 (clojure.pprint/pprint (pokemon.types/defense-strengths)) | 206 (clojure.pprint/pprint (pokemon.types/defense-strengths)) |
187 #+end_src | 207 #+end_src |
188 | 208 |
205 :dark [1 1 1 1 1 1 2 1 1 1 0 2 1 0.5 1 0.5 1], | 225 :dark [1 1 1 1 1 1 2 1 1 1 0 2 1 0.5 1 0.5 1], |
206 :steel [0.5 2 1 1 0.5 0.5 2 0 2 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5], | 226 :steel [0.5 2 1 1 0.5 0.5 2 0 2 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5], |
207 :bug [1 2 1 1 0.5 1 0.5 1 0.5 2 1 1 2 1 1 1 1]} | 227 :bug [1 2 1 1 0.5 1 0.5 1 0.5 2 1 1 2 1 1 1 1]} |
208 #+end_example | 228 #+end_example |
209 | 229 |
210 =defense-strengths= is a more convenient form of =pokemon-gen-two=, with key/value pair access. | 230 =defense-strengths= is a more convenient form of =pokemon-gen-two=, |
231 with key/value pair access. | |
211 | 232 |
212 * Interfacing with the Data | 233 * Interfacing with the Data |
234 | |
235 In the pok\eacute{}mon games, a pok\eacute{}mon can have up to two | |
236 types at the same time. For example, Zapdos, the fearsome legendary | |
237 that can control lightning, has both the Electric and Flying types. A | |
238 pok\eacute{}mon with more than one type gains the advantages and | |
239 disadvanteags of both types. The suceptibilitys of each type are | |
240 multiplied together to produce the hybrid type's susceptibilities. For | |
241 example, Electric is weak to Ground (susceptibility of 2), but Flying | |
242 is immune to Ground (suceptibility of 0). Zapdos' type, | |
243 Electrig/Flying, is immune to Ground because $2 \times 0 = 0$. | |
244 | |
213 #+srcname: types | 245 #+srcname: types |
214 #+begin_src clojure :results silent | 246 #+begin_src clojure :results silent |
215 (in-ns 'pokemon.types) | 247 (in-ns 'pokemon.types) |
216 | 248 |
217 (defn multitypes "All combinations of up to n types" [n] | 249 (defn multitypes "All combinations of up to n types" [n] |
219 (map vec | 251 (map vec |
220 (reduce concat | 252 (reduce concat |
221 (map (partial combinations (type-names)) | 253 (map (partial combinations (type-names)) |
222 (range 1 (inc n))))))) | 254 (range 1 (inc n))))))) |
223 | 255 |
224 (defn susceptibility ;; susceptibility-map | 256 (defn susceptibility |
225 "Hash-map of the susceptibilities of the given type combination | 257 "Hash-map of the susceptibilities of the given type combination |
226 to each type of attack" | 258 to each type of attack" |
227 [pkmn-types] | 259 [pkmn-types] |
228 (rlm.map-utils/map-vals | 260 (rlm.map-utils/map-vals |
229 clojure.core/rationalize | 261 clojure.core/rationalize |
230 (apply hash-map | 262 (apply hash-map |
231 (interleave (type-names) | 263 (interleave (type-names) |
232 (apply (partial map *) | 264 (apply (partial map *) |
233 (map (defense-strengths) pkmn-types)))))) | 265 (map (defense-strengths) pkmn-types)))))) |
234 | 266 |
235 (defn susceptance ;; susceptibility | 267 (defn susceptance |
236 "The cumulative susceptibility of the given type combination" | 268 "The cumulative susceptibility of the given type combination" |
237 [types] | 269 [types] |
238 (reduce + (map sqr (vals (susceptibility types))))) | 270 (reduce + (map #(expt % 2) (vals (susceptibility types))))) |
239 #+end_src | 271 #+end_src |
272 | |
273 Now we can work out the suceptability of Zapdos automatically. | |
274 | |
275 Electric is weak to Ground. | |
276 #+begin_src clojure :exports both | |
277 (:ground (pokemon.types/susceptibility [:electric])) | |
278 #+end_src | |
279 | |
280 #+results: | |
281 : 2 | |
282 | |
283 Flying is immune to Ground. | |
284 #+begin_src clojure :exports both | |
285 (:ground (pokemon.types/susceptibility [:flying])) | |
286 #+end_src | |
287 | |
288 #+results: | |
289 : 0 | |
290 | |
291 Together, they are immune to Ground. | |
292 #+begin_src clojure :exports both | |
293 (:ground (pokemon.types/susceptibility [:electric :flying])) | |
294 #+end_src | |
295 | |
296 #+results: | |
297 : 0 | |
298 | |
299 | |
300 | |
240 | 301 |
241 * Best-First Search | 302 * Best-First Search |
242 | 303 |
243 I'd like to find type combinations that are interesting, but the total | 304 I'd like to find type combinations that are interesting, but the total |
244 number of combinations gets huge as we begin to consider more | 305 number of combinations gets huge as we begin to consider more |
245 types. For example, the total possible number of type combinations | 306 types. For example, the total possible number of type combinations |
246 given just 8 possible types is: 17^{8} = 6975757441 combinations. | 307 given just 8 possible types is: 17^{8} = 6,975,757,441 combinations. |
247 Therefore, it's prudent to use search. | 308 Therefore, it's prudent to use search. |
248 | 309 |
249 These functions are a simple implementation of best-first search in | 310 These functions are a simple implementation of best-first search in |
250 clojure. The idea to start off with a collection of nodes and some way | 311 clojure. The idea to start off with a collection of nodes and some way |
251 of finding the best node, and to always expand the best node at every | 312 of finding the best node, and to always expand the best node at every |