-
Notifications
You must be signed in to change notification settings - Fork 0
/
guess.nw
245 lines (175 loc) · 5.26 KB
/
guess.nw
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
% -*- mode: noweb; ess-noweb-default-code-mode: lisp-mode; -*-
\documentclass{tufte-handout}
\input{preamble.tex}
\hypersetup{
pdffitwindow=true,
pdfstartview={FitH},
pdftitle={The Guess-My-Number Game},
pdfauthor={Eric Bailey <eric@ericb.me>},
pdfsubject={Land of Lisp: Chapter 2},
pdfkeywords={Lisp, game, simple, literate programming, noweb},
colorlinks=true,
linkcolor=ErlangRed,
urlcolor=ErlangRed
}
\title{%
The Guess-My-Number Game%
\thanks{\cite{barski2010land-ch2}}
}
\date{%
January 14, 2017
\thanks{Last updated \today}
}
\begin{document}
\maketitle
@
\begin{abstract}
In this game, you pick a number from $1$ to $100$, and the computer has to
guess it.
\end{abstract}
\begin{marginfigure}
\srclink{src/guess.lisp}:
<<*>>=
(in-package :cl-user)
(defpackage lol.guess
(:use :cl :prove)
(:export :bigger
:smaller
:start-over))
(in-package :lol.guess)
<<reset the global state>>
@ %def lol.guess
\end{marginfigure}
% \tableofcontents
% \newpage
\section{Defining the Small and Big Variables}
To give the computer a range of numbers in which to guess, we define the lower
and upper limits, [[*small*]] and [[*big*]], respectively. We'll need to
[[<<reset the global state>>]] as such whenever we want to restart the game,
\marginnote{%
\say{Global variable names should start and end with asterisks (also known in
this context as earmuffs)} \citep{google-style-guide}.%
}
<<reset the global state>>=
(defparameter *small* 1)
(defparameter *big* 100)
@
\section{Defining the Guess-My-Number Function}
With [[*small*]] and [[*big*]] defined, we can tell the computer how to guess a
number ([[guess-my-number]]) within those limits.
\begin{marginfigure}%
\caption{The guessing algorithm}
\begin{minted}{c}
sum <- small + big
right shift sum by 1
return sum
\end{minted}
\label{fig:guessing-algorithm}
\end{marginfigure}
The basic algorithm is to
[[<<halve the sum of the limits and shorten the result>>]].
To achieve that, we use Common Lisp's
\href{http://www.lispworks.com/documentation/HyperSpec/Body/f_ash.htm}{\lsp{ash}}
function to perform an {\sl arithmetic right shift} by $1$, i.e.
$\floor{\cee{sum} \times 2^{-1}}$.
To define the [[guess-my-number]] function, we simply implement the algorithm
described in pseudocode in \Fref{fig:guessing-algorithm}.
<<halve the sum of the limits and shorten the result>>=
(ash (+ *small* *big*) -1)
@
\begin{marginfigure}
Now, when we want to [[<<have the computer guess a number>>]], we simply call
[[guess-my-number]] as follows.
<<have the computer guess a number>>=
(guess-my-number)
@
\end{marginfigure}
<<*>>=
(defun guess-my-number ()
<<halve the sum of the limits and shorten the result>>)
@
\section{Defining the Smaller and Bigger Functions}
\marginnote{%
To appropriately adjust [[*big*]],
[[<<subtract one from the most recent guess>>]].%
}
\begin{marginfigure}
<<subtract one from the most recent guess>>=
(1- <<have the computer guess a number>>)
@
\end{marginfigure}
To define the [[smaller]] function, we need to update the global state
such that the next guess is {\em smaller} than the last, i.e.
[[<<set [[*big*]] to one less than the last guess>>]] then
[[<<have the computer guess a number>>]].
<<set [[*big*]] to one less than the last guess>>=
(setf *big* <<subtract one from the most recent guess>>)
@
<<*>>=
(defun smaller ()
<<set [[*big*]] to one less than the last guess>>
<<have the computer guess a number>>)
@
\marginnote{%
To appropriately adjust [[*small*]],
[[<<add one to the most recent guess>>]].%
}
\begin{marginfigure}
<<add one to the most recent guess>>=
(1+ <<have the computer guess a number>>)
@
\end{marginfigure}
To define the [[bigger]] function, we need to update the global state
such that the next guess is {\em bigger} than the last, i.e.
[[<<set [[*small*]] to one greater than the last guess>>]] then
[[<<have the computer guess a number>>]].
<<set [[*small*]] to one greater than the last guess>>=
(setq *small* <<add one to the most recent guess>>)
@
<<*>>=
(defun bigger ()
<<set [[*small*]] to one greater than the last guess>>
<<have the computer guess a number>>)
@
\section{Defining the Start-Over Function}
At this point, to define the [[start-over]] function is trivial. We simply
[[<<reset the global state>>]] then [[<<have the computer guess a number>>]].
<<*>>=
(defun start-over ()
<<reset the global state>>
<<have the computer guess a number>>)
@
\newpage
\setlength{\linewidth}{1.5\textwidth}
\begin{multicols}{2}
\section{Full Listing}
\inputminted[linenos]{lisp}{guess.lisp}
\columnbreak
\section{Tests}
<<test/guess.lisp>>=
(in-package :lol.guess)
(plan 1)
(subtest "A Plausible Session"
(is (start-over) 50 "(start-over) ; => 50")
(is (smaller) 25 "(smaller) ; => 25")
(is (bigger) 37 "(bigger) ; => 37")
(is (bigger) 43 "(bigger) ; => 43")
(is (smaller) 40 "(smaller) ; => 40")
(is (bigger) 41 "(bigger) ; => 41")
(is (bigger) 42 "(bigger) ; => 42"))
(finalize)
@
\end{multicols}
\newpage
\setlength{\linewidth}{1.8\textwidth}
\begin{multicols}{2}
\section{Chunks}
\nowebchunks
% \columnbreak
\section{Index}
\nowebindex
\end{multicols}
\setlength{\linewidth}{1.4\textwidth}
\bibliography{lol}
\bibliographystyle{plainnat}
\end{document}