/
wall-follower.lisp
198 lines (166 loc) · 7.27 KB
/
wall-follower.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
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
;; Wall-follower robot as an extension to the gp framework.
;; Pranav Ravichandran <me@onloop.net>
(defun make-grid-world (dimensions)
"Make a matrix with specific dimensions."
(make-array dimensions :initial-element 0))
(defun current-cell (x y)
"Make a cons cell to denote the current coordinates
of the wall-following robot on the grid world."
(cons x y))
(defun n (grid-world current-cell)
"Move the robot north by one cell in the grid world."
(let ((new-x (- (car current-cell) 1)))
(list grid-world
(if (>= new-x 0)
(cons new-x (cdr current-cell))
current-cell))))
(defun s (grid-world current-cell)
"Move the robot south by one cell in the grid world."
(let ((new-x (+ (car current-cell) 1)))
(list grid-world
(if (<= new-x (- (car (array-dimensions grid-world)) 1))
(cons new-x (cdr current-cell))
current-cell))))
(defun e (grid-world current-cell)
"Move the robot east by one cell in the grid world."
(let ((new-y (+ (cdr current-cell) 1)))
(list grid-world
(if (<= new-y (- (cadr (array-dimensions grid-world)) 1))
(cons (car current-cell) new-y)
current-cell))))
(defun w (grid-world current-cell)
"Move the robot west by one cell in the grid world."
(let ((new-y (- (cdr current-cell) 1)))
(list grid-world
(if (>= new-y 0)
(cons (car current-cell) new-y)
current-cell))))
(defun ne (grid-world current-cell)
"Move the robot north east by one cell in the grid world."
(let ((new-x (- (car current-cell) 1))
(new-y (+ (cdr current-cell) 1)))
(list grid-world
(if (and (>= new-x 0)
(<= new-y (- (cadr (array-dimensions grid-world)) 1)))
(cons new-x new-y)
current-cell))))
(defun nw (grid-world current-cell)
"Move the robot north west by one cell in the grid world."
(let ((new-x (- (car current-cell) 1))
(new-y (- (cdr current-cell) 1)))
(list grid-world
(if (and (>= new-x 0) (>= new-y 0))
(cons new-x new-y)
current-cell))))
(defun se (grid-world current-cell)
"Move the robot south east by one cell in the grid world."
(let ((new-x (+ (car current-cell) 1))
(new-y (+ (cdr current-cell) 1)))
(list grid-world
(if (and (<= new-x (- (car (array-dimensions grid-world)) 1))
(<= new-y (- (cadr (array-dimensions grid-world)) 1)))
(cons new-x new-y)
current-cell))))
(defun sw (grid-world current-cell)
"Move the robot south west by one cell in the grid world."
(let ((new-x (+ (car current-cell) 1))
(new-y (- (cdr current-cell) 1)))
(list grid-world
(if (and (<= new-x (- (car (array-dimensions grid-world)) 1))
(>= new-y 0))
(cons new-x new-y)
current-cell))))
(defun n-sensor (grid-world current-cell)
"Check if there's a wall north of the robot."
(= (car current-cell) 0))
(defun s-sensor (grid-world current-cell)
"Check if there's a wall south of the robot."
(= (car current-cell) (- (car (array-dimensions grid-world)) 1)))
(defun e-sensor (grid-world current-cell)
"Check if there's a wall east of the robot."
(= (cdr current-cell) (- (cadr (array-dimensions grid-world)) 1)))
(defun w-sensor (grid-world current-cell)
"Check if there's a wall west of the robot."
(= (cdr current-cell) 0))
(defun ne-sensor (grid-world current-cell)
"Check if there's a wall north east of the robot."
(and (n-sensor grid-world current-cell) (e-sensor grid-world current-cell)))
(defun nw-sensor (grid-world current-cell)
"Check if there's a wall north west of the robot."
(and (n-sensor grid-world current-cell) (w-sensor grid-world current-cell)))
(defun se-sensor (grid-world current-cell)
"Check if there's a wall south east of the robot."
(and (s-sensor grid-world current-cell) (e-sensor grid-world current-cell)))
(defun sw-sensor (grid-world current-cell)
"Check if there's a wall south west of the robot."
(and (s-sensor grid-world current-cell) (w-sensor grid-world current-cell)))
;; For the 5x5 grid world.
(setf dims '(5 5))
;; The 5x5 grid world.
(setf grid-world (make-grid-world dims))
;; List of starting positions.
(setf current-cell (list (current-cell 2 2)
(current-cell 0 0)
(current-cell 4 4)
(current-cell 0 4)
(current-cell 4 0)
(current-cell 1 1)
(current-cell 3 3)
(current-cell 1 3)
(current-cell 3 1)
(current-cell 0 3)))
;; Assoc list of primitives and their arity.
(setf primitives '((if 3) (and 2) (or 2) (not 1)))
;; Args for the lambda function that generates the program.
(setf args '(grid-world current-cell))
;; Value of args for the generated program.
(setf fargs (mapcar #'(lambda (x) (list grid-world x)) current-cell))
;; Set of actions.
(setf actions '((n grid-world current-cell)
(w grid-world current-cell)
(e grid-world current-cell)
(s grid-world current-cell)))
; (ne grid-world current-cell)
; (nw grid-world current-cell)
; (se grid-world current-cell)
; (sw grid-world current-cell)))
;; Set of conditionals/sensor programs.
(setf conditionals '((n-sensor grid-world current-cell)
(w-sensor grid-world current-cell)
(e-sensor grid-world current-cell)
(s-sensor grid-world current-cell)
(ne-sensor grid-world current-cell)
(nw-sensor grid-world current-cell)
(se-sensor grid-world current-cell)
(sw-sensor grid-world current-cell)))
(defun wall-cell-p (grid-world cell)
"Check if a cell in the grid world is a wall cell."
(let ((dimensions (array-dimensions grid-world)))
(or (= (car cell) 0)
(= (cdr cell) 0)
(= (car cell) (- (car dimensions) 1))
(= (cdr cell) (- (cadr dimensions) 1)))))
(defun new-cell-p (hashset cell)
"Check if in a single evaluation the cell has not already been visited."
(not (gethash (write-to-string cell) hashset)))
(defun fitness-p (fitness)
"Fitness predicate function that checks if a fitness has 'succeeded'."
(let* ((dimensions dims)
(wall-cells (+ (* 2 (car dimensions)) (* 2 (- (cadr dimensions) 2)))))
(>= fitness (* wall-cells (length current-cell)))))
(defun fitness-helper (results)
"Fitness function helper that takes results and checks them for the fitness."
(if (typep results 'list)
(let ((hashset (make-hash-table :test 'equal)))
(loop for result in results
while (new-cell-p hashset (cadr result))
do (setf (gethash (write-to-string (cadr result)) hashset) t)
counting #'(lambda (result)
(if (and (new-cell-p (car result) (cadr result))
(wall-cell-p (car result) (cadr result)))))
into fitness
finally (return fitness)))
0))
(defun fitness-function (results)
"Fitness function that maps the fitness helper across the results list."
(apply #'+ (mapcar #'fitness-helper results)))