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