A snake is a bunch of connected stones of the same color. I can't use the word "string" so I'll go with "snake." I should read the GNU Go doc to rationalize my class names:
(defclass Snake () ((Color :accessor Color :initarg Color) (Points :accessor Points :initarg Points)))
Next, snakes get a print character because I want to have boards of snakes...
(defmethod PChar ((sn Snake)) (if (eq (Color sn) *White*) #\o #\b))
And a sort order, so I can sort lists of snakes:
(defmethod lessp ((sn1 Snake) (sn2 Snake)) (lessp (car (Points sn1)) (car (Points sn2))))
A helper method to remove a snake from a board, replace the stones with the snake itself, and return the list of points making up the snake:
(defmethod take-string ((b Position) (p Point) (s Stone) (sn Snake)) (setf (at b p) sn) (cons p (mapcan (lambda (pa) (if (eq (at b pa) s) (take-string b pa s sn))) (adjacent p))))
To make a snake:
(defmethod Make-Snake ((b Position) (p Point) (s Stone)) (let* ((sn (make-instance 'Snake 'Color s)) (ps (take-string b p s sn))) (setf (Points sn) (s-uniq ps)) sn))
Given a snake, and a position, return the liberties that the snake has:
(defmethod liberties ((s Snake) (b Position)) (s-uniq (mapcan (lambda (p) (if (empty? b p) (list p))) (apply #'append (mapcar #'adjacent (Points s))))))
Now we define a class that represents all the snakes on a board. Snakes is a list of the snakes, SMap is a board that maps a point on the board to a specific snake:
(defclass Snake-Info () ((Snakes :accessor Snakes :initarg Snakes) (SMap :accessor SMap :initarg SMap)))
Making a Snake-Info is now easy:
(defmethod Make-Snake-Info ((b Position)) (let* ((sb (copy b)) (snakes (mapcan (lambda (p) (if (stone? sb p) (list (Make-Snake sb p (at sb p))))) (all-points b)))) (make-instance 'Snake-Info 'Snakes snakes 'SMap sb)))