The Code So Far/Game 0

Sub-page of TheCodeSoFar

"Game," here means all the information needed to understand a position: the board, the stones, the player to play next, the Ko situation. It also has information about how the situation arose (i.e. the previous moves.) The Game class may be used for games in progress or completed games:

 (defclass Game ()
   ((Pos :documentation "The current position."
	:accessor Pos
  	:initarg Pos)
    (Current-Player :documentation "The player that will place the next stone or pass"
 		    :accessor Current-Player
 		    :initarg Current-Player)
    (Snake-Set :documentation "The connected strings on this board"
 	       :accessor Snake-Set
 	       :initarg Snake-Set)
    (Ko-Point :documentation "Where the current player may not play due to Ko.
                              Note we currently only deal with simple Ko."
 	      :accessor Ko-Point
	      :initarg Ko-Point)
    (Last-Move :accessor Last-Move :initarg Last-Move)
    (Previous :accessor Previous :initarg Previous)))

The Game class should ensure moves are valid (i.e. not suicide) and deal with the rules of GO (e.g. remove killed strings.) Something like this:

 (defmethod move ((g Game) (p Point))
   (if (and (empty? (Pos g) p)
	    (not (eq (Ko-Point g) p)))
       (make-instance 'Game
		      'Pos (add (Position g) (Current-Player g) p) ;; FIX - remove dead strings
		      'Current-Player (Other (Current-Player g))
		      'Ko-Point () ;; FIX - check for suicide too
		      'Previous g)))

It's clear I need to do some work with strings before I can finish the Game class.

Ok, so now that the strings are done...

Make a game in progress (the current position and who is to play next)...

 (defmethod Make-Game ((p Position) (s Stone))
   (make-instance 'Game
		  'Pos p
		  'Current-Player s
		  'Ko-Point ()
		  'Last-Move ()
		  'Previous ()
		  'Snake-Set (Make-Snake-Info p)))

Make a new game on an empty board with Black to play:

 (defun New-Game (sz)
   (Make-Game (new-position sz) *Black*))

A game is over after two passes:

 (defmethod done? (g Game)
   (and (eq (Last-Move g) *Pass*)
        (Previous g)
        (eq (Last-Move (Previous g)) *Pass* )))

Passing is easy:

 (defmethod move ((g Game) (p Pass))
   (make-instance 'Game
		  'Pos (copy (Position g))
		  'Current-Player (Other (Current-Player g))
		  'Ko-Point () 'Last-Move p
		  'Previous g
		  'Snake-Set (Snake-Set g)))

A helper method to find snakes that are affected by playing a stone on a board:

 (defmethod adjacent-snakes ((g Game) (p Point))
   (s-uniq (mapcan (lambda (p)
		     (let ((sn (at (SMap (Snake-Set g)) p)))
		       (if (not (eq sn *Empty*)) (list sn))))
		   (adjacent p))))

Everything is now in place to place a stone in a game:

 (defmethod move ((g Game) (p Point))
   (if (and (empty? (Pos g) p)
	    (not (eq (Ko-Point g) p)))
       (let* ((snakes (adjacent-snakes g p))
	      (kills (mapcan (lambda (sn)
			       (if (and (eq (Color sn) (Other (Current-Player g)))
				        (= 1 (length (liberties sn (Pos g)))))
				   (list sn)))
			     snakes))
	      (safe-friends (mapcan (lambda (sn)
				      (if (and (eq (Color sn) (Current-Player g))
					       (> (length (liberties sn (Pos g))) 1))
					  (list sn)))
				    snakes))
	      (p-liberties (liberties (Pos g) p)))
	 (if (or p-liberties kills safe-friends) ;; move is valid if we killed anything or is not suicide
	     (let* ((dead-stones (apply #'append (mapcar #'Points kills)))
		    (ko-point (if (and (null p-liberties)
				       (= 1 (length dead-stones)))
				  (car dead-stones)))
		   (new-pos (add (Pos g) (Current-Player g) p)))
	       (mapc (lambda (p) (setf (at new-pos p) *Empty*)) dead-stones)
	       (make-instance 'Game
			      'Pos new-pos
			      'Current-Player (Other (Current-Player g))
			      'Ko-Point ko-point
			      'Previous g
			      'Snake-Set (Make-Snake-Info new-pos)))
	  ))))

A utility function:

 (defmethod play ((g Game) l)
   (move g (Point (pos g) l)))

And, finally, print a game in progress:

 (defmethod printb ((g Game))
   (printb (Pos g))
   (format t "    ~B to play." (if (eq (Current-Player g) *Black*) "Black" "White" ))
   (if (Ko-Point g)
       (format t " (ko at ~S, ~S)" (r (Ko-Point g)) (c (Ko-Point g)))))

This is a copy of the living page "The Code So Far/Game 0" at Sensei's Library.
(OC) 2004 the Authors, published under the OpenContent License V1.0.
[Welcome to Sensei's Library!]
StartingPoints
ReferenceSection
About