There are many ways to track the liberties of a chain
And there are many different implementations of each:

* none
* count pseudo liberties
   * simple count
   * do count, sum, and sum squared, which can detect atari
* array of liberties
   * store all liberties
   * store first k liberties
* linked list of liberties
   * doubly linked list, fixed locations for liberties (needs many nodes)
   * doubly linked list, also store liberty (needs only 1600 nodes)

After fairly extensive performance testing on an Intel Core chip,
I find that most reasonable techniques perform within a factor
of 1.5 or 2.0 of the best, so as a practical matter, it doesn't
really matter that much. Yet, 2 performance results stand out:

* for doing pure MC, use simple pseudo liberties
* for doing board analysis (like reading ladders), use arrays of liberties.

I am in the middle of porting this to the i7 core architecture. because
of the larger, faster L2 cache doubly linked lists may work well.

I have a code generator that makes it (somewhat) easy to try this out:
    http://pages.swcp.com/~wing/cgbg/

Of course, writing out the different implementations yourself is a good
exercise to help understand what happens.

Michael Wing

> Thanks both. I guess reading over my message it was a bit ambiguous since I 
> could have meant 
either liberty counts i.e.. |liberty| or the actual contents of the liberty 
set. I actually meant the latter.
> 
> When it comes to liberty counts- the only system I know of (which I read 
> about here) was to not 
have precise liberty counts but rather have a situation which you guarantee 
that the liberties reach 0 
at the same time a liberty count would. I think the term used here was 
pseudo-liberties. This makes 
merging easy but I am curious how are merges handled if you have precise 
liberty counts. 
> 
> I assume that one would have to walk the stones in a given chain after you 
> perform the addition 
and subtract one for each duplicate.
> 
> --- On Fri, 8/14/09, Don Dailey <[email protected]> wrote:
> 
> > From: Don Dailey <[email protected]>
> > Subject: Re: [computer-go] representing liberties
> > To: "computer-go" <[email protected]>
> > Date: Friday, August 14, 2009, 6:16 PM
> > I'm not sure I understand your
> > question.   But I'll try to explain it a little
> > better.
> > 
> > Basically, you keep a C structure or the equivalent which
> > tracks each individual chain.   On your board array you
> > put the index of that structure (or a pointer to it.)  
> > 
> > 
> > The structure will look something like this:
> > 
> >   typedef struct 
> >   {
> >        int color;
> >        int stone_count;
> >        int head_stone;
> >        int liberty_count;
> > 
> >   }  chain_t; 
> > 
> > And perhaps other crap you may want to keep.
> > 
> > 
> > So lets say you have an array of these, one for each chain
> > on the board with room to grow.
> > 
> > When you place a stone on the board,  you look at the 4
> > neighbors to see if this is going to be a new chain of 1, or
> > connect to an existing chain.    If it's an existing
> > chain, you will need to create a brand new entry,  set the
> > stone_count to 1, the liberty count to 1, 2, 3 or 4  (by
> > looking at the 4 surrounding points)  and set the
> > head_stone to the location of the new stone.    the
> > head_stone can be ANY stone in the group - it's just a
> > way to quickly reference one of the stones in the group.  
> > 
> > 
> > Your board of course will have the index of the
> > chain_t.    I start at 1 and make zero mean empty but you
> > could use -1 to represent empty squares if you want to.  
> > So if the value of the board array is 5,  it means it is
> > the 5th chain in the chain_t array and you can immediately
> > see how many stones are there,  how many liberties etc.
> > 
> > 
> > The logic for updating the liberty count is pretty basic. 
> > When you place a stone next to an existing group,  you know
> > that group loses 1 liberty, so you subtract 1 from ANY group
> > of either color that touches it (there can only be 4 at
> > most.)     But then you must check to see if the stone
> > you just placed created liberties for the group it belongs
> > to.    So you count the empty points around the new stone
> > that do not already belong to that same group.    
> > (There is also the case where 2 chains must be merged,  but
> > we will ignore that for now.) 
> > 
> > 
> > When a group is captured,  you must do a bit more
> > housekeeping.   You need to delete it's entry somewhow
> > in the chain array and you will have to recalculate the
> > liberties for any enemy chain that is currently touching any
> > of the captured stones.    This is not as hard as it seems
> > once you work it out.  
> > 
> > 
> > One way to delete the entry is to just set the stone_count
> > to zero for instance.   You may want to
> > "compress" the chain list from time to time but if
> > you make the list big enough,  you will be able to complete
> > one or more playouts without needing to do this.   You
> > could also keep a "free list" so that you
> > immediately re-use entries - that's probably what I
> > would recommend because it's real simple and the free
> > list will never grow very large.    
> > 
> > 
> > How do you unmake moves?   I suggest that you
> > don't.   Instead, making a move should either be by
> > state copy,  or if you know you will never need to unmake a
> > move (such as when doing fast playouts)  you don't have
> > to worry about it.    But of course you will still want
> > to keep some original copy to track the state of the actual
> > game.
> > 
> > 
> > So your should wrap your whole game state up into a neat
> > little package and operate only on those.   You will be
> > thankful if you ever decide to go with parallel processing
> > for instance.   
> > 
> > So to make a move you might have something like this in C,
> > this is non-object oriented version:
> > 
> > 
> >    int make( const position *original_state,  position
> > *new_state,  move_type  mv )
> >    {
> >        *new_state = *original_state;
> > 
> >        status = low_level_make( new_state,  mv );
> >        return status;
> > 
> >    }
> > 
> > The  "position" object is a C structure that has
> > the entire board, chain lists and move history.   The move
> > history can be implemented as a pointer to previous move
> > states.  
> > 
> > So in any kind of recursive search situation, you are
> > simply passing position states down the tree, never having
> > to unmake a move.    In the playouts you don't even
> > have to copy state.   
> > 
> > 
> > With this data structure you can also easily iterate
> > through the chains without having to loop over every point
> > on the board.    In fact you can always know exactly how
> > many chains are on the board of either color and do
> > something wth them if needed.   Or you can quickly count
> > the number of stones on the board (of course if you wanted
> > to you could keep this in a separate counter in the position
> > state.)  
> > 
> > 
> > When you make captures you will need to hit every stone. 
> > I use a recursive flood fill type of routine to do this.  
> > I know that some programs keep linked lists of stones -
> > I'm not sure if that is worth the trouble and extra
> > space.  Mabye it is.     I think I figured out that you
> > rarely have to go through every stone,  mainly in
> > captures.  
> > 
> > 
> > 
> > Ok, now my disclaimer.   There are some very experienced
> > go programmer here and they may find this naive or
> > silly.    My reference bots do not use this, they just do
> > the dumb thing - a single flat array the represents the
> > board and the stones on it. 
> > 
> > 
> > 
> > - Don
> > 
> > 
> > 
> > 
> > 
> > 
> > 
> > 
> > 
> > 
> > 
> > 
> > 
> > 
> > 
> > On Fri, Aug 14, 2009 at 6:10 PM,
> > Carter Cheng <[email protected]>
> > wrote:
> > 
> > So to determine where the last two
> > liberties for a group of stones for example is the obvious
> > method of just doing it to have some method of liberty
> > counting + a exhaustive search to determine the last two
> > liberties for example?
> > 
> > 
> > 
> > 
> > --- On Fri, 8/14/09, Don Dailey <[email protected]>
> > wrote:
> > 
> > 
> > 
> > > From: Don Dailey <[email protected]>
> > 
> > > Subject: Re: [computer-go] representing liberties
> > 
> > > To: "computer-go" <[email protected]>
> > 
> > > Date: Friday, August 14, 2009, 2:33 PM
> > 
> > >
> > 
> > >
> > 
> > > On Fri, Aug 14, 2009 at 5:13 PM,
> > 
> > > Carter Cheng <[email protected]>
> > 
> > > wrote:
> > 
> > >
> > 
> > > I have been having difficulties selecting a good
> > 
> > > representation for liberty sets for strings of stones.
> > I am
> > 
> > > curious how other people might be doing this. I
> > suspect that
> > 
> > > for heavier playouts one would like to know not only
> > the
> > 
> > > count of the liberties but also where precisely they
> > might
> > 
> > > be relatively quickly(to determine if the group is in
> > atari
> > 
> > > among other things).
> > 
> > >
> > 
> > > Simple is best, until you know EXACTLY what you will
> > want
> > 
> > > to do and how often you will need to do it.
> > 
> > >
> > 
> > > Something pretty simple that I have used in the past
> > is to
> > 
> > > track each chain and incrementally maintain the
> > liberty
> > 
> > > count. 
> > 
> > >
> > 
> > >
> > 
> > > When you plop a stone down,  you have to look at only
> > 4
> > 
> > > points to see which group if any it belongs to, or if
> > it
> > 
> > > connects 2 or more groups.    And you can update
> > the
> > 
> > > liberty counts of all affected groups very quickly.
> > 
> > >
> > 
> > >
> > 
> > > Where there is a capture, you must do considerably
> > more
> > 
> > > work - but captures represent only a small fraction of
> > the
> > 
> > > moves.   Small captures are more common than large
> > 
> > > captures, but they require little work.    
> > 
> > >
> > 
> > >
> > 
> > > - Don
> > 
> > >
> > 
> > >
> > 
> > >
> > 
> > >
> > 
> > >  
> > 
> > >
> > 
> > >
> > 
> > >
> > 
> > >
> > 
> > >
> > 
> > >
> > 
> > >
> > 
> > > _______________________________________________
> > 
> > >
> > 
> > > computer-go mailing list
> > 
> > >
> > 
> > > [email protected]
> > 
> > >
> > 
> > > http://www.computer-go.org/mailman/listinfo/computer-go/
> > 
> > >
> > 
> > >
> > 
> > >
> > 
> > >
> > 
> > > -----Inline Attachment Follows-----
> > 
> > >
> > 
> > > _______________________________________________
> > 
> > > computer-go mailing list
> > 
> > > [email protected]
> > 
> > > http://www.computer-go.org/mailman/listinfo/computer-go/
> > 
> > 
> > 
> > 
> > 
> > 
> > 
> > _______________________________________________
> > 
> > computer-go mailing list
> > 
> > [email protected]
> > 
> > http://www.computer-go.org/mailman/listinfo/computer-go/
> > 
> > 
> > 
> > 
> > -----Inline Attachment Follows-----
> > 
> > _______________________________________________
> > computer-go mailing list
> > [email protected]
> > http://www.computer-go.org/mailman/listinfo/computer-go/


      
> _______________________________________________
> computer-go mailing list
> [email protected]
> http://www.computer-go.org/mailman/listinfo/computer-go/
> 



-- 



_______________________________________________
computer-go mailing list
[email protected]
http://www.computer-go.org/mailman/listinfo/computer-go/

Reply via email to