[Welcome to Sensei's Library!]

StartingPoints
ReferenceSection
About


Referenced by
TheCodeSoFar

 

The Code So Far - 2
   

I decide to write a simple move chooser. The initial algorithm is extremely naive: for each connected string of stones, assign an urgency based on the number of liberties that it has. For all empty spaces, add up the urgencies of all adjacent strings. Pick the space with the highest score. Note that it has no concept of kill versus save or even who the current player is.

  (defun urgency (liberties-length)
    (case liberties-length
   ((1) 50)
   ((2) 10)
   ((3)  3)
   (otherwise 1)))
  (defmethod get-candidate-moves-0 ((analyzer analyzer))
    (let ((worm-info (worm-info (game analyzer)))
     (game-board (game-board (game analyzer))))
      (let ((candidates (mapcan (lambda (worm)
      (let ((liberties (liberties worm game-board)))
        (mapcar (lambda (point)
           (cons point (urgency (length liberties))))
         liberties)))
           (snakes worm-info))))
        (collapse candidates #'+))))

[Diagram]
Diag.: A success, and the first failure (GGPFB 1-23)

The right hand side move a is good if white plays, unfortunately, the problem is for black to play and kill. Problem 1-23 is the first problem in the book for which the correct move is different depending on who is to play.



I add the victory condition code back in - the program now knows it has solved the first 14 problems, 15 is "to save" and it has no criterion by which to judge success. For now, I'll just add the "more than 3 liberties is safe" rule. Maybe I should implement a series of analyzers, varying from fast and simple to slow and careful? Unresolved boards could start with simple analyzers and retry with the more complex ones as game time permits?


I've recently been working on an IGS client for Common Lisp, it's far enough along to play games, but lacks a front-end. It might make a good option for integration with some sort of AI. Currently it only plays mirror Go, since I spent all of 5 minutes on the AI :-). You should stop by #lisp on irc.openprojects.net, if you haven't already, there are several of us Go-inclined CL programmers. I'm 'emu'. I'll probably put it up on CLiki at one point or another, too. -- mrd?

Gorobei: I will, as soon as I get around to setting up an IRC client on my Linux box :)


Life and Death is proving to be really hard. While mulling over ideas, I write a little Bouzy 5-21 implementation:

Her's the output for Lucky's Problem:

[Diagram]
Diag.: Bouzy 5-21 for Lucky's Problem

This is all very pretty, but reminds me a lot of image processing code: simple stuff looks good, but hard problems (e.g. finding camouflaged tanks) are beyond its scope. E.g. Bouzy's algorithm requires we remove all dead groups, but if we could do this, we probably won't need Bouzy's algorithm in our game code :)

Worse, the algorithm is basically untunable: you can change the dialation and erosion counts, add 'fake' stones, remove dead stones, etc, but at its core it is still a relatively inflexible function.



Computer analysis of life and death has been an open problem for several decades. So it *should* be hard.:-) -- WilliamNewman


I rewrite a bunch of the code: symbols are very cool (e.g. having a class represent a Stone seemed a good idea, now I see a symbol is a much better fit.)

I decide to write a simple routine: (read-sgf-game filename). It's only 50 lines of code, but I spend many hours trying to get it right. I can parse simple games just fine, but some sgf files just don't fit into my Game class (a tree of positions with child positions generated by moves from the parent node.) I can deal with marked stones, variations, comments, etc, but stuff like variations without moves are just unrepresentable! There's almost a programming rule here: if you can't something to work, you're trying to implement an impossibility.

So how to fix things?

  • keep Game and Sgf-Node separate. Game represents valid games, and Sgf-Node any valid sgf. Easy, but not much of a solution.
  • only let Game load valid games (i.e. linear strings of moves in a tree structure.) Not very useful because many interesting files are annotated heavily.
  • loosen up the Game class so it can also represent non-games (e.g. games with arbitrary stones added during variations, etc.) This seems to be the right thing...
 (defclass Game ()
   ((Game-Board
      :documentation "The current Game-Board."
      :accessor Game-Board :initarg :Game-Board)
    (Current-Player
      :documentation "The player that will place the next stone or pass"
      :accessor Current-Player :initarg :Current-Player)
    (Properties
      :documentation "Random sgf-like info - may include marks, comments, unknown meta-information."
      :accessor Properties :initarg :Properties :initform ())
    (Variations
      :documentation "sgf-like variations - all variations, main line is (car variations)"
      :accessor Variations :initarg :Variations :initform ())
    (Worm-Info
      :documentation "The connected strings on this board - this should be computed only on demand."
      :accessor Worm-Info :initarg :Worm-Info)
    (Last-Move
      :documentation "How we got to this board - may be () if was created by annotation rather than play."
      :accessor Last-Move :initarg :Last-Move)
    (Previous
      :documentation "previous board, or () if this is the start of the game."
      :accessor Previous :initarg :Previous)))

So, I thought I'd take a look at your code but I'm not quite sure what's the latest code. The link at TheCodeSoFar seems to be a bit outdated and GorobeiTheCurrentCode hasn't been edited since May. Is it possbile to create a tarball or something else of your latest code? (OT: As I'm new to CL, where did you find the information about CLOS?) -- UrbanHafner

Gorobei: I've thrown an up-to-date tarball online. The above links should now point to it. For CLOS, I just googled for a few tutorials, then bought "The Art of the Meta-object Protocol." Obviously a good book, my officemates keep stealing it.

Thanks. -- UrbanHafner


Gorobei: A month wasted. Looking at my code, it's a complete disaster: the reason it was so hard to add sgf and keep my simple reg-tests running was that many classes/slots were ill-defined. I delete a bunch of crufty code, rationalize some stuff (e.g. the focus of goals is now always lists of points,) and accept the fact that my game class needs to be able to read SGF files (e.g. a game may contain a bunch of extra stones in a variation placed to illustrate a point.) It's still a mess, but at least the patient is stabilized.

I'm almost embarassed that I'm using one the coolest programming systems in the world (CL's macros and CLOS's tunability are awesome,) and yet I haven't even used any of the powerful features.

I'll try to solve some ladder problems next - these should point up a bunch of flaws in my thinking...

My initial code implements "if the defender gets three liberties than he is safe." After a mere week of pulling my hair out, the code can solve some simple problems:

On a good note, I feed the ladder code my initial reg-tests. The infamous 1-22 problem is finally resolved:

[Diagram]
Diag.: White to play. This line (SAVEG) loses

GGPFB-1-23 is also solved. So are the "micro-ladder" problems, 1-24 through 1-28.



This is a copy of the living page "The Code So Far - 2" at Sensei's Library.
(C) the Authors, published under the OpenContent License V1.0.