[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: Benson Rules!



> I studied your thesis and even started to implement some code
>when I was implementing the scoring for pubgo (many thanks for
>making your work public).
>
>I found that to implement the scheme for a general case
>(many strings and false eyes etc) would have required a considerable
>effort (in terms of program structure). The problem is deciding which
>strings are the focus of the algolrithm. It looked like you would
>need to try all combinations or have some heuristics for flaging
>a stable core. I am missing something ?
>

Yes, you're missing something, but you're not the first :)
It is the main difference between Benson's first and second paper, an
improvement in the algorithm. The same idea also works for my definitions
of 1-vital and 2-vital. Instead of computing small sets and making them
bigger, you go the other way.
You initially make a set as big as possible, and then throw out those
blocks that don't have 2 healthy regions.

I guess code says it better than words, so I have attached the core
routines below. These are used by all solvers, such as BensonSolver and my
own VitalSolver. VitalSolver computes 2-vital regions (regions that already
provide 2 sure libs for a neighboring block) before calling this.

>
> I also came to the conclusion that us humans do not think like this.
>In the end I just used a brute force search to detect life / death.
>

I agree that humans don't initially work like this. However, as a player I
have also found it useful to think about these fundamentals.

        Martin

The following is actual code from Smart Go Board/Explorer, with some
debugging  #if's removed. This code is not in the public domain and is
given for illustration purposes only.

void BasicSolver::FindSafePoints (BWSET& safe)
{
        GenBlocksRegions (); // find all blocks and regions on whole board

        for (BlackWhite col = fBlack; col <= fWhite; col++)
        {
                ListOf<ListOf<BBlock> > sets;
                FindTestSets (sets, col); // find maximal sets for
aliveness testing

                for (ListIteratorOf<ListOf<BBlock> > it (sets); it; ++it)
                {       TestAlive (**it, safe, col); // find safe subset
within each maximal set
                        delete *it; // new 96-02-05
                }
        }
} // FindSafePoints

void BasicSolver::FindTestSets (ListOf<ListOf<BBlock> > & sets, BlackWhite col)
{
        ASSERT(sets.IsEmpty());

        ListOf<BBlock> doneSoFar;
        for (ListIteratorOf<BBlock> it (AllBlocks (col)); it; ++it)
        {       BBlock* block = *it;
                if (!doneSoFar.Contains (block))
                {
                        ListOf<BBlock>* blocks = new ListOf<BBlock>;
                        blocks->Append(block);

                        FindClosure(*blocks);
                        doneSoFar.Concat(&ListOf<BBlock>(*blocks)); // copy
constructor,

// to avoid deleting blocks list
                        sets.Append (blocks);
                }
        }
} // FindTestSets

void BasicSolver::FindClosure (ListOf<BBlock>& blocks)
// compute closure of blocks set: expand set of blocks until
// all blocks adjacent to all adjacent regions are in set.
// see [Benson] for explanation.
{
        ListOf<BBlock> toTest = blocks;

        while (toTest.NonEmpty())
        {
                const BBlock* b = toTest.Pop();
                for (ListIteratorOf<Region> it (b->m_healthy); it; ++it)
                {       Region* r = *it;
                        for (ListIteratorOf<BBlock> it (r->m_blocks); it; ++it)
                        {       BBlock* b2 = *it;
                                if(!blocks.Contains(b2) &&
b2->m_healthy.Contains(r))
                                {
                                        blocks.Append(b2);
                                        toTest.Append(b2);
                                }
                        }
                }
        }
} // FindClosure

void BasicSolver::TestAlive (ListOf<BBlock>& blocks, BWSET& safe,
BlackWhite color)
// Test if list of Benson blocks forms a living group.
//      Each block must have a sure liberty count of at least 2.
//      A region provides one sure liberty if it is healthy and its
boundary consists
//      only of blocks in the list.
{
        ListOf<Region> regions = AllRegions(color);

        bool changed;
        ListOf<BBlock> toDelete;
        do
        {
                TestAdjacent (regions, blocks);
                toDelete.Clear();
                for (ListIteratorOf<BBlock> it (blocks); it; ++it)
                {
                        ListOf<Region>& br = (*it)->m_healthy;

                        bool has2 = br.MinLength(2);
                        if (has2)
                        {
                                int nuRegions = 0;
                                for (ListIteratorOf<Region> it(br); it; ++it)
                                {
                                        if (regions.Contains(*it))
                                        {
                                                nuRegions++;
                                                if (nuRegions >= 2)
                                                        break;
                                        }
                                }
                                has2 = (nuRegions >= 2);
                        }
                        if (!has2)
                                toDelete.Append(*it);
                }

                changed = toDelete.NonEmpty();
                if (changed)
                {
                        for (ListIteratorOf<BBlock> it (toDelete); it; ++it)
                                blocks.Exclude(*it);
                }
        } while(changed);

        if (blocks.NonEmpty())
        {
                PointSet blockPoints;
                for (ListIteratorOf<BBlock> it (blocks); it; ++it)
                {
                        blockPoints |= (*it)->Stones();
                }

                color = blocks.Top()->Color(); // **** setting it once
would be enough..
                safe [color] |= blockPoints;

                {       for (ListIteratorOf<Region> it (regions); it; ++it)
                        {       if      ((*it)->HealthyForSomeBlock (blocks))
                                {       safe [color] |= (*it)->Points();
                                }
                }       }
        }
} // TestAlive