1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
|
#lang racket
(require net/url
net/url-connect
json
slideshow/pict
racket/draw)
;; let's try to make a pokedex in racket!
;; first step will be to write a function to query the pokeAPI
;; like so, https://pokeapi.co/api/v2/pokemon/ditto
;; once there is a function in place that returns data I will
;; have a choice to make -- do I want to always query the API,
;; do I want to cache results, or do I want to create an offline
;; repository of poke-data to search through and sometimes update?
;; API URL
(define *POKE-API* "https://pokeapi.co/api/v2/")
(define (get-pokemon id)
"queries the api, returns a butt ton of info"
(call/input-url (string->url (~a *POKE-API* "pokemon/" id)) ; ~a, like string-append but appends *either* strings or numbers to a string
get-pure-port
(compose string->jsexpr port->string))) ; QUESTION: could I use read-json here, instead?
(define (dex-entry id)
"selects the info we need from the api, builds a hash table of the data that will build the entry"
(let ([poke-data (get-pokemon id)])
(define entry-data (make-hash))
(hash-set! entry-data "name" (hash-ref poke-data 'name))
(hash-set! entry-data "id" (hash-ref poke-data 'id))
(hash-set! entry-data "sprite" (hash-ref (hash-ref poke-data 'sprites) 'front_default))
(hash-set! entry-data "stats" (hash-ref poke-data 'stats))
(hash-set! entry-data "types" (hash-ref poke-data 'types))
entry-data))
(define (inspector h)
"display the contents of a hash table for human eyeballs and let the hash table fall back out"
(hash-map h
(lambda (k v)
(if (list? v) (map ; consider making this if a cond and testing for lists/hash tables to recursively dive into nested data
(lambda (x) (inspector x)) v)
(display (~a " key: " k "\nvalue: " v "\n=====\n")))))
h)
; (inspector (dex-entry 11))
; (inspector (dex-entry "bulbasaur"))
(define (capitalize-first-letter str)
"utility to capitalize the first letter of a string"
(cond
[(non-empty-string? str)
(define first-letter-str
(substring str 0 1))
(define rest-str
(substring str 1 (string-length str)))
(string-append (string-upcase first-letter-str)
rest-str)]
[else ""]))
(define (get-image id sprite-file-name)
"download a sprite"
(define img (hash-ref (dex-entry id) "sprite"))
(define img-url
(string->url img))
(define the-data
(parameterize ([current-https-protocol 'secure])
(port->bytes (get-pure-port img-url))))
(define out (open-output-file sprite-file-name))
(write-bytes the-data out)
(close-output-port out)
(display-image sprite-file-name))
(define (display-image image)
"display a sprite"
(define display-image (bitmap (make-object bitmap% image)))
(frame (scale display-image 1)))
(define (see-pokemon id)
"check to see if we've already got a sprite, if we don't, get it"
(define sprite-file-name
(~a "imgs/" id ".png"))
(if (file-exists? sprite-file-name)
(display-image sprite-file-name)
(get-image id sprite-file-name)))
; (see-pokemon "bulbasaur")
; (see-pokemon "butterfree")
; (see-pokemon "pikachu")
; (see-pokemon 33)
;; FIXME: I'd very much like to sort out how to display stats, types, and maybe the evolution chain.
(define (poke id [debug #f])
"display some basic info about a pokemon given it's name or id"
(define poke-data (dex-entry id))
(when debug
(inspector poke-data))
(displayln (~a "name: "
(capitalize-first-letter (hash-ref poke-data "name"))))
(displayln (~a "id: " (hash-ref poke-data "id")))
(see-pokemon (hash-ref poke-data "name"))) ; using name here prevents duplicate files with different names, id.png v name.png
(poke "zapdos")
(poke 74)
(poke "charizard")
(poke "slowking")
(poke "slowbro")
(poke "slowpoke")
(poke "kingler")
|