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
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
|
to crypto :text
make "text map "uppercase :text
make "fulltext :text
make "moretext []
make "textstack []
if not procedurep "letterp [copydef "letterp "namep]
forletters "A "Z "initvars
make "maxcount 0
initcount "single
initcount "triple
cleartext
histogram :text
redisplay "false
if or guess.single guess.triple [showclear :text]
parseloop
end
;; Initialization
to initcount :type
setlist. :type []
setcount. :type 0
end
to initvars :letter
setcnt :letter 0
make :letter "| |
setunbound :letter
end
;; Histogram
to histogram :text
foreach :text [localmake "word filter "letterp ?
foreach :word "histlet
prepare.guess :word]
end
to histlet :letter
localmake "cnt 1+cnt :letter
setcursor list (index :letter) (nonneg 24-:cnt)
type :letter
setcnt :letter :cnt
if :maxcount < :cnt [make "maxcount :cnt]
end
;; Guessing letters
to prepare.guess :word
if equalp count :word 1 [tally "single :word]
if equalp count :word 3 [tally "triple :word]
end
to tally :type :word
localmake "countvar word :type :word
if not memberp :word list. :type ~
[setlist. :type fput :word list. :type make :countvar 0]
localmake "count (thing :countvar)+1
make :countvar :count
if :count > (count. :type) ~
[setcount. :type :count setmax. :type :word]
end
to guess.single
if emptyp (list. "single) [output "false]
if emptyp butfirst (list. "single) ~
[qbind first (list. "single) "A output "true]
qbind (max. "single) "A
qbind (ifelse equalp first (list. "single) (max. "single)
[last (list. "single)]
[first (list. "single)]) ~
"I
output "true
end
to guess.triple
if emptyp (list. "triple) [output "false]
if :maxcount < (3+cnt last (max. "triple)) ~
[qbind first (max. "triple) "T
qbind first butfirst (max. "triple) "H
qbind last (max. "triple) "E
output "true]
output "false
end
;; Keyboard commands
to parseloop
forever [parsekey uppercase readchar]
end
to parsekey :char
if :char = "@ [fullclear stop]
if :char = "+ [moretext stop]
if :char = "- [lesstext stop]
if not letterp :char [beep stop]
bind :char uppercase readchar
end
;; Keeping track of guesses
to bind :from :to
if not equalp :to "| | [if not letterp :to [beep stop]
if boundp :to [beep stop]]
if letterp thing :from [dark thing :from]
make :from :to
fixtop :from
if letterp :to [light :to]
showclear :text
end
to qbind :from :to
if letterp thing :from [stop]
make :from :to
fixtop :from
light :to
end
;; Maintaining the display
to redisplay :flag
cleartext
showtop
alphabet
showcode :text
if :flag [showclear :text]
end
;; Top section of display (letter counts and guesses)
to showtop
setcursor [0 0]
showrow "A "E
showrow "F "J
showrow "K "O
showrow "P "T
showrow "U "Y
showrow "Z "Z
end
to showrow :from :to
forletters :from :to [setposn ? cursor onetop ?]
print []
end
to onetop :letter
localmake "count cnt :letter
if :count = 0 [type word :letter "| | stop]
localmake "text (word :letter "- twocol :count "- thing :letter)
ifelse :maxcount < :count+3 [invtype :text] [type :text]
type "| |
end
to twocol :number
if :number > 9 [output :number]
output word 0 :number
end
to fixtop :letter
setcursor posn :letter
onetop :letter
end
;; Middle section of display (guessed cleartext letters)
to alphabet
setcursor [6 6]
forletters "A "Z [ifelse boundp ? [invtype ?] [type ?]]
end
to light :letter
setcursor list 6+(index :letter) 6
invtype :letter
setbound :letter
end
to dark :letter
setcursor list 6+(index :letter) 6
type :letter
setunbound :letter
end
;; Bottom section of display (coded text)
to showcode :text
make "moretext []
showcode1 8 0 :text
end
to showcode1 :row :col :text
if emptyp :text [make "moretext [] stop]
if :row > 22 [stop]
if and equalp :row 16 equalp :col 0 [make "moretext :text]
if (:col+count first :text) > 37 [showcode1 :row+2 0 :text stop]
codeword :row :col first :text
showcode1 :row (:col+1+count first :text) butfirst :text
end
to codeword :row :col :word
setcursor list :col :row
invtype :word
end
;; Bottom section of display (cleartext)
to showclear :text
showclear1 8 0 :text 2
end
to showclear1 :row :col :text :delta
if emptyp :text [stop]
if :row > 23 [stop]
if keyp [stop]
if (:col+count first :text) > 37 ~
[showclear1 :row+:delta 0 :text :delta stop]
clearword :row :col first :text
showclear1 :row (:col+1+count first :text) butfirst :text :delta
end
to clearword :row :col :word
setcursor list :col :row+1
foreach :word [ifelse letterp ? [type thing ?] [type ?]]
end
;; Windowing commands
to fullclear
cleartext
showclear1 0 0 :fulltext 1
print []
invtype [type any char to redisplay]
ignore readchar
redisplay "true
end
to moretext
if emptyp :moretext [beep stop]
push "textstack :text
make "text :moretext
redisplay "true
end
to lesstext
if emptyp :textstack [beep stop]
make "text pop "textstack
redisplay "true
end
;; Iteration tool for letters
to forletters :from :to :action
for [lettercode [ascii :from] [ascii :to]] ~
[apply :action (list char :lettercode)]
end
;; Data abstraction (constructors and selectors)
to setbound :letter
make word "bound :letter "true
end
to setunbound :letter
make word "bound :letter "false
end
to boundp :letter
output thing word "bound :letter
end
to setcnt :letter :thing
make (word "cnt :letter) :thing
end
to cnt :letter
output thing (word "cnt :letter)
end
to setposn :letter :thing
make (word "posn :letter) :thing
end
to posn :letter
output thing (word "posn :letter)
end
to setcount. :word :thing
make (word "count. :word) :thing
end
to count. :word
output thing (word "count. :word)
end
to setlist. :word :thing
make (word "list. :word) :thing
end
to list. :word
output thing (word "list. :word)
end
to setmax. :word :thing
make (word "max. :word) :thing
end
to max. :word
output thing (word "max. :word)
end
;; Miscellaneous helpers
to index :letter
output (ascii :letter)-(ascii "A)
end
to beep
tone 440 15
end
to invtype :text
type standout :text
end
to nonneg :number
output ifelse :number < 0 [0] [:number]
end
;; Sample cryptograms
make "cgram1 [Dzynufqyjulli, jpqhq ok yr hoxpj qnzeujory qceqwj xhrtoyx
zw oyjr u trhjptpolq trhln. oynqqn, rzh qceqkkogq eryeqhy tojp
whrvlqfk rd qnzeujory uj whqkqyj kofwli fquyk jpuj jpq |xhrty-zwk| nr
yrj pugq kzep u trhln. u nqeqyj qnzeujory uofk uj, whqwuhqk drh, u
frhq trhjptpolq dzjzhq, tojp u noddqhqyj erffzyoji kwohoj, noddqhqyj
reezwujoryk, uyn frhq hqul zjoloji jpuy ujjuoyoyx kjujzk uyn kuluhi.]
make "cgram2 [Lvo vfkp lfzj md opaxflimn iz lm gitokflo fnp zlkonblvon f
hmalv'z inilifliuo, fnp fl lvo zfyo liyo lm zoo lm il lvfl vo jnmwz
wvfl iz noxozzfkh lm xmco wilv lvo mnbminb fxliuilioz fnp xaglako md
zmxiolh, zm lvfl viz inilifliuo xfn to kogoufnl. il iz ftzakp lm
lvinj lvfl lviz lfzj xfn to fxxmycgizvop th zm yaxv zillinb in f tms
dfxinb dkmnl, yfnicagflinb zhytmgz fl lvo pikoxlimn md pizlfnl
fpyinizlkflmkz. lviz iz kflvok f wfh lm kobiyonl fnp tkfinwfzv.]
make "cgram3 [Pcodl hbdcx qxdrdlh yihcodr, hbd rzbiier gxd lih ziyqdhdlh
hi hdgzb gwhbdlhcz echdxgzf, xdgnclp gr g ydglr ia ecudxghcil gln
zwehcoghcil. gln c niwuh hbgh yirh ia wr jbi rdxciwref xdgn gln jxchd
hbd dlpecrb eglpwgpd dodx edgxldn ch uf hbd xiwhd ia "xwl, rqih, xwl"
hi rcegr ygxldx.]
make "cgram4 [Jw btn xnsgsyp ejke gfebbcg, dtyjbn fbccsksg, ryu fbccsksg
nswcsfpsu pes usgjns, wnssuba, ryu wtptns bw pes qbtyk, pesns zbtcu
ls yb knrujyk, yb psgpjyk svfsxp rg r psrfejyk aspebu, ryu yb
lcrfilbrnu dtykcsg. jy wrfp, zs rns ksppjyk cbfigpsx gfesutcjyk ryu
knrujyk pb pes xbjyp bw pbnptns.]
|