private static void GoalPathesI(GBSearchModule module,
                                    ArrayList goalpathes, DBNode node, Stack path)
    {
        if (node == null)
        {
            return;
        }

        if (module.IsGoal(node.State))
        {
            ArrayList newGoalPath = new ArrayList();

            foreach (DBNode pNode in path)
            {
                newGoalPath.Add(pNode);
            }

            newGoalPath.Reverse();

            newGoalPath.Add(node);
            goalpathes.Add(newGoalPath);

            return;
        }

        foreach (DBNode child in node.Children)
        {
            path.Push(node);
            GoalPathesI(module, goalpathes, child, path);
            path.Pop();
        }
    }
    /** Apply the operator to the given state, returning a new state.
     *
     * @param state The source state.
     *
     * @returns The newly created destination state.
     */
    public IDBSpaceState Apply(DBSearchModule module, IDBSpaceState stateDB)
    {
        GBSearchModule gmod  = (GBSearchModule)module;
        GBSpaceState   state = (GBSpaceState)stateDB;

        // TODO: remove later, we already checked this previously
        if (Valid(state) == false)
        {
            throw (new ArgumentException("Operator not applicable!"));
        }

        GoBangBoard newBoard = (GoBangBoard)state.GB.Clone();

        // Apply all the f_{add} stones
        for (int n = 0; n < fAdd.GetLength(0); ++n)
        {
            newBoard.board[fAdd[n, 1], fAdd[n, 0]] = fAdd[n, 2];
        }

        GBSpaceState newState = new GBSpaceState(newBoard, this, state,
                                                 gmod.maximumCategory);

        newState.UpdateIsGoal(gmod);

        return(newState);
    }
    /** Build a list of goal pathes.
     */
    private static ArrayList GoalPathes(GBSearchModule module, DBNode root)
    {
        ArrayList goalpathes = new ArrayList();

        GoalPathesI(module, goalpathes, root, new Stack());

        return(goalpathes);
    }
Exemplo n.º 4
0
 public GBOperatorCombineFastCheck(DBSearch dbS, GBSearchModule gbS,
                                   ArrayList thisStageDependencies, int level)
 {
     this.dbS = dbS;
     this.gbS = gbS;
     this.thisStageDependencies = thisStageDependencies;
     this.level = level;
 }
    public GBOperatorCombineFastCheck(DBSearch dbS, GBSearchModule gbS,
		ArrayList thisStageDependencies, int level)
    {
        this.dbS = dbS;
        this.gbS = gbS;
        this.thisStageDependencies = thisStageDependencies;
        this.level = level;
    }
    // Global function
    public GBThreatSequence FindWinningThreatSeq()
    {
        // First find a number of possibly winning threat trees.
        GBSearchModule gbSearch  = new GBSearchModule(GoBangBoard.boardDim);
        GBSpaceState   rootState = new GBSpaceState((GoBangBoard)gb.Clone());

        rootState.UpdateIsGoal(gbSearch);

        // HEURISTIC: use category reduction (page 140-141)
        gbSearch.categoryReductionHeuristicOn = true;

        DBSearch db = new DBSearch(gbSearch, breadthFirst);

        db.Search(rootState);
        //db.DumpDOTGoalsOnly ();

        // Now, enumerate all the possibly winning threat trees found
        GBThreatSequence[] potentialWinningSeqs =
            GBThreatSequence.BuildAllGoalPathes(gbSearch, db.Root);
        Console.WriteLine("{0} potential winning threat sequences.",
                          potentialWinningSeqs.Length);

        // Check them one by one until a surely winning threat tree is found
        GoBangBoard gbFlipped = (GoBangBoard)gb.Clone();

        gbFlipped.Flip();

        int DEBUGwinningFound         = 0;
        GBThreatSequence DEBUGwinning = null;

        foreach (GBThreatSequence threatSeq in potentialWinningSeqs)
        {
            if (DefenseRefutes(threatSeq,
                               (GoBangBoard)gbFlipped.Clone()) < 0)
            {
                // Found a sure win, return early
                // FIXME: for debugging we count all winning sequences found,
                // but we should return as early as possible.
                DEBUGwinningFound += 1;
                DEBUGwinning       = threatSeq;
                //Console.WriteLine ("WINNING:\n{0}", threatSeq);
                // FIXME
                //return (threatSeq);
            }
        }

        Console.WriteLine("{0} winning of {1} potential winning threat sequences identified",
                          DEBUGwinningFound, potentialWinningSeqs.Length);

        // Found no unrefuted threat sequence
        return(DEBUGwinning);
    }
    public static GBThreatSequence[] BuildAllGoalPathes(GBSearchModule module,
                                                        DBNode root)
    {
        ArrayList goalpathes = GoalPathes(module, root);

        Console.WriteLine("I have {0} goal pathes", goalpathes.Count);

        // Create the threat sequences.
        ArrayList threatSeqs = new ArrayList();

        // Build one individual threat sequence for each goalpath.
        foreach (ArrayList gp in goalpathes)
        {
            GBThreatSequence ts = BuildThreatSequence(gp);
            threatSeqs.Add(ts);
        }

        // DEBUG output
        Console.WriteLine("{0} threat seqs lists", threatSeqs.Count);
        int seqNo = 1;

        foreach (GBThreatSequence seqW in threatSeqs)
        {
            GBThreatSequence seq = seqW;
            Console.WriteLine();

            Console.WriteLine(((GBSpaceState)root.State).GB);
            Console.WriteLine();
            Console.WriteLine("Sequence {0}: ", seqNo);

            int m = 0;
            while (seq != null)
            {
                Console.WriteLine("  move{0}: {1}, threat class {2}", m,
                                  seq.attacker, seq.attackerThreatClass);
                m += 1;

                foreach (GBMove reply in seq.defender)
                {
                    Console.WriteLine("      def-reply{0}: {1}", m, reply);
                    m += 1;
                }

                seq = seq.next;
            }

            seqNo += 1;
        }

        return((GBThreatSequence[])
               threatSeqs.ToArray(typeof(GBThreatSequence)));
    }
    /** Try to find a winning threat sequence by dependency based search and
     * on the fly refutation for goal nodes.
     *
     * Return early, as soon as a sure candidate has been found.
     *
     * @param timeoutMS If non-zero, a maximum time spend in db-search is
     * given in milliseconds.  At least 1000 (1s) is meaningful to do
     * something, though.
     *
     * @returns The first winning threat sequence on success, null otherwise.
     */
    public GBThreatSequence FindWinningThreatSeqOTF(int timeoutMS)
    {
        // First find a number of possibly winning threat trees.
        GBSearchModule gbSearch  = new GBSearchModule(GoBangBoard.boardDim);
        GBSpaceState   rootState = new GBSpaceState((GoBangBoard)gb.Clone());

        rootState.UpdateIsGoal(gbSearch);

        // HEURISTIC: use category reduction (page 140-141)
        // FIXME: re-enable as soon as three3 bug is fixed.
        // FIXME: test if this is good in the real ai, otherwise disable again.
        //gbSearch.categoryReductionHeuristicOn = true;

        // Do on-the-fly refutation checking.
        gbSearch.doDefenseRefutationCheck = true;

        if (timeoutMS != 0)
        {
            gbSearch.doExpirationCheck = true;
            gbSearch.expireTime        = DateTime.Now.AddMilliseconds(timeoutMS);
        }

        DBSearch db = new DBSearch(gbSearch, breadthFirst);

        try {
            Console.WriteLine("Board:\n{0}\n", gb);
            db.Search(rootState);
            //db.DumpDOT ();
        } catch (GBSearchModule.GBSearchTimeoutException) {
            // We timed out...
            Console.WriteLine("FindWinningThreatSeqOTF: timeouted...");
        } catch (GBWinningThreatSequenceFoundException gex) {
            //db.DumpDOT ();
            return(gex.seq);
        }

        return(null);
    }
    /** Test the GBSearchModule
     */
    public static void Main(string[] args)
    {
        // Initialize a board randomly
        GoBangBoard gb = new GoBangBoard ();
        Random rnd = new Random ();

        /*
        for (int n = 0 ; n < 23 ; ++n)
            gb.board[rnd.Next (0, gb.boardDim), rnd.Next (0, gb.boardDim)] =
                rnd.Next (0, 3) - 1;
        */

        /*
        gb.board[5,5] = gb.board[5,8] = -1;
        gb.board[7,4] = gb.board[7,9] = -1;

        gb.board[5,4] = gb.board[5,6] = gb.board[5,7] = gb.board[5,9] = 1;
        gb.board[7,6] = gb.board[7,7] = 1;
        */

        gb.board[6,6] = gb.board[6,7] = gb.board[6,8] = 1;
        gb.board[7,7] = gb.board[8,6] = gb.board[8,7] = gb.board[8,8] = 1;
        gb.board[9,6] = gb.board[10,5] = gb.board[10,6] = gb.board[10,7] = 1;

        gb.board[6,5] = gb.board[7,5] = gb.board[7,6] = gb.board[7,8] = -1;
        gb.board[8,5] = gb.board[8,9] = gb.board[9,5] = gb.board[9,7] = gb.board[9,9] = -1;
        gb.board[10,4] = gb.board[11,6] = -1;

        gb.board[5,5] = 1;
        gb.board[4,4] = -1;

        gb.board[6,9] = 1;
        gb.board[6,10] = -1;
        gb.board[4,7] = 1;
        gb.board[5,7] = -1;

        /*
        gb.board[6,10] = 1;
        gb.board[6,9] = -1;
        */

        /*
        gb.board[6,6] = gb.board[6,7] = gb.board[6,8] = 1;
        gb.board[7,7] = gb.board[8,6] = gb.board[8,7] = gb.board[8,8] = 1;
        gb.board[9,6] = gb.board[10,5] = gb.board[10,6] = gb.board[10,7] = 1;

        gb.board[6,5] = gb.board[7,5] = gb.board[7,6] = gb.board[7,8] = -1;
        gb.board[8,5] = gb.board[8,9] = gb.board[9,5] = gb.board[9,7] = gb.board[9,9] = -1;
        gb.board[10,4] = gb.board[11,6] = -1;

        // Move 1/2
        gb.board[5,5] = 1;
        gb.board[4,4] = -1;

        // Move 3/4
        gb.board[5,7] = 1;
        gb.board[4,7] = -1;

        // Move 5/6
        gb.board[5,9] = 1;
        gb.board[4,10] = -1;

        // Move 7/8
        gb.board[5,8] = 1;
        gb.board[5,6] = -1;

        // Move 9/10
        gb.board[5,11] = 1;
        gb.board[5,10] = -1;

        // Move 11/12
        gb.board[6,10] = 1;
        gb.board[6,9] = -1;

        // Move 13/14
        gb.board[7,9] = 1;
        gb.board[4,12] = -1;

        // Move 15/16
        gb.board[4,6] = 1;
        gb.board[3,5] = -1;
        */

        /* TODO: check this, ask marco
        gb.board[4,4] = gb.board[6,6] = gb.board[7,7] = 1;
        */

        GBSearchModule gbSearch = new GBSearchModule (GoBangBoard.boardDim);
        GBSpaceState rootState = new GBSpaceState (gb);
        rootState.UpdateIsGoal (gbSearch);

        DBSearch db = new DBSearch (gbSearch, false);
        db.Search (rootState);

        db.DumpDOT ();
        //db.DumpDOTGoalsOnly ();
        gbSearch.DEBUGnodeArray ();
        /*
        foreach (DLPSpaceState state in db.GoalStates ()) {
            DumpOperatorChain (state);
        }
        */
    }
Exemplo n.º 10
0
    /** Test the GBSearchModule
     */
    public static void Main(string[] args)
    {
        // Initialize a board randomly
        GoBangBoard gb  = new GoBangBoard();
        Random      rnd = new Random();

        /*
         * for (int n = 0 ; n < 23 ; ++n)
         *      gb.board[rnd.Next (0, gb.boardDim), rnd.Next (0, gb.boardDim)] =
         *              rnd.Next (0, 3) - 1;
         */

        /*
         * gb.board[5,5] = gb.board[5,8] = -1;
         * gb.board[7,4] = gb.board[7,9] = -1;
         *
         * gb.board[5,4] = gb.board[5,6] = gb.board[5,7] = gb.board[5,9] = 1;
         * gb.board[7,6] = gb.board[7,7] = 1;
         */

        gb.board[6, 6] = gb.board[6, 7] = gb.board[6, 8] = 1;
        gb.board[7, 7] = gb.board[8, 6] = gb.board[8, 7] = gb.board[8, 8] = 1;
        gb.board[9, 6] = gb.board[10, 5] = gb.board[10, 6] = gb.board[10, 7] = 1;

        gb.board[6, 5]  = gb.board[7, 5] = gb.board[7, 6] = gb.board[7, 8] = -1;
        gb.board[8, 5]  = gb.board[8, 9] = gb.board[9, 5] = gb.board[9, 7] = gb.board[9, 9] = -1;
        gb.board[10, 4] = gb.board[11, 6] = -1;

        gb.board[5, 5] = 1;
        gb.board[4, 4] = -1;

        gb.board[6, 9]  = 1;
        gb.board[6, 10] = -1;
        gb.board[4, 7]  = 1;
        gb.board[5, 7]  = -1;

        /*
         * gb.board[6,10] = 1;
         * gb.board[6,9] = -1;
         */

        /*
         * gb.board[6,6] = gb.board[6,7] = gb.board[6,8] = 1;
         * gb.board[7,7] = gb.board[8,6] = gb.board[8,7] = gb.board[8,8] = 1;
         * gb.board[9,6] = gb.board[10,5] = gb.board[10,6] = gb.board[10,7] = 1;
         *
         * gb.board[6,5] = gb.board[7,5] = gb.board[7,6] = gb.board[7,8] = -1;
         * gb.board[8,5] = gb.board[8,9] = gb.board[9,5] = gb.board[9,7] = gb.board[9,9] = -1;
         * gb.board[10,4] = gb.board[11,6] = -1;
         *
         * // Move 1/2
         * gb.board[5,5] = 1;
         * gb.board[4,4] = -1;
         *
         * // Move 3/4
         * gb.board[5,7] = 1;
         * gb.board[4,7] = -1;
         *
         * // Move 5/6
         * gb.board[5,9] = 1;
         * gb.board[4,10] = -1;
         *
         * // Move 7/8
         * gb.board[5,8] = 1;
         * gb.board[5,6] = -1;
         *
         * // Move 9/10
         * gb.board[5,11] = 1;
         * gb.board[5,10] = -1;
         *
         * // Move 11/12
         * gb.board[6,10] = 1;
         * gb.board[6,9] = -1;
         *
         * // Move 13/14
         * gb.board[7,9] = 1;
         * gb.board[4,12] = -1;
         *
         * // Move 15/16
         * gb.board[4,6] = 1;
         * gb.board[3,5] = -1;
         */

        /* TODO: check this, ask marco
         * gb.board[4,4] = gb.board[6,6] = gb.board[7,7] = 1;
         */

        GBSearchModule gbSearch  = new GBSearchModule(GoBangBoard.boardDim);
        GBSpaceState   rootState = new GBSpaceState(gb);

        rootState.UpdateIsGoal(gbSearch);

        DBSearch db = new DBSearch(gbSearch, false);

        db.Search(rootState);

        db.DumpDOT();
        //db.DumpDOTGoalsOnly ();
        gbSearch.DEBUGnodeArray();

        /*
         * foreach (DLPSpaceState state in db.GoalStates ()) {
         *      DumpOperatorChain (state);
         * }
         */
    }
Exemplo n.º 11
0
    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);
    }
    /** Try to find a winning threat sequence by dependency based search and
     * on the fly refutation for goal nodes.
     *
     * Return early, as soon as a sure candidate has been found.
     *
     * @param timeoutMS If non-zero, a maximum time spend in db-search is
     * given in milliseconds.  At least 1000 (1s) is meaningful to do
     * something, though.
     *
     * @returns The first winning threat sequence on success, null otherwise.
     */
    public GBThreatSequence FindWinningThreatSeqOTF(int timeoutMS)
    {
        // First find a number of possibly winning threat trees.
        GBSearchModule gbSearch = new GBSearchModule (GoBangBoard.boardDim);
        GBSpaceState rootState = new GBSpaceState ((GoBangBoard) gb.Clone ());
        rootState.UpdateIsGoal (gbSearch);

        // HEURISTIC: use category reduction (page 140-141)
        // FIXME: re-enable as soon as three3 bug is fixed.
        // FIXME: test if this is good in the real ai, otherwise disable again.
        //gbSearch.categoryReductionHeuristicOn = true;

        // Do on-the-fly refutation checking.
        gbSearch.doDefenseRefutationCheck = true;

        if (timeoutMS != 0) {
            gbSearch.doExpirationCheck = true;
            gbSearch.expireTime = DateTime.Now.AddMilliseconds (timeoutMS);
        }

        DBSearch db = new DBSearch (gbSearch, breadthFirst);

        try {
            Console.WriteLine ("Board:\n{0}\n", gb);
            db.Search (rootState);
            //db.DumpDOT ();
        } catch (GBSearchModule.GBSearchTimeoutException) {
            // We timed out...
            Console.WriteLine ("FindWinningThreatSeqOTF: timeouted...");
        } catch (GBWinningThreatSequenceFoundException gex) {
            //db.DumpDOT ();
            return (gex.seq);
        }

        return (null);
    }
    // Global function
    public GBThreatSequence FindWinningThreatSeq()
    {
        // First find a number of possibly winning threat trees.
        GBSearchModule gbSearch = new GBSearchModule (GoBangBoard.boardDim);
        GBSpaceState rootState = new GBSpaceState ((GoBangBoard) gb.Clone ());
        rootState.UpdateIsGoal (gbSearch);

        // HEURISTIC: use category reduction (page 140-141)
        gbSearch.categoryReductionHeuristicOn = true;

        DBSearch db = new DBSearch (gbSearch, breadthFirst);
        db.Search (rootState);
        //db.DumpDOTGoalsOnly ();

        // Now, enumerate all the possibly winning threat trees found
        GBThreatSequence[] potentialWinningSeqs =
            GBThreatSequence.BuildAllGoalPathes (gbSearch, db.Root);
        Console.WriteLine ("{0} potential winning threat sequences.",
            potentialWinningSeqs.Length);

        // Check them one by one until a surely winning threat tree is found
        GoBangBoard gbFlipped = (GoBangBoard) gb.Clone ();
        gbFlipped.Flip ();

        int DEBUGwinningFound = 0;
        GBThreatSequence DEBUGwinning = null;

        foreach (GBThreatSequence threatSeq in potentialWinningSeqs) {
            if (DefenseRefutes (threatSeq,
                (GoBangBoard) gbFlipped.Clone ()) < 0)
            {
                // Found a sure win, return early
                // FIXME: for debugging we count all winning sequences found,
                // but we should return as early as possible.
                DEBUGwinningFound += 1;
                DEBUGwinning = threatSeq;
                //Console.WriteLine ("WINNING:\n{0}", threatSeq);
                // FIXME
                //return (threatSeq);
            }
        }

        Console.WriteLine ("{0} winning of {1} potential winning threat sequences identified",
            DEBUGwinningFound, potentialWinningSeqs.Length);

        // Found no unrefuted threat sequence
        return (DEBUGwinning);
    }
    private static int DefenseRefutes(GBThreatSequence seq, GoBangBoard curBoard,
		int depth)
    {
        // If either we reached the end of the sequence (seq is null) or we
        // have a class zero threat, we consider the sequence to be
        // un-refutable and return a negative number.
        if (seq == null || seq.attackerThreatClass == 0)
            return (-1);

        // Make the attackers move (with -1 now, as the board is flipped)
        curBoard.board[seq.attacker.Y, seq.attacker.X] = -1;
        /*Console.WriteLine ("move at ({0},{1})",
            "abcdefghijklmnopqrstuvwxyz"[seq.attacker.X], seq.attacker.Y);

        Console.WriteLine ("DEFENSE board is:\n{0}", curBoard);
        Console.WriteLine ("   attacker threats with {0}", seq.attackerThreatClass);*/

        // Now search for possibly winning threat sequences that cover the
        // goals.  To do this, first build the goalsquares
        int[,] extraGoalSquares = ExtraGoalSquares (seq);

        // TODO
        GBSpaceState rootState =
            new GBSpaceState ((GoBangBoard) curBoard.Clone (),
                seq.attackerThreatClass);

        GBSearchModule gbSearch = new GBSearchModule (GoBangBoard.boardDim);

        // Extra constraints (page 137)
        //
        // 1. "The goal set U_g for player B should be extended with singleton
        // goals for occupying any square in threat a_j or reply d_j with j
        // \geq i."
        //
        // 2. "If B find a potential winning threat sequence, ... this threat
        // sequence is not investigated for counter play of player A.  Instead
        // in such a case we always assume that A's potential winning threat
        // sequence has been refuted."
        //
        // 3. "Thus in a db-search for player B, only threats having replies
        // consisting of a single move are applied."
        gbSearch.goalIfOccupied = extraGoalSquares;
        gbSearch.OneGoalStopsSearch = true;
        gbSearch.maximumCategory = seq.attackerThreatClass - 1;
        //Console.WriteLine ("       maxCat = {0}", gbSearch.maximumCategory);

        // Limit the root node's legal operators to only the one with the
        // appropiate category below the maximum one.  Disable the category
        // reduction heuristics, as we do the exhaustive defense search.
        rootState.UpdateLegalOperators (gbSearch.maximumCategory, false);

        // Do the db-search for the defender
        DBSearch db = new DBSearch (gbSearch, false);
        db.Search (rootState);
        if (db.GoalCount > 0) {
            /*
            Console.WriteLine ("Threat below class {0} or goal square occupied.",
                gbSearch.maximumCategory);
            db.DumpDOT ();
            Console.ReadLine ();*/

            return (depth);
        }

        /*Console.WriteLine ("No class {0} or below threats for the defender found yet",
            gbSearch.maximumCategory);*/

        // Make defenders move (now attacker 1, with advantage)
        foreach (GBMove defMove in seq.defender)
            curBoard.board[defMove.Y, defMove.X] = 1;
        //Console.WriteLine ("BOARD:\n{0}", curBoard);

        return (DefenseRefutes (seq.next, curBoard, depth+1));
    }
Exemplo n.º 15
0
    private static int DefenseRefutes(GBThreatSequence seq, GoBangBoard curBoard,
                                      int depth)
    {
        // If either we reached the end of the sequence (seq is null) or we
        // have a class zero threat, we consider the sequence to be
        // un-refutable and return a negative number.
        if (seq == null || seq.attackerThreatClass == 0)
        {
            return(-1);
        }

        // Make the attackers move (with -1 now, as the board is flipped)
        curBoard.board[seq.attacker.Y, seq.attacker.X] = -1;

        /*Console.WriteLine ("move at ({0},{1})",
         *      "abcdefghijklmnopqrstuvwxyz"[seq.attacker.X], seq.attacker.Y);
         *
         * Console.WriteLine ("DEFENSE board is:\n{0}", curBoard);
         * Console.WriteLine ("   attacker threats with {0}", seq.attackerThreatClass);*/

        // Now search for possibly winning threat sequences that cover the
        // goals.  To do this, first build the goalsquares
        int[,] extraGoalSquares = ExtraGoalSquares(seq);

        // TODO
        GBSpaceState rootState =
            new GBSpaceState((GoBangBoard)curBoard.Clone(),
                             seq.attackerThreatClass);

        GBSearchModule gbSearch = new GBSearchModule(GoBangBoard.boardDim);

        // Extra constraints (page 137)
        //
        // 1. "The goal set U_g for player B should be extended with singleton
        // goals for occupying any square in threat a_j or reply d_j with j
        // \geq i."
        //
        // 2. "If B find a potential winning threat sequence, ... this threat
        // sequence is not investigated for counter play of player A.  Instead
        // in such a case we always assume that A's potential winning threat
        // sequence has been refuted."
        //
        // 3. "Thus in a db-search for player B, only threats having replies
        // consisting of a single move are applied."
        gbSearch.goalIfOccupied     = extraGoalSquares;
        gbSearch.OneGoalStopsSearch = true;
        gbSearch.maximumCategory    = seq.attackerThreatClass - 1;
        //Console.WriteLine ("       maxCat = {0}", gbSearch.maximumCategory);

        // Limit the root node's legal operators to only the one with the
        // appropiate category below the maximum one.  Disable the category
        // reduction heuristics, as we do the exhaustive defense search.
        rootState.UpdateLegalOperators(gbSearch.maximumCategory, false);

        // Do the db-search for the defender
        DBSearch db = new DBSearch(gbSearch, false);

        db.Search(rootState);
        if (db.GoalCount > 0)
        {
            /*
             * Console.WriteLine ("Threat below class {0} or goal square occupied.",
             *      gbSearch.maximumCategory);
             * db.DumpDOT ();
             * Console.ReadLine ();*/

            return(depth);
        }

        /*Console.WriteLine ("No class {0} or below threats for the defender found yet",
         *      gbSearch.maximumCategory);*/

        // Make defenders move (now attacker 1, with advantage)
        foreach (GBMove defMove in seq.defender)
        {
            curBoard.board[defMove.Y, defMove.X] = 1;
        }
        //Console.WriteLine ("BOARD:\n{0}", curBoard);

        return(DefenseRefutes(seq.next, curBoard, depth + 1));
    }
    public static GBThreatSequence[] BuildAllGoalPathes(GBSearchModule module,
		DBNode root)
    {
        ArrayList goalpathes = GoalPathes (module, root);
        Console.WriteLine ("I have {0} goal pathes", goalpathes.Count);

        // Create the threat sequences.
        ArrayList threatSeqs = new ArrayList ();

        // Build one individual threat sequence for each goalpath.
        foreach (ArrayList gp in goalpathes) {
            GBThreatSequence ts = BuildThreatSequence (gp);
            threatSeqs.Add (ts);
        }

        // DEBUG output
        Console.WriteLine ("{0} threat seqs lists", threatSeqs.Count);
        int seqNo = 1;
        foreach (GBThreatSequence seqW in threatSeqs) {
            GBThreatSequence seq = seqW;
            Console.WriteLine ();

            Console.WriteLine (((GBSpaceState) root.State).GB);
            Console.WriteLine ();
            Console.WriteLine ("Sequence {0}: ", seqNo);

            int m = 0;
            while (seq != null) {
                Console.WriteLine ("  move{0}: {1}, threat class {2}", m,
                    seq.attacker, seq.attackerThreatClass);
                m += 1;

                foreach (GBMove reply in seq.defender) {
                    Console.WriteLine ("      def-reply{0}: {1}", m, reply);
                    m += 1;
                }

                seq = seq.next;
            }

            seqNo += 1;
        }

        return ((GBThreatSequence[])
            threatSeqs.ToArray (typeof (GBThreatSequence)));
    }
    /** Build a list of goal pathes.
     */
    private static ArrayList GoalPathes(GBSearchModule module, DBNode root)
    {
        ArrayList goalpathes = new ArrayList ();

        GoalPathesI (module, goalpathes, root, new Stack ());

        return (goalpathes);
    }
    private static void GoalPathesI(GBSearchModule module,
		ArrayList goalpathes, DBNode node, Stack path)
    {
        if (node == null)
            return;

        if (module.IsGoal (node.State)) {
            ArrayList newGoalPath = new ArrayList ();

            foreach (DBNode pNode in path)
                newGoalPath.Add (pNode);

            newGoalPath.Reverse ();

            newGoalPath.Add (node);
            goalpathes.Add (newGoalPath);

            return;
        }

        foreach (DBNode child in node.Children) {
            path.Push (node);
            GoalPathesI (module, goalpathes, child, path);
            path.Pop ();
        }
    }