-
Notifications
You must be signed in to change notification settings - Fork 0
/
chapter_12_sol.lisp
174 lines (147 loc) · 4.64 KB
/
chapter_12_sol.lisp
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
;;; 12.4 a write a defstruct for a structure called node, with four components
;;; name, question, yes-case, no-case
(defstruct node
(name "")
(question "")
(yes-case nil)
(no-case nil))
;;; 12.4 b define a global variable *node-list* that wil hold all the nodes
;;; write a function init that initialises the network by setting *node-list* to nil
(defvar *node-list* nil)
(defun init ()
(setf *node-list* nil))
;;; 12.4 c write add-node it should return the name of the node it added
(defun add-node (name question yes-case no-case)
(let ((n (make-node :name name
:question question
:yes-case yes-case
:no-case no-case)))
(push n *node-list*)
n))
(progn
(init)
(let ((exp (make-node
:name "test 1"
:question "test 2"
:yes-case 'a
:no-case 'b)))
(assert (equalp
(add-node (node-name exp)
(node-question exp)
(node-yes-case exp)
(node-no-case exp))
exp))
(assert (equalp *node-list*
(list exp)))))
;;; 12.4 d write find-node which takes a node name as input and returns the node if its appears in *node-list*
(defun find-node (n)
(first (member n *node-list* :key #'node-name :test #'equal)))
(progn
(setf *node-list* (list (make-node :name "Test 1")
(make-node :name "Test 2")))
(assert (find-node "Test 1"))
(assert (not (find-node "Test 3"))))
;;; 12.4 node data
(progn
(init)
(add-node 'start
"Does the engine turn over?"
'engine-turns-over
'engine-wont-turn-over)
(add-node 'engine-turns-over
"Will the engine rune for any period of time?"
'engine-will-run-briefly
'engine-wont-run)
(add-node 'engine-wont-run
"Is there gas in the tank?"
'gas-in-tank
"Fill the tank and try starting the engine again.")
(add-node 'engine-wont-turn-over
"Do you hear any sound when you turn the key?"
'sound-when-turn-key
'no-sound-when-turn-key)
(add-node 'no-sound-when-turn-key
"Is the battery voltage low?"
"Replace the battery"
'battery-voltage-ok)
(add-node 'battery-voltage-ok
"Are the battery cables dirty or loose?"
"Clean the cables and tighten the connections."
'battery-cables-good))
;;; 12.4 e write process-node, it takes a node name as input
;;; if no node, print message not defined yet and return nil
;;; else ask the question associated with node, and return the yes or no action depending on user response
(defun process-node (name &aux (n (find-node name)))
(cond
((null n)
(format t "~&~A not defined yet" name))
((y-or-n-p (node-question n))
(node-yes-case n))
(t
(node-no-case n))))
;;; 12.4 f write the function run, it maintains a local var current-node, whose initial-value is start
;;; it loops, calling process-node and storing the value back until string (print it) or nil is returned
(defun run ()
(do
((current-node (process-node 'start)
(process-node current-node)))
((or (null current-node)
(stringp current-node))
(when (stringp current-node)
(format t "~&~A" current-node)))))
;;; 12.4 g write an interactive function to add a new node
(defun valid-input (request validp)
(format t "~&~A" request)
(let ((input (read)))
(if (funcall validp input) input
(valid-input request validp))))
(defun user-new-node ()
(add-node
(valid-input "Node name?" #'symbolp)
(valid-input "Node question?" #'stringp)
(valid-input "Yes-case?" #'symbolp)
(valid-input "No-case?" #'symbolp)))
;;; 12.4 h write nodes that conform to description in book
(add-node 'engine-will-run-briefly
"Does engine stall when cold but not when warm?"
'cold-idle
nil)
(add-node 'cold-idle
"Is the cold idle speed at least 700 rpm?"
nil
"Adjust the idle speed")
;;; 12.5 create a defstruct for captain with fields name, age, ship
;;; make the enterprise point to your new captain through its captain component.
;; from book
(defun print-starship (x stream depth)
(format stream "#<STARSHIP ~A>"
(starship-name x)))
(defstruct (starship
(:print-function print-starship))
(captain nil)
(name nil)
(shields 'down)
(condition 'green)
(speed 0))
(defun print-captain (x stream depth)
(format stream "#<CAPTAIN \"~A\">"
(captain-name x)))
(defstruct (captain
(:print-function print-captain))
(name nil)
(age nil)
(ship nil))
(progn
(let* ((cap
(make-captain :name "James T. Kirk"
:age 35
:ship nil))
(ship
(make-starship :captain cap
:name "Enterprise")))
(setf (captain-ship cap) ship)
(assert (equalp (format nil "~S" ship)
"#<STARSHIP Enterprise>"))
(assert (equalp (format nil "~S" cap)
"#<CAPTAIN \"James T. Kirk\">"))
))