[computer-go] How to improve Orego

Łukasz Lew lukasz.lew at gmail.com
Mon Dec 11 09:43:30 PST 2006


Hi, here is an explanation along with the code:

First, my eyechecking is very fast:

  bool is_eyelike (color::t color, v::t v) {
    int diag_color_cnt[color::cnt];

    assertc (board_ac, is_ready ());

    if (((nbr_player_cnt[v] >> (color * 4)) & 0xf) != 4) {
      assertc (board_ac && slow_ac, slow_eyetest(color, v) != 4);
      return false;
    }
    assertc (board_ac && slow_ac, slow_eyetest(color, v) == 4);

    rep (c, color::cnt) diag_color_cnt[c] = 0;
    diag_color_cnt[color_at[v::NW (v)]]++;
    diag_color_cnt[color_at[v::NE (v)]]++;
    diag_color_cnt[color_at[v::SW (v)]]++;
    diag_color_cnt[color_at[v::SE (v)]]++;

    if (diag_color_cnt[color::edge] > 0)
diag_color_cnt[color::opponent(color)]++;
    if (diag_color_cnt[color::opponent(color)] >= 2) return false;
    return true;
  }

Basicly it's all about this condition
((nbr_player_cnt[v] >> (color * 4)) & 0xf) != 4

color is 0 (black) or 1(white) .
nbr_player_cnt[v] is two 4bit  counters in one int.
Updating it is fast, as I add 0x01 or 0x10 depending on new neighbour.
nbr_player_cnt[v] += (1 << (new_nbr_color * 4));

----

So I do not allow for self eye filling. What I did is I was generating
pass when I made full loop on my circular list (array), without
finding legal move.

What I do now (from yesterday), I move all rejected moves (for any of
the players) to "rejected" array. When the main list gets empty, I
just memcpy rejected onto main and try again. I generate pass if after
memcpy, no legal move is found. This improved 30.1 -> 33.3pps.

If I allow for only one memcpy, then sometimes
one-eye-only-no-other-liberties dead stones
remain after the playout, but there is no to much thrashing on the end
of the playout and I get 37 pps

Hope this helps.

Lukasz.

On 12/9/06, Don Dailey <drd at mit.edu> wrote:
> Lukasz,
>
> I have an implementation of your circular list in place, but I'm having
> a difficult time dealing with the single point eyes which my program
> does not allow as well as suicide which I don't allow either.
>
> I built a little circular list and I put captured points back into the
> circular
> list in random locations.   That part is fine.
>
> My implementation does not allow suicide or moves to certain kinds of 1
> point eyes.   When I reach those points in the list of empty
> intersections,  I cannot play them, but I cannot dismiss them either.
> They may be legal for the opponent and they may be legal later for the
> computer.
>
> Just for timing purposes I wanted to see what would happen if I just
> pushed those to the end of the list and continued until I tried all
> moves.   This is clearly not random but it does work.
>
> Unfortunately,  near the end of games I'm thrashing around in the list a
> lot and it's actually a slowdown.   There are too many unplayable moves
> that I have to skip over but I cannot dismiss them.   These moves
> dominate the list near the end of the game.
>
> The problem is more with the eyes than with suicide.   You solved the
> suicide problem by making it legal,  but I don't know how you solved the
> eye problem.
>
> I'm not sure what you are doing, but it sounds like you basically allow
> ANY move to an empty intersection except a single stone suicide, in
> which case you dismiss this intersection from the empty list forever.
> This would probably cause your loop to terminate before going to far
> even without an eye rule.
>
> But is this understanding correct?   Can you clarify?
>
> - Don
>
>
>
> On Thu, 2006-12-07 at 16:05 +0100, Łukasz Lew wrote:
> > I really do randomize a whole vector of empty intersections before the playout.
> > When I get new empty intersection I just pick random place in vector,
> > move it to the end,
> > and use the place for new intersection.
> >
> > Here is the code:
> >
> >   void add_rnd (v::t v) {
> >     int ii;
> >
> >     empty_v_cnt++;
> >
> >     ii = pm::rand () % empty_v_cnt;         // TODO improve speed "%"
> >     tab[empty_v_cnt-1] = tab[ii];
> >     tab[ii] = v;
> >     assertc (mc_legal_ac, empty_v_cnt <= max_size*max_size);
> >   }
> >
> > I play the playout until there are no more legal moves. I allow ko
> > recapture and large suicides. I have problem with signle stone
> > suicides.
> > So when one happens (I can only detect it by actually playing the
> > stone), I just take next empty intersection.
> >
> > "Circular" reduces frequency of such wasteful events.
> > It means that I check next empty intersection in the vector starting
> > from the place I finished last time.
> >
> > I hope this is clear now. If not, just ask :)
> >
> > Lukasz Lew
> >
> > On 12/6/06, Don Dailey <drd at mit.edu> wrote:
> > > On Mon, 2006-12-04 at 18:32 +0100, Łukasz Lew wrote:
> > > > I deal with eyes by randomizing list of empty intersections before the
> > > > playout, and while searching non-eye I go through them in circular
> > > > manner.
> > >
> > > What do you mean by circular and what does this have to do with eyes?
> > > I'm looking to speed my random player up a little bit more.   Here is
> > > what I've been doing for the last year or two:
> > >
> > > I collect all the empty intersections into an array and I randomize them
> > > as I go.   When a capture happens, it screws up your list - you must
> > > either add those intersections back to the pool of empty intersections
> > > or just reinitialize the list.   Right now I'm just reinitializing the
> > > list from scratch again - probably not the fastest way.
> > >
> > > I could of course randomize the list of empty intersections with a
> > > Fisher-Yates shuffle FIRST and then traverse the list in order till
> > > there is a capture but I think this is more work on the average because
> > > if you scramble a big list and the next move is a capture,  you have to
> > > rework the list anyway and randomize again.    I guess you might call
> > > what I do a "lazy" shuffle - you don't do the work unless you need to.
> > > (However, if I knew I would always need the whole list, it probably
> > > produces a little bit faster code to scramble them all at once in a
> > > tight little shuffle loop.)
> > >
> > > The actually procedure for "incremental randomization" is that I pick
> > > randomly from the empty list and then "fix the list back up" by swapping
> > > this out of the way with the first element in the list (which gets moved
> > > out of the picture because I bump up the "list start" pointer.)
> > >
> > > - Don
> > >
> > >
> > >
> > >
> > > _______________________________________________
> > > computer-go mailing list
> > > computer-go at computer-go.org
> > > http://www.computer-go.org/mailman/listinfo/computer-go/
> > >
>
>


More information about the computer-go mailing list