public bool Applicable(IDBOperator oper, DBNode node)
    {
        GBOperator   goper  = (GBOperator)oper;
        GBSpaceState gstate = (GBSpaceState)node.State;

        return(goper.Applicable(gstate));
    }
    private static bool IsLastOperatorDependent(GoBangBoard.StoneSet ss,
                                                GBOperator last)
    {
        // Special case for root node
        if (last == null)
        {
            return(true);
        }

        int px = ss.x, py = ss.y;

        for (int n = 0; n < ss.stones.Length; ++n)
        {
            // Now check if it could theoretically depend.  Then the
            // last operator must have touched (fAdd) stones available
            // in this stoneset.
            for (int k = 0; k < last.fAdd.GetLength(0); ++k)
            {
                if (last.fAdd[k, 0] == px && last.fAdd[k, 1] == py)
                {
                    return(true);
                }
            }
            py += ss.ay;
            px += ss.ax;
        }

        return(false);
    }
    public void RegisterNewNode(DBNode node, DBNode root)
    {
        DoExpirationCheck();

        if (node.IsGoal == false)
        {
            return;
        }

        // For goal nodes, we check if on-the-fly refutation is wanted, and if
        // so, we try to refute the goal node.
        if (doDefenseRefutationCheck)
        {
            GBSpaceState     gRootState = (GBSpaceState)root.State;
            GBThreatSequence seq        = GBThreatSearch.DefenseRefutable
                                              (gRootState.GB, root, node);

            if (seq != null)
            {
                throw (new GBThreatSearch.GBWinningThreatSequenceFoundException(seq));
            }
        }

        // This is old code
#if false
        // Now the last node did modify something, but we only want to cache
        // dependency nodes, as combination nodes will not be combined
        // themselves.
        if (node.Type != DBNode.NodeType.Dependency)
        {
            return;
        }

        GBSpaceState state = (GBSpaceState)node.State;
        GBOperator   last  = state.LastOperator;
        if (last == null)
        {
            return;
        }

        // Now, we add this node to the array at all its influencing places,
        // but only where it sets a stone of the attacker (which is the only
        // position that can create new possibilities for attack).
        for (int n = 0; n < last.fAdd.GetLength(0); ++n)
        {
            // Ignore everything except the attacker stones.
            if (last.fAdd[n, 2] != 1)
            {
                continue;
            }

            // Add coordinate
            nodesThatAffectSquares[last.fAdd[n, 1], last.fAdd[n, 0]].Add(node);

            return;
        }
#endif
    }
    public GBSpaceState(GoBangBoard gb, GBOperator lastOperator,
                        GBSpaceState lastState, GBOperator[] legalOperators)
    {
        this.gb           = gb;
        this.lastOperator = lastOperator;
        this.lastState    = lastState;

        this.legalOperators = legalOperators;
    }
    public static void Main(string[] args)
    {
        GoBangBoard gb  = new GoBangBoard();
        Random      rnd = new Random();

        // Initialize board randomly
        for (int n = 0; n < 130; ++n)
        {
            gb.board[rnd.Next(0, boardDim), rnd.Next(0, boardDim)] =
                rnd.Next(0, 3) - 1;
        }

        int count = 0;

        foreach (StoneSet ss in gb.G5)
        {
            Console.Write("ss at ({0},{1}) to ({2},{3}), len {4}: ",
                          ss.x, ss.y, ss.ax, ss.ay, ss.stones.Length);
            foreach (int stone in ss.stones)
            {
                Console.Write("{0}", (stone == 0) ? "." :
                              ((stone == 1) ? "O" : "X"));
            }
            Console.WriteLine();

            count += 1;
        }
        Console.WriteLine("|G5| = {0}", count);

        count = 0;
        foreach (StoneSet ss in gb.G6)
        {
            count += 1;
        }
        Console.WriteLine("|G6| = {0}", count);

        count = 0;
        foreach (StoneSet ss in gb.G7)
        {
            count += 1;
        }
        Console.WriteLine("|G7| = {0}", count);

        // Test operators a little
        gb.DumpBoard();

        GBSpaceState state = new GBSpaceState(gb);

        GBOperator[] legalOpers = GBOperator.LegalOperators(state, 2);
        foreach (GBOperator gop in legalOpers)
        {
            Console.WriteLine("oper: {0}", gop);
        }
    }
    // @param gp Goal path.
    public static GBThreatSequence BuildThreatSequence(ArrayList gp)
    {
        GBThreatSequence ts = new GBThreatSequence();

        GBThreatSequence now = ts;

        for (int n = 0; n < gp.Count; ++n)
        {
            DBNode       pathnode = (DBNode)gp[n];
            GBSpaceState state    = (GBSpaceState)pathnode.State;

            // First add the nodes of the path.
            if (state.CombinedOperPath != null)
            {
                /*Console.WriteLine ("DEBUG CombinedOperPath, {0} moves",
                 *      state.CombinedOperPath.Count);*/

                foreach (GBOperator oper in state.CombinedOperPath)
                {
                    //Console.WriteLine ("    oper: {0}", oper);
                    FillInMoves(now, oper);

                    now.next = new GBThreatSequence();
                    now      = now.next;
                }
            }

            //Console.WriteLine ("DEBUG LastOperator");
            // Now the last operator
            GBOperator last = (GBOperator)state.LastOperator;
            if (last == null)
            {
                continue;
            }

            //Console.WriteLine ("    last: {0}", last);
            FillInMoves(now, last);

            // Chain it up, baby.
            now.next = null;
            if (n < (gp.Count - 1))
            {
                now.next = new GBThreatSequence();
                now      = now.next;
            }
        }

        return(ts);
    }
    public void UpdateLegalOperators(int maxCat, bool doCatReduction)
    {
        // If we do category reduction, we shall proceed like this:
        // "... if in a node N of the db-search DAG, the defender has a threat
        // of category c_1, for each descendent of N the attacker is
        // restricted to threats of categories less than c_1".
        //
        // So we first find out the threats of the defender
        if (maxCat >= 1 && doCatReduction)
        {
            // Reverse attacker/defender
            GoBangBoard gbFlip = (GoBangBoard)gb.Clone();
            gbFlip.Flip();

            int lowestCat = GBOperator.LowestOperatorCategory(gbFlip);
            //Console.WriteLine ("lowestCat = {0}, maxCat = {1}", lowestCat, maxCat);

            // If the defender has a five already, there is no need to search.
            if (lowestCat == 0)
            {
                this.legalOperators = null;

                return;
            }

            // Now, we have to add one to the lowest category.  This is
            // because the operators judge what they can create in one move,
            // not what is already there on the board.
            lowestCat += 1;

            // Otherwise, if the defenders lowest category threat is below or
            // equal to the current maximum category, we decrease the maximum
            // category to allow only those attacker threats that can still
            // force.
            if (lowestCat <= maxCat)
            {
                Console.WriteLine("doCatRed: from {0} to {1}", maxCat, lowestCat - 1);
                maxCat = lowestCat - 1;
            }
            else
            {
                Console.WriteLine("maxCat = {0}", maxCat);
            }
        }

        this.legalOperators = GBOperator.LegalOperators(this, maxCat);
    }
    /** Test for operator equality.  This is important as to identify common
     * operators in combination nodes.
     *
     * @param o2 The other operator to be compared.
     *
     * @returns True in case they are equal, false otherwise.
     */
    public override bool Equals(object o2)
    {
        if (o2 == null)
        {
            return(false);
        }

        GBOperator op2 = (GBOperator)o2;

        if (Name != op2.Name)
        {
            return(false);
        }

        if (fAdd.GetLength(0) != op2.fAdd.GetLength(0))
        {
            return(false);
        }

        // XXX: Tricky, as we have not specified an ordering for the f_{add}
        // set (which we maybe should do, as we could get rid of the inner
        // loop then).  So, operator equality should be on board level, hence
        // we need to compare the stone coordinates, and not the relative
        // settings in the fAdd array.
        for (int n1 = 0; n1 < fAdd.GetLength(0); ++n1)
        {
            for (int n2 = 0; n2 < fAdd.GetLength(0); ++n2)
            {
                if (fAdd[n1, 0] == op2.fAdd[n2, 0] &&
                    fAdd[n1, 1] == op2.fAdd[n2, 1] &&
                    fAdd[n1, 2] == op2.fAdd[n2, 2])
                {
                    goto foundStone;
                }
            }

            // Stone was not found, operators are not equal
            return(false);

foundStone:
            ;
        }

        // All stones have been found.
        return(true);
    }
    public static int[,] BuildOperatorMap(GoBangBoard board, out int maxCount)
    {
        // Get legal operators for the state represented by the board
        GBSpaceState state = new GBSpaceState(board);

        GBOperator[] opers = GBOperator.LegalOperators(state, 2);

        // Now build an attack count map and keep track of the maximum number
        // of operators a single attack stone creates.
        maxCount         = 0;
        int[,] attackMap = new int[GoBangBoard.boardDim, GoBangBoard.boardDim];

        foreach (GBOperator op in opers)
        {
            if (op is GBOperatorThree3)
            {
                continue;
            }

            for (int n = 0; n < op.fAdd.GetLength(0); ++n)
            {
                // We are not (yet) interested in the defending stones.
                if (op.fAdd[n, 2] == -1)
                {
                    continue;
                }

                int x = op.fAdd[n, 0];
                int y = op.fAdd[n, 1];
                attackMap[y, x] += 1;
                Console.WriteLine("at ({0}, {1}) oper: {2}", x, y, op);

                if (attackMap[y, x] > maxCount)
                {
                    maxCount = attackMap[y, x];
                }
            }
        }

        return(attackMap);
    }
    private static void FillInMoves(GBThreatSequence seq, GBOperator oper)
    {
        // Create attacker and defender moves.
        ArrayList defenderMoves = new ArrayList();

        //Console.WriteLine ("DEBUG FillInMoves, {0} moves", oper.fAdd.GetLength (0));

        for (int move = 0; move < oper.fAdd.GetLength(0); ++move)
        {
            // Attacker move
            if (oper.fAdd[move, 2] == 1)
            {
                seq.attacker = new GBMove(oper.fAdd[move, 0],
                                          oper.fAdd[move, 1], oper.fAdd[move, 2]);
                seq.attackerThreatClass = oper.Class;
            }
            else if (oper.fAdd[move, 2] == -1)
            {
                defenderMoves.Add(new GBMove(oper.fAdd[move, 0],
                                             oper.fAdd[move, 1], oper.fAdd[move, 2]));
            }
        }
        seq.defender = (GBMove[])defenderMoves.ToArray(typeof(GBMove));
    }
    private static bool IsLastOperatorDependent(GoBangBoard.StoneSet ss,
		GBOperator last)
    {
        // Special case for root node
        if (last == null)
            return (true);

        int px = ss.x, py = ss.y;

        for (int n = 0 ; n < ss.stones.Length ; ++n) {
            // Now check if it could theoretically depend.  Then the
            // last operator must have touched (fAdd) stones available
            // in this stoneset.
            for (int k = 0 ; k < last.fAdd.GetLength (0) ; ++k) {
                if (last.fAdd[k,0] == px && last.fAdd[k,1] == py)
                    return (true);
            }
            py += ss.ay;
            px += ss.ax;
        }

        return (false);
    }
    public GBSpaceState(GoBangBoard gb, GBOperator lastOperator,
		GBSpaceState lastState, GBOperator[] legalOperators)
    {
        this.gb = gb;
        this.lastOperator = lastOperator;
        this.lastState = lastState;

        this.legalOperators = legalOperators;
    }
 public GBSpaceState(GoBangBoard gb, GBOperator lastOperator,
                     GBSpaceState lastState, int maxCat)
     : this(gb, lastOperator, lastState, null)
 {
     this.legalOperators = GBOperator.LegalOperators(this, maxCat);
 }
    private static void FillInMoves(GBThreatSequence seq, GBOperator oper)
    {
        // Create attacker and defender moves.
        ArrayList defenderMoves = new ArrayList ();

        //Console.WriteLine ("DEBUG FillInMoves, {0} moves", oper.fAdd.GetLength (0));

        for (int move = 0 ; move < oper.fAdd.GetLength (0) ; ++move) {
            // Attacker move
            if (oper.fAdd[move, 2] == 1) {
                seq.attacker = new GBMove (oper.fAdd[move, 0],
                    oper.fAdd[move, 1], oper.fAdd[move, 2]);
                seq.attackerThreatClass = oper.Class;
            } else if (oper.fAdd[move, 2] == -1) {
                defenderMoves.Add (new GBMove (oper.fAdd[move, 0],
                    oper.fAdd[move, 1], oper.fAdd[move, 2]));
            }
        }
        seq.defender = (GBMove[]) defenderMoves.ToArray (typeof (GBMove));
    }
    public bool UpdateIsGoal(DBSearchModule dbS)
    {
        GBSearchModule gbS = (GBSearchModule)dbS;
        int            white, hole;

        // 1. Five
        foreach (GoBangBoard.StoneSet ss in GB.G5)
        {
            GBOperator.CountStones(ss, out white, out hole);

            if (white == 5 && hole == 0)
            {
                /*Console.WriteLine (GB);
                 * Console.WriteLine ("=> goal because of five");*/

                isGoal = true;
                return(true);
            }
        }

        // 2. Straight four
        // FIXME/TODO: check if this is right, i mean the check here
        if (gbS.maximumCategory >= 1)
        {
            foreach (GoBangBoard.StoneSet ss in GB.G6)
            {
                if (ss.stones[0] != 0 || ss.stones[5] != 0)
                {
                    continue;
                }

                GBOperator.CountStones(ss, out white, out hole);

                if (white == 4 && hole == 2)
                {
                    /*Console.WriteLine (GB);
                     * Console.WriteLine ("goal because of four");*/
                    isGoal = true;
                    return(true);
                }
            }
        }

        // Check if there are extra fixed goal squares.
        if (gbS.goalIfOccupied == null)
        {
            isGoal = false;

            return(false);
        }
// There extra squares, check if they are occupied by the defender
        // (-1, but in the flipped field its 1) in this state.
        for (int n = 0; n < gbS.goalIfOccupied.GetLength(0); ++n)
        {
            if (gb.board[gbS.goalIfOccupied[n, 1], gbS.goalIfOccupied[n, 0]] == 1)
            {
                /*Console.WriteLine (GB);
                 * Console.WriteLine ("goal because occupation of ({0},{1})",
                 *      gbS.goalIfOccupied[n,0], gbS.goalIfOccupied[n,1]);*/
                isGoal = true;

                return(true);
            }
        }

        // Neither a necessary field has been occupied, nor a five/four been
        isGoal = false;
        return(false);
    }
    // TODO: this needs to be changed fundamentally, including changes in
    // DBSearch.cs.
    //
    // GoMoku will need up to four nodes combined in one combination step, for
    // a situation like this (artificial, but illustrates the point):
    //
    //    O  O  O
    //    O  O  O
    //    O3 O2 O1
    //
    // Lets assume the two rows at the top already existed before, and the
    // states O1, O2 and O3 have been independently explored (as they create a
    // new application of an operator, this will be the case).  However, then
    // the row O1, O2 and O3 create a new threat.  This can only be "seen" by
    // db-search if they are allowed to be combined in one step.  No single
    // combination will create a new dependent operator.
    //
    // We might do up-to-four combination efficiently by exploiting the board
    // geometry.  To do that, we create an array the same dimensions as the
    // board of linked list, storing states.  For each dependency node state,
    // store the state in a number of linked lists.  Store them in that linked
    // lists that are behind the coordinates in the f_{add} set of the last
    // operator of the state.
    //
    // Then, for each coordinate, we do the following: extract all linked
    // lists in a G_7 environment centered at the coordinate into one big
    // linked list.  Only check all the states refered in this big list for
    // 2-, 3- and 4-combinability.  For each coordinate we have to do this
    // four times for the different G_7 environment.
    //
    // The pseudo code for the whole combination stage would look like:
    //
    // foreach (Coordinate coord in boardCoordinates) {
    //   foreach (G_7 g7 centeredIn coord) {
    //     ArrayList states = new ArrayList ();
    //     foreach (Square sq in g7)
    //       states.AddRange (sq.States);
    //
    //     foreach (2-Combination (c1, c2) in states)
    //       CheckCombinability (c1, c2);
    //     foreach (3-Combination (c1, c2, c3) in states)
    //       CheckCombinability (c1, c2, c3);
    //     foreach (4-Combination (c1, c2, c3, c4) in states)
    //       CheckCombinability (c1, c2, c3, c4);
    //   }
    // }
    //
    // The numerical complexity is (n \over k) = \frac{n!}{k! (n - k)!}
    // where n = number of states collected in "states". k = number of
    // elements in the combination (2, 3, 4).
    //
    // So, for n states on the combined G_7 square list this would give
    // (n \over k) k-Combinations.
    //
    // States |  2-C |    3-C |     4-C
    // -------+------+--------+--------
    //     10 |   45 |    120 |     210
    //     20 |  190 |   1140 |    4845
    //    100 | 4950 | 161700 | 3921225
    //
    // So we should keep the number of states influencing a board square well
    // below 100, while <= 20 is certainly ok.
    //
    // XXX: for now, we only test with two-combinability
    public IDBSpaceState CombineIfResultIsNewOperators(DBNode node1,
                                                       Stack node1Path, DBNode node2, Stack node2Path)
    {
        GBSpaceState gstate1 = (GBSpaceState)node1.State;
        GBSpaceState gstate2 = (GBSpaceState)node2.State;
        GBOperator   last2   = gstate2.LastOperator;

        // First check the boards are not incompatible:
        // TODO: check if this is right (or necessary, does not seem to change
        // any results).
        if (gstate2.GB.CompatibleWith(((GBSpaceState)node1.State).GB) == false)
        {
            return(null);
        }

        // Build combined state by applying operator chain.
        ArrayList operatorChain = new ArrayList();

        foreach (DBNode pN in node2Path)
        {
            if (node1Path.Contains(pN))
            {
                break;
            }

            GBSpaceState nstate = (GBSpaceState)pN.State;
            operatorChain.Add(nstate.LastOperator);

            if (nstate.CombinedOperPath != null)
            {
                ArrayList combRev = (ArrayList)nstate.CombinedOperPath.Clone();
                combRev.Reverse();

                operatorChain.AddRange(combRev);
            }
        }
        operatorChain.Reverse();
        operatorChain.Add(last2);

        GBSpaceState gComb = (GBSpaceState)node1.State;

        foreach (GBOperator oper in operatorChain)
        {
            gComb = (GBSpaceState)oper.Apply(this, gComb);
        }

        //GBSpaceState gComb = (GBSpaceState) last2.Apply (this, node1.State);
        //gComb.GB.AddExtraStones (gstate2.GB);
        gComb.UpdateLegalOperators(maximumCategory, categoryReductionHeuristicOn);

        // Now check if the new state results in new operators
        GBOperator[] n1o = gstate1.LegalOperators;
        GBOperator[] n2o = gstate2.LegalOperators;

        GBOperator[] nCo = gComb.LegalOperators;
        if (nCo == null)
        {
            return(null);
        }

        // Check: nCo \setminus (n1o \cup n2o) \neq \emptyset
        foreach (GBOperator gbo in nCo)
        {
            if (n1o != null && Array.IndexOf(n1o, gbo) >= 0)
            {
                return(null);
            }
            if (n2o != null && Array.IndexOf(n2o, gbo) >= 0)
            {
                return(null);
            }
        }

        gComb.UpdateIsGoal(this);

        // Now that the combination succeeded, we still need to copy over all
        // the operators we applied 'at once' when copying the field content.
        // We need to do this for the threat sequence search later, which
        // needs operator-level granularity for the defense search.
        gComb.BuildCombinedOperatorPath(node1Path, node2Path);

        return(gComb);
    }
    public bool Applicable(IDBOperator oper, GBSpaceState state)
    {
        GBOperator goper = (GBOperator)oper;

        return(goper.Applicable(state));
    }
    public GBSpaceState(GoBangBoard gb, GBOperator lastOperator,
		GBSpaceState lastState, int maxCat)
        : this(gb, lastOperator, lastState, null)
    {
        this.legalOperators = GBOperator.LegalOperators (this, maxCat);
    }