This is the first day I've wished I were working in J, like last year, instead of Lisp. Common Lisp arrays show the age of the language design. They're basically C arrays with less convenient syntax; if you want higher-order array iteration you have to write it yourself or use a package that provides it. This solution is also less efficient than it could be for part 2, because I recompute the full neighbors array on each iteration rather than updating it incrementally.
(defun read-inputs (filename)
(let* ((input-lines (uiop:read-file-lines filename))
(rows (length input-lines))
(cols (length (car input-lines)))
(result (make-array (list rows cols) :initial-element 0)))
(loop for line in input-lines
for y from 0 to (1- rows)
do (loop for x from 0 to (1- cols)
if (eql (char line x) #\@)
do (setf (aref result y x) 1)))
result))
(defun neighbors (grid)
(let* ((dimensions (array-dimensions grid))
(rows (car dimensions))
(cols (cadr dimensions))
(result (make-array dimensions :initial-element 0)))
(flet ((neighbors-at (y x)
(loop for dy from -1 to 1
sum (loop for dx from -1 to 1
sum (let ((yy (+ y dy))
(xx (+ x dx)))
(if (and (>= yy 0)
(< yy rows)
(>= xx 0)
(< xx cols)
(not (and (= dx 0) (= dy 0)))
(> (aref grid yy xx) 0))
1
0))))))
(loop for y from 0 to (1- rows)
do (loop for x from 0 to (1- cols)
do (setf (aref result y x) (neighbors-at y x))))
result)))
(defun main-1 (filename)
(let* ((grid (read-inputs filename))
(dimensions (array-dimensions grid))
(neighbors-grid (neighbors grid)))
(loop for y from 0 to (1- (car dimensions))
sum (loop for x from 0 to (1- (cadr dimensions))
sum (if (and (> (aref grid y x) 0)
(< (aref neighbors-grid y x) 4))
1
0)))))
(defun remove-accessible (grid)
(let* ((dimensions (array-dimensions grid))
(neighbors-grid (neighbors grid))
(removed 0))
(loop for y from 0 to (1- (car dimensions))
do (loop for x from 0 to (1- (cadr dimensions))
do (if (and (> (aref grid y x) 0)
(< (aref neighbors-grid y x) 4))
(progn
(setf (aref grid y x) 0)
(incf removed)))))
removed))
(defun main-2 (filename)
(let ((grid (read-inputs filename))
(removed 0))
(loop for this-removed = (remove-accessible grid)
until (zerop this-removed)
do (incf removed this-removed))
removed))