-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathMCProblem.lsp
353 lines (300 loc) · 11.8 KB
/
MCProblem.lsp
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
;----------------------------------------
; Missionaries vs. Cannibals Problem
;----------------------------------------
; Struct for current state defining the state of the problem
(defstruct state
start_bank ;; Array(2) defining num m and c on start bank
end_bank ;; Array(2) defining num m and c on end bank
boat_pos ;; Position of boat
)
;; Struct for a single node in the tree
(defstruct node
move ;; Array(2) of the move sequence that resulted in the node
state ;; Struct of current state
id ;; ID num of node
parent_id ;; ID num of parent node
heuristic ;; Represents heuristic value
depth ;; Depth of the node
)
;; Array for new states
(setf state-vector (make-array 0 :fill-pointer 0 :adjustable t))
;; Hashtable for visited states
(setf visited (make-hash-table))
;; Array to store unique states
(setf unique-states(make-array 0 :fill-pointer 0 :adjustable t))
;; Total missionaries
(setf tot_m 15)
;; Total Cannibals
(setf tot_c 15)
;; Total boat size
(setf boat_size 6)
;; Counter for IDs
(setf counter 0)
;-------------------------------------------------------
; Name: init_node
; Params: initial number of missionaries, initial
; number of cannibals, number the boat
; can carry
; Desc: - initializes the first node and state
; - adds the new state to the unique states
; - adds the new node to the state-vector
;--------------------------------------------------------
(defun init_node(tot_m tot_c boat_size)
(setf start_bank (make-array '(2)))
(setf (aref start_bank 0) tot_m)
(setf (aref start_bank 1) tot_c)
(setf end_bank (make-array '(2)))
(setf (aref end_bank 0) 0)
(setf (aref end_bank 1) 0)
(setf state (make-state :start_bank start_bank :end_bank end_bank :boat_pos 0))
(setf start_node(make-node :state state :id (incf counter) :parent_id 0 :heuristic 30 :depth 1))
(vector-push-extend state unique-states)
(vector-push-extend start_node state-vector)
)
;----------------------------------------------------------
; Name: find_moves
; Params: current node to find moves for
; Desc: - Determines how many moves are feasible given
; the current state
; - For all plausible moves calls the transition
; function
;----------------------------------------------------------
(defun find_moves(curr_node)
(if (= 0 (state-boat_pos (node-state curr_node)))
(progn
(setf s_bank(state-start_bank(node-state curr_node)))
(setf total (+(aref s_bank 0)(aref s_bank 1)))
)
(progn
(setf e_bank(state-end_bank(node-state curr_node)))
(setf total (+(aref e_bank 0)(aref e_bank 1)))
)
)
(if (< total boat_size)
(setf x total)
(setf x boat_size)
)
(loop for j from 1 to x do
(loop for c from 0 to j do
(if (or(<= c (/ j 2))(= c j))
(transition curr_node (- j c) c)
)
)
)
)
;-------------------------------------------------------------
; Name: transition
; Params: current node, number of missionaries to be
; transported, number of cannibals to be
; transported
; Desc: - Calculates new values for start and end e_bank
; based off of m and c criteria and current node
; boat position
; - Calls isValid function to check validity of
; newly created node
; - Calls isUnique to check uniqueness of the newly
; created node
; - If the node is both unique and valid it calls
; create node
;--------------------------------------------------------------
(defun transition(curr_node m c)
(setf boat_pos(state-boat_pos (node-state curr_node)))
(setf curr_s_bank(state-start_bank(node-state curr_node)))
(setf curr_e_bank(state-end_bank(node-state curr_node)))
(setf new_start_bank (make-array '(2)))
(setf new_end_bank (make-array '(2)))
(if (= 0 boat_pos)
(progn
(setf (aref new_start_bank 0) (- (aref curr_s_bank 0) m))
(setf (aref new_start_bank 1) (- (aref curr_s_bank 1) c))
(setf (aref new_end_bank 0) (+ (aref curr_e_bank 0) m))
(setf (aref new_end_bank 1) (+ (aref curr_e_bank 1) c))
)
(progn
(setf (aref new_start_bank 0) (+ (aref curr_s_bank 0) m))
(setf (aref new_start_bank 1) (+ (aref curr_s_bank 1) c))
(setf (aref new_end_bank 0) (- (aref curr_e_bank 0) m))
(setf (aref new_end_bank 1) (- (aref curr_e_bank 1) c))
)
)
; Check validity of new node
(if (and (isValid new_start_bank new_end_bank)(isUnique new_start_bank new_end_bank boat_pos))
(create_node new_start_bank new_end_bank boat_pos (node-id curr_node) curr_node)
)
)
;-------------------------------------------------------
; Name: isValid
; Params: start bank array of new node and end bank array
; of new node
; Return: returns true if is valid
; Desc: - Checks that the number of missionaries is never
; outnumbered by the number of cannibals at either
; bank
;--------------------------------------------------------
(defun isValid(start_bank end_bank )
(setf start_m (aref start_bank 0))
(setf start_c (aref start_bank 1))
(setf end_m (aref end_bank 0))
(setf end_c (aref end_bank 1))
(if (and (or (= start_m 0)(<= start_c start_m))(or(= end_m 0)(<= end_c end_m)))
(if (and (and (<= 0 start_m)(<= 0 start_c))(and (<= 0 end_m)(<= 0 start_c)))
(return-from isValid 't)
)
)
)
;------------------------------------------------------------
; Name: isUnique
; Params: start bank array, end bank array and Position
; of boat to check uniqueness of
; Return: returns true if given params form a unique states
; returns nil if given params form a state that has
; previously been expanded
; Desc: - Loops through array of unique-states
; - Checks to find if the given params is a state
; that has already been expanded
; - If the params form a unique state, a new state is
; created and pushed to the unique-states vector
;------------------------------------------------------------
(defun isUnique(s_bank e_bank boat_pos)
(if (= 0 boat_pos)
(setf boat_pos 1)
(setf boat_pos 0)
)
;;If in unique states array don't expand
(setf l (length unique-states))
(loop for i from 0 to (- l 1) do
(setf curr_state (aref unique-states i))
(if (and (= (aref (state-start_bank curr_state) 0)(aref s_bank 0))
(= (aref (state-start_bank curr_state) 1)(aref s_bank 1))
(= (aref (state-end_bank curr_state) 0)(aref e_bank 0))
(= (aref (state-end_bank curr_state) 1)(aref e_bank 1))
(= (state-boat_pos curr_state) boat_pos)
)
(return-from isUnique nil)
)
)
(setf new_state (make-state :start_bank s_bank :end_bank e_bank :boat_pos boat_pos))
(vector-push-extend new_state unique-states)
(return-from isUnique 't)
)
;-------------------------------------------------------
; Name: create_node
; Params: start bank array, end bank array, boat position
; of new node to create, id of parent node, current
; node to be expanded from
; Desc: - Calculates heuristic for new node
; - Sets all values for a new node
; - Pushes the new node to the state-vector
;--------------------------------------------------------
(defun create_node(s_bank e_bank boat_pos id curr_node)
(if (= 0 boat_pos)
(setf boat_pos 1)
(setf boat_pos 0)
)
;(setf h (+ (aref s_bank 0)(aref s_bank 1)))
(setf h (+ (aref s_bank 0)(aref s_bank 1)))
(setf h (+ h boat_pos))
(setf h (* h (+ 1(node-depth curr_node))))
(setf new_state (make-state :start_bank s_bank :end_bank e_bank :boat_pos boat_pos))
(setf new_node(make-node :state new_state :id (incf counter) :parent_id id :heuristic h :depth (+ 1(node-depth curr_node))))
(vector-push-extend new_node state-vector)
)
;-------------------------------------------------------
; Name: sort_nodes
; Params: state-vector to sort
; Desc: - utilizes a simple selection sort to sort
; the nodes in the current state vector
;--------------------------------------------------------
(defun sort_nodes(state-vector)
(setf l (length state-vector))
(loop for i from 0 to (- l 1) do
(setf min i)
(loop for j from (+ i 1) to (- l 1) do
(setf curr_s (aref state-vector j))
(setf min_s (aref state-vector min))
(if (> (node-heuristic curr_s) (node-heuristic min_s))
(setf min j)
)
)
;;Swap
(setf tmp (aref state-vector i))
(setf (aref state-vector i) (aref state-vector min))
(setf (aref state-vector min) tmp)
)
)
;-------------------------------------------------------
; Name: isGoal
; Params: node to check if is at goal state
; Returns: returns true if node is at the goal state
; returns nil if node is not at the goal state
; Desc: - checks if the current node is at the goal
; state and returns
;--------------------------------------------------------
(defun isGoal(node)
(setf state (node-state node))
(if (and (= (aref (state-start_bank state) 0) 0)
(= (aref (state-start_bank state) 1) 0)
(= (aref (state-end_bank state) 0)tot_m)
(= (aref (state-end_bank state) 1)tot_c)
(= (state-boat_pos state) 1)
)
(return-from isGoal 't)
(return-from isGoal nil)
)
)
;-------------------------------------------------------
; Name: getSolution
; Params: the node that is at the goal state
; Desc: - creates a new array to store the solution
; - pushes the goal node to the solution vector
; - loops until the parent_id = 1 (the start state)
; - backtracks by using visited hashtable to get previous
; node based off of parent id
; - calls format solution once solution-vector is filled out
;--------------------------------------------------------
(defun getSolution(goal_node)
(setf solution-vector (make-array 0 :fill-pointer 0 :adjustable t))
(setf parent_id (node-parent_id goal_node))
(vector-push-extend goal_node solution-vector)
(loop while(not (= parent_id 1)) do
(setf next_node(gethash parent_id visited))
(setf parent_id (node-parent_id next_node))
(vector-push-extend next_node solution-vector)
)
;;TODO: add start state here
(formatSolution solution-vector)
)
;-------------------------------------------------------
; Name: formatSolution
; Params: array of nodes that outline the solution
; Desc: - loops through solution vector and formats
; the output
;--------------------------------------------------------
(defun formatSolution(solution-vector)
(setf l (length solution-vector))
(loop for i from (- l 1) downto 0 do
(setf something (aref solution-vector i))
(setf else (node-state something))
(format t "~% ~S ~S |~~~~~~~~~~~~~~| ~S ~S" (aref (state-start_bank else) 0)(aref (state-start_bank else) 1)(aref (state-end_bank else) 0)(aref (state-end_bank else) 1))
)
)
;; Main function that initializes and calls the solver
;-------------------------------------------------------
; Name: main
; Params:
; Desc: -
;--------------------------------------------------------
(defun main()
(format t "~%Missionaries vs. Cannibals~%")
(init_node tot_m tot_c boat_size)
(setf curr_node (vector-pop state-vector))
(loop while(not(isGoal curr_node)) do
(find_moves curr_node)
(setf (gethash (node-id curr_node) visited)curr_node)
(if (< 0 (length state-vector))
(sort_nodes state-vector)
)
(setf curr_node (vector-pop state-vector))
)
(getSolution curr_node)
)