/** 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); }
// Return the operator's category that is the lowest among the applicable // operators for state. public static int LowestOperatorCategory(GoBangBoard board) { // A maximum, not important, just must be larger than any real // category int max = 99; // Search category 0 and 1 in G_5 foreach (GoBangBoard.StoneSet ss in board.G5) { // There is no category below zero, so we can return early. if (GBOperatorFive.Present(ss)) { return(0); } if (GBOperatorFour.Present(ss)) { max = 1; } } if (max < 99) { return(max); } // Search category 1 and 2 in G_6 foreach (GoBangBoard.StoneSet ss in board.G6) { // If there was no 0/1 before, this is certainly the minimum. if (GBOperatorStraightFour.Present(ss)) { return(1); } if (max > 2 && GBOperatorBrokenThree.Present(ss)) { max = 2; } else if (max > 2 && GBOperatorThree3.Present(ss)) { max = 2; } } if (max < 99) { return(max); } foreach (GoBangBoard.StoneSet ss in board.G7) { if (GBOperatorThree2.Present(ss)) { return(2); } } return(99); }
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); } }
public static void CountStones(GoBangBoard.StoneSet ss, out int white, out int hole) { white = hole = 0; for (int n = 0 ; n < ss.stones.Length ; ++n) { if (ss.stones[n] == 1) white += 1; else if (ss.stones[n] == 0) hole += 1; } }
// 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 void AddExtraStones(GoBangBoard b2) { for (int y = 0; y < boardDim; ++y) { for (int x = 0; x < boardDim; ++x) { if (board[y, x] == 0 && b2.board[y, x] != 0) { board[y, x] = b2.board[y, x]; } } } }
/** Test a potential winning threat sequence for refutability. * * @param curBoard The original board the original attacker db-search was * started with (root.State.GB). * @param root The root node of the search tree. * @param goalnode The new goal node identified by db-search. * * @returns null if the sequence is refutable, otherwise the sequence * itself is returned. */ public static GBThreatSequence DefenseRefutable(GoBangBoard curBoard, DBNode root, DBNode goalnode) { // First create the goal path, that is, all nodes that lie on the // direct child path to the node. ArrayList gp = GBThreatSequence.GoalPath(root, goalnode); // Check if there is a clear refutable path node in the path and // return early if this is the case. //Console.WriteLine ("Path:"); foreach (DBNode gpN in gp) { //Console.WriteLine (" {0}", gpN); if (gpN.IsRefutePathRoot) { //Console.WriteLine ("DEBUG: node in refutepath"); return(null); } } // Now combine the operators and build a one-by-one threat sequence. GBThreatSequence seq = GBThreatSequence.BuildThreatSequence(gp); // Clone and flip board GoBangBoard gbFlipped = (GoBangBoard)curBoard.Clone(); gbFlipped.Flip(); Console.Write(" checking potential {0} pair-move sequence: ", gp.Count); Console.Out.Flush(); int refutes = DefenseRefutes(seq, gbFlipped); if (refutes < 0) { Console.WriteLine("un-refutable"); return(seq); } Console.WriteLine("refutable at pair-move {0}", refutes); // Mark root of refutation if (refutes < (gp.Count - 1)) { DBNode refutePathRoot = (DBNode)gp[refutes + 1]; refutePathRoot.IsRefutePathRoot = true; } return(null); }
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); }
// Check if there are no conflicting stones. public bool CompatibleWith(GoBangBoard b2) { for (int y = 0; y < boardDim; ++y) { for (int x = 0; x < boardDim; ++x) { if (board[y, x] == 0 || b2.board[y, x] == 0 || board[y, x] == b2.board[y, x]) { continue; } return(false); } } return(true); }
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); }
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); }
public int CompareTo(object o2) { GoBangBoard gb2 = (GoBangBoard)o2; for (int y = 0; y < boardDim; ++y) { for (int x = 0; x < boardDim; ++x) { if (board[y, x] < gb2.board[y, x]) { return(-1); } else if (board[y, x] > gb2.board[y, x]) { return(1); } } } return(0); }
public GBSpaceState(GoBangBoard gb) : this(gb, null, null, 2) { }
public GBThreatSearch(GoBangBoard gb, bool breadthFirst) { this.gb = gb; this.breadthFirst = breadthFirst; }
public static bool Present(GoBangBoard.StoneSet ss) { // The pattern is .????. with "." position fixed. if (ss.stones[0] != 0 || ss.stones[5] != 0) return (false); // Now the middle three (index 2, 3, 4, 5) have to be tested, there // should only be two white stones. int countWhite = 0; int countHole = 0; CountStones (ss, out countWhite, out countHole); if (countWhite != 2 || countHole != 4) return (false); // Now, the broken three condition: "s_4 neither minimum nor maximum // in { s_2, s_3, s_4, s_5 }", where s_4 = s_5 = ., s_2 = s_3 = o. // // This is a bit ambiguous, because it does not say anything else // about the other values s_2, s_3, s_5. // Case 1: .o..o. if (ss.stones[2] == 0 && ss.stones[3] == 0) return (true); // Case 2: .o.o.. if (ss.stones[2] == 0 && ss.stones[4] == 0) return (true); // Case 3: ..o.o. if (ss.stones[1] == 0 && ss.stones[3] == 0) return (true); // Case 4: .oo... and ...oo. if ((ss.stones[1] == 1 && ss.stones[2] == 1) || (ss.stones[3] == 1 && ss.stones[4] == 1)) return (true); return (false); }
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 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); }
public void CombineCheck(ArrayList[,] affect) { int patternG5 = 0; GoBangBoard board = new GoBangBoard(); ArrayList[] affecting = new ArrayList[5]; foreach (GoBangBoard.StoneSet ss in board.G5) { for (int n = 0; n < ss.stones.Length; ++n) { affecting[n] = affect[ss.y + n * ss.ay, ss.x + n * ss.ax]; } // Now in positions we have 'oneBits' number of positions. CheckC2(affecting); #if false // Do a pre-filtering of sensible patterns in this G_5 bool[] fivePatterns = new bool[1 << 5]; for (int p = 0; p < fivePatterns.Length; ++p) { fivePatterns[p] = false; for (int n = 0; n < 5; ++n) { ss.stones[n] = (p & (1 << n)) == 0 ? 0 : 1; if (ss.stones[n] == 1 && affecting[n].Count == 0) { goto nextPattern; } } /* * Console.Write ("A pattern {0}: ", p); * for (int n = 0 ; n < 5 ; ++n) * Console.Write ("{0}", ss.stones[n] == 1 ? "O" : "."); * Console.WriteLine (); */ GBOperatorFive[] fiveP = GBOperatorFive.GetOperatorsIfValid(ss); GBOperatorFour[] fourP = GBOperatorFour.GetOperatorsIfValid(ss); /* * Console.WriteLine (" pattern {0}: {1} fives, {2} fours", p, * (fiveP == null) ? "-" : String.Format ("{0}", fiveP.Length), * (fourP == null) ? "-" : String.Format ("{0}", fourP.Length)); */ // Only if we trigger a pattern, we mark it for later action. if ((fiveP != null && fiveP.Length > 0) || (fourP != null && fourP.Length > 0)) { fivePatterns[p] = true; //Console.WriteLine (" pattern {0} OK", p); } nextPattern: ; } for (int p = 0; p < fivePatterns.Length; ++p) { if (fivePatterns[p] == false) { continue; } // Now examine the pattern really. Console.WriteLine("pattern {0} success", p); Console.WriteLine(" a[0 to 4]: {0}, {1}, {2}, {3}, {4}", affecting[0].Count, affecting[1].Count, affecting[2].Count, affecting[3].Count, affecting[4].Count); patternG5 += 1; // TODO // Now we have an array of list of affecting moves plus a // pattern they may trigger. We know that those moves in the // same array element are conflicting, so we do not need to // check those. Also, we know the new operators are // independent of exchange of operators (commutative), so we // must only check each combination once, regardless of the // order. int oneBits = 0; for (int n = 0; n < 5; ++n) { if ((p & (1 << n)) != 0) { oneBits += 1; } } int[] positions = new int[oneBits]; int oneBitPos = 0; for (int n = 0; n < 5; ++n) { if ((p & (1 << n)) == 0) { continue; } positions[oneBitPos] = n; oneBitPos += 1; } } #endif } //Console.WriteLine ("G5 patterns: {0}", patternG5); }
public static void Main(string[] args) { 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; */ /* // Testcase A gb.board[4,9] = gb.board[5,6] = gb.board[6,8] = 1; gb.board[7,7] = gb.board[8,6] = gb.board[9,5] = gb.board[9,6] = 1; gb.board[9,9] = gb.board[10,11] = 1; gb.board[5,9] = gb.board[5,10] = -1; gb.board[6,7] = gb.board[6,9] = -1; gb.board[7,8] = gb.board[7,9] = gb.board[8,9] = -1; gb.board[9,10] = gb.board[10,4] = -1; */ /* // Testcase B gb.board[5,5] = gb.board[4,6] = gb.board[7,5] = gb.board[7,6] = 1; gb.board[5,6] = gb.board[6,6] = -1; */ /* gb.board[5,6] = gb.board[8,6] = gb.board[9,6] = 1; */ /* // FIXME: this sequence is not found as un-refutable, while it is in // fact (magic case, we know exactly what it is caused by and this is // unlikely to appear in a real game and difficult to fix (though // possible)) // 138, figure 5.5 gb.board[0,0] = gb.board[1,1] = gb.board[2,2] = gb.board[5,13] = -1; gb.board[6,9] = gb.board[7,7] = gb.board[7,8] = -1; gb.board[8,6] = gb.board[8,12] = -1; gb.board[10,7] = gb.board[10,9] = -1; gb.board[10,2] = gb.board[11,1] = gb.board[12,0] = -1; gb.board[2,12] = gb.board[3,12] = 1; gb.board[6,6] = gb.board[6,7] = gb.board[7,6] = gb.board[7,10] = 1; gb.board[8,8] = gb.board[8,11] = gb.board[9,8] = 1; */ // 127b gb.board[5,6] = gb.board[6,9] = gb.board[7,7] = gb.board[8,8] = 1; gb.board[8,9] = 1; gb.board[6,6] = gb.board[6,8] = gb.board[7,6] = gb.board[7,10] = -1; gb.board[8,6] = -1; /* // 127a 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; */ Console.WriteLine ("Starting winning threat sequence search..."); GBThreatSearch gts = new GBThreatSearch (gb, false); GBThreatSequence seq = gts.FindWinningThreatSeqOTF (); if (seq != null) { Console.WriteLine ("Board:"); Console.WriteLine (gb); Console.WriteLine (); Console.WriteLine ("winning threat sequence found:"); Console.WriteLine (seq); } GBThreatSearch gts2 = new GBThreatSearch (gb, true); GBThreatSequence seq2 = gts2.FindWinningThreatSeqOTF (); if (seq2 != null) { Console.WriteLine ("Board:"); Console.WriteLine (gb); Console.WriteLine (); Console.WriteLine ("winning threat sequence found:"); Console.WriteLine (seq2); } }
public static GBOperatorThree2[] GetOperatorsIfValid(GoBangBoard.StoneSet ss) { if (Present (ss) == false) return (null); // Operator is valid, lets produce it (only one variant) GBOperatorThree2 three2 = new GBOperatorThree2 (); three2.fAdd = new int[3,3]; for (int n = 2 ; n < (ss.stones.Length - 2) ; ++n) { if (ss.stones[n] != 0) continue; three2.fAdd[0,0] = ss.x + n*ss.ax; three2.fAdd[0,1] = ss.y + n*ss.ay; three2.fAdd[0,2] = 1; } // Two defending moves (s_2 and s_6, index 1 and 5) three2.fAdd[1,0] = ss.x + 1*ss.ax; three2.fAdd[1,1] = ss.y + 1*ss.ay; three2.fAdd[1,2] = -1; three2.fAdd[2,0] = ss.x + 5*ss.ax; three2.fAdd[2,1] = ss.y + 5*ss.ay; three2.fAdd[2,2] = -1; return (new GBOperatorThree2[] { three2 }); }
public static bool Present(GoBangBoard.StoneSet ss) { /*Console.Write ("three ({0},{1}): ", ss.x, ss.y); foreach (int a in ss.stones) Console.Write ("{0}", a == 1 ? "O" : (a == 0 ? "." : "X")); Console.WriteLine ();*/ // The pattern is ..???.., with "." position fixed, so we can // early-check on this now. if (ss.stones[0] != 0 || ss.stones[1] != 0 || ss.stones[5] != 0 || ss.stones[6] != 0) return (false); // Now the middle three (index 2, 3, 4) have to be tested int countWhite = 0; int countHole = 0; CountStones (ss, out countWhite, out countHole); if (countWhite != 2 || countHole != 5) { return (false); } return (true); }
public static GBOperatorStraightFour[] GetOperatorsIfValid(GoBangBoard.StoneSet ss) { if (Present (ss) == false) return (null); // Operator is valid, lets produce it (only one variant) GBOperatorStraightFour sfour = new GBOperatorStraightFour (); sfour.fAdd = new int[1,3]; for (int n = 1 ; n < (ss.stones.Length - 1) ; ++n) { if (ss.stones[n] != 0) continue; sfour.fAdd[0,0] = ss.x + n*ss.ax; sfour.fAdd[0,1] = ss.y + n*ss.ay; sfour.fAdd[0,2] = 1; } return (new GBOperatorStraightFour[] { sfour }); }
public static bool Present(GoBangBoard.StoneSet ss) { // The pattern is .????. with "." position fixed. if (ss.stones[0] != 0 || ss.stones[5] != 0) return (false); // Now the middle three (index 2, 3, 4) have to be tested int countWhite = 0; int countHole = 0; CountStones (ss, out countWhite, out countHole); if (countWhite != 3 || countHole != 3) return (false); return (true); }
public static bool Present(GoBangBoard.StoneSet ss) { int countWhite = 0; int countHole = 0; CountStones (ss, out countWhite, out countHole); if (countWhite != 3 || countHole != 2) return (false); return (true); }
public static GBOperatorFour[] GetOperatorsIfValid(GoBangBoard.StoneSet ss) { if (Present (ss) == false) return (null); // Operator is valid, lets apply two variations GBOperatorFour four1 = new GBOperatorFour (); GBOperatorFour four2 = new GBOperatorFour (); four1.fAdd = new int[2,3]; four2.fAdd = new int[2,3]; int hole = 0; for (int n = 0 ; n < ss.stones.Length ; ++n) { if (ss.stones[n] != 0) continue; four2.fAdd[hole,0] = four1.fAdd[hole,0] = ss.x + n*ss.ax; four2.fAdd[hole,1] = four1.fAdd[hole,1] = ss.y + n*ss.ay; if (hole == 0) { four1.fAdd[0,2] = 1; four2.fAdd[0,2] = -1; hole += 1; } else { four1.fAdd[1,2] = -1; four2.fAdd[1,2] = 1; } } return (new GBOperatorFour[] { four1, four2 }); }
public static GBOperatorFive[] GetOperatorsIfValid(GoBangBoard.StoneSet ss) { if (Present (ss) == false) return (null); // Operator is valid, lets apply it. GBOperatorFive five = new GBOperatorFive (); five.fAdd = new int[1,3]; for (int n = 0 ; n < ss.stones.Length ; ++n) { if (ss.stones[n] != 0) continue; five.fAdd[0,0] = ss.x + n*ss.ax; five.fAdd[0,1] = ss.y + n*ss.ay; five.fAdd[0,2] = 1; } return (new GBOperatorFive[] { five }); }
public GBSpaceState(GoBangBoard gb, GBOperator lastOperator, GBSpaceState lastState, int maxCat) : this(gb, lastOperator, lastState, null) { this.legalOperators = GBOperator.LegalOperators(this, maxCat); }
public static GBOperatorThree3[] GetOperatorsIfValid(GoBangBoard.StoneSet ss) { if (Present (ss) == false) return (null); // Case A: ..oo.. if (ss.stones[1] == 0 && ss.stones[4] == 0) { // Operator is valid, lets produce it (two variants) GBOperatorThree3 three31 = new GBOperatorThree3 (); GBOperatorThree3 three32 = new GBOperatorThree3 (); three31.fAdd = new int[4,3]; three32.fAdd = new int[4,3]; int hole = 0; for (int n = 1 ; n < (ss.stones.Length-1) ; ++n) { if (ss.stones[n] != 0) continue; three31.fAdd[hole,0] = three32.fAdd[hole,0] = ss.x + n*ss.ax; three31.fAdd[hole,1] = three32.fAdd[hole,1] = ss.y + n*ss.ay; if (hole == 0) { three31.fAdd[0,2] = 1; three32.fAdd[0,2] = -1; hole += 1; } else { three31.fAdd[1,2] = -1; three32.fAdd[1,2] = 1; } } // Two defending moves (s_1 and s_6, index 0 and 5) three31.fAdd[2,0] = three32.fAdd[2,0] = ss.x; three31.fAdd[2,1] = three32.fAdd[2,1] = ss.y; three31.fAdd[2,2] = three32.fAdd[2,2] = -1; three31.fAdd[3,0] = three32.fAdd[3,0] = ss.x + 5*ss.ax; three31.fAdd[3,1] = three32.fAdd[3,1] = ss.y + 5*ss.ay; three31.fAdd[3,2] = three32.fAdd[3,2] = -1; return (new GBOperatorThree3[] { three31, three32 }); } else if ((ss.stones[2] == 0 && ss.stones[4] == 0) || (ss.stones[1] == 0 && ss.stones[3] == 0)) { // Case B & C: .o.o.. and ..o.o. // TODO GBOperatorThree3 three3 = new GBOperatorThree3 (); three3.fAdd = new int[4,3]; int stoneCount = 0; int pCell = 0; for (int n = 1 ; n < (ss.stones.Length-1) ; ++n) { if (ss.stones[n] != 0) { stoneCount += 1; continue; } three3.fAdd[pCell,0] = ss.x + n*ss.ax; three3.fAdd[pCell,1] = ss.y + n*ss.ay; if (stoneCount == 1) { three3.fAdd[pCell,2] = 1; } else three3.fAdd[pCell,2] = -1; pCell += 1; } // Two defending moves (s_1 and s_6, index 0 and 5) three3.fAdd[2,0] = ss.x; three3.fAdd[2,1] = ss.y; three3.fAdd[2,2] = -1; three3.fAdd[3,0] = ss.x + 5*ss.ax; three3.fAdd[3,1] = ss.y + 5*ss.ay; three3.fAdd[3,2] = -1; return (new GBOperatorThree3[] { three3, }); } else if (ss.stones[3] == 0 && ss.stones[4] == 0) { // Case D: .oo... GBOperatorThree3 three3 = new GBOperatorThree3 (); three3.fAdd = new int[4,3]; three3.fAdd[0,0] = ss.x + 3*ss.ax; three3.fAdd[0,1] = ss.y + 3*ss.ay; three3.fAdd[0,2] = 1; three3.fAdd[1,0] = ss.x + 4*ss.ax; three3.fAdd[1,1] = ss.y + 4*ss.ay; three3.fAdd[1,2] = -1; // Two defending moves (s_1 and s_6, index 0 and 5) three3.fAdd[2,0] = ss.x; three3.fAdd[2,1] = ss.y; three3.fAdd[2,2] = -1; three3.fAdd[3,0] = ss.x + 5*ss.ax; three3.fAdd[3,1] = ss.y + 5*ss.ay; three3.fAdd[3,2] = -1; return (new GBOperatorThree3[] { three3, }); } else if (ss.stones[1] == 0 && ss.stones[2] == 0) { // Case E: ...oo. GBOperatorThree3 three3 = new GBOperatorThree3 (); three3.fAdd = new int[4,3]; three3.fAdd[0,0] = ss.x + 2*ss.ax; three3.fAdd[0,1] = ss.y + 2*ss.ay; three3.fAdd[0,2] = 1; three3.fAdd[1,0] = ss.x + 1*ss.ax; three3.fAdd[1,1] = ss.y + 1*ss.ay; three3.fAdd[1,2] = -1; // Two defending moves (s_1 and s_6, index 0 and 5) three3.fAdd[2,0] = ss.x; three3.fAdd[2,1] = ss.y; three3.fAdd[2,2] = -1; three3.fAdd[3,0] = ss.x + 5*ss.ax; three3.fAdd[3,1] = ss.y + 5*ss.ay; three3.fAdd[3,2] = -1; return (new GBOperatorThree3[] { three3, }); } else { throw (new ApplicationException ("BUG in Three3, uncatched case")); } }
public static GBOperatorBrokenThree[] GetOperatorsIfValid(GoBangBoard.StoneSet ss) { if (Present (ss) == false) return (null); // Case 1 if (ss.stones[2] == 0 && ss.stones[3] == 0) { // Operator is valid, lets produce it (two variants) GBOperatorBrokenThree bthree1 = new GBOperatorBrokenThree (); GBOperatorBrokenThree bthree2 = new GBOperatorBrokenThree (); bthree1.fAdd = new int[4,3]; bthree2.fAdd = new int[4,3]; int hole = 0; for (int n = 1 ; n < (ss.stones.Length-1) ; ++n) { if (ss.stones[n] != 0) continue; bthree1.fAdd[hole,0] = bthree2.fAdd[hole,0] = ss.x + n*ss.ax; bthree1.fAdd[hole,1] = bthree2.fAdd[hole,1] = ss.y + n*ss.ay; if (hole == 0) { bthree1.fAdd[0,2] = 1; bthree2.fAdd[0,2] = -1; hole += 1; } else { bthree1.fAdd[1,2] = -1; bthree2.fAdd[1,2] = 1; } } // Two defending moves (s_1 and s_6, index 0 and 5) bthree1.fAdd[2,0] = bthree2.fAdd[2,0] = ss.x; bthree1.fAdd[2,1] = bthree2.fAdd[2,1] = ss.y; bthree1.fAdd[2,2] = bthree2.fAdd[2,2] = -1; bthree1.fAdd[3,0] = bthree2.fAdd[3,0] = ss.x + 5*ss.ax; bthree1.fAdd[3,1] = bthree2.fAdd[3,1] = ss.y + 5*ss.ay; bthree1.fAdd[3,2] = bthree2.fAdd[3,2] = -1; return (new GBOperatorBrokenThree[] { bthree1, bthree2 }); } // Case 4: // .oo... if (ss.stones[1] == 1 && ss.stones[2] == 1) { GBOperatorBrokenThree bthree = new GBOperatorBrokenThree (); bthree.fAdd = new int[4,3]; bthree.fAdd[0,0] = ss.x + 0*ss.ax; bthree.fAdd[0,1] = ss.y + 0*ss.ay; bthree.fAdd[0,2] = -1; bthree.fAdd[1,0] = ss.x + 5*ss.ax; bthree.fAdd[1,1] = ss.y + 5*ss.ay; bthree.fAdd[1,2] = -1; bthree.fAdd[2,0] = ss.x + 3*ss.ax; bthree.fAdd[2,1] = ss.y + 3*ss.ay; bthree.fAdd[2,2] = -1; bthree.fAdd[3,0] = ss.x + 4*ss.ax; bthree.fAdd[3,1] = ss.y + 4*ss.ay; bthree.fAdd[3,2] = 1; return (new GBOperatorBrokenThree[] { bthree }); } else if (ss.stones[3] == 1 && ss.stones[4] == 1) { // and ...oo. GBOperatorBrokenThree bthree = new GBOperatorBrokenThree (); bthree.fAdd = new int[4,3]; bthree.fAdd[0,0] = ss.x + 0*ss.ax; bthree.fAdd[0,1] = ss.y + 0*ss.ay; bthree.fAdd[0,2] = -1; bthree.fAdd[1,0] = ss.x + 5*ss.ax; bthree.fAdd[1,1] = ss.y + 5*ss.ay; bthree.fAdd[1,2] = -1; bthree.fAdd[2,0] = ss.x + 2*ss.ax; bthree.fAdd[2,1] = ss.y + 2*ss.ay; bthree.fAdd[2,2] = -1; bthree.fAdd[3,0] = ss.x + 1*ss.ax; bthree.fAdd[3,1] = ss.y + 1*ss.ay; bthree.fAdd[3,2] = 1; return (new GBOperatorBrokenThree[] { bthree }); } // Case 2 and 3 // // Only one variation exist: // .o.o.. or ..o.o. // xoxoox xooxox if ((ss.stones[1] == 1 && ss.stones[3] == 1) || (ss.stones[2] == 1 && ss.stones[4] == 1)) { GBOperatorBrokenThree bthree = new GBOperatorBrokenThree (); bthree.fAdd = new int[4,3]; int posCount = 0; int pFillC = 0; for (int n = 1 ; n < (ss.stones.Length-1) ; ++n) { if (ss.stones[n] == 1) { posCount += 1; continue; } // Free stone // Case A: middle, fill with oponent if (posCount == 1) { bthree.fAdd[pFillC,0] = ss.x + n*ss.ax; bthree.fAdd[pFillC,1] = ss.y + n*ss.ay; bthree.fAdd[pFillC,2] = -1; pFillC += 1; } else { // Case B: not the middle, fill with our own bthree.fAdd[pFillC,0] = ss.x + n*ss.ax; bthree.fAdd[pFillC,1] = ss.y + n*ss.ay; bthree.fAdd[pFillC,2] = 1; pFillC += 1; } } // The two corner stones: x....x bthree.fAdd[2,0] = ss.x; bthree.fAdd[2,1] = ss.y; bthree.fAdd[2,2] = -1; bthree.fAdd[3,0] = ss.x + 5*ss.ax; bthree.fAdd[3,1] = ss.y + 5*ss.ay; bthree.fAdd[3,2] = -1; return (new GBOperatorBrokenThree[] { bthree, }); } throw (new ApplicationException ("Broken three: impossible case")); }
public static bool Present(GoBangBoard.StoneSet ss) { // The pattern is .????. with "." position fixed. if (ss.stones[0] != 0 || ss.stones[5] != 0) return (false); // Now the middle three (index 2, 3, 4, 5) have to be tested, there // should only be two white stones. int countWhite = 0; int countHole = 0; CountStones (ss, out countWhite, out countHole); if (countWhite != 2 || countHole != 4) return (false); // The "three with 3 reply moves" condition: "s_2 either minimum or // maximum in { s_2, s_3, s_4, s_5 }". // // This is a bit ambiguous, because it does not say anything else // about the other values s_3, s_4, s_5. // // This most likely means that there should not be two empty stones in // the middle: .o..o., but it must be either .oo..., ...oo., .o.o.., // ..o.o. or ..oo.. if (ss.stones[2] == 0 && ss.stones[3] == 0) return (false); return (true); }
/** Test a potential winning threat sequence for refutability. * * @param curBoard The original board the original attacker db-search was * started with (root.State.GB). * @param root The root node of the search tree. * @param goalnode The new goal node identified by db-search. * * @returns null if the sequence is refutable, otherwise the sequence * itself is returned. */ public static GBThreatSequence DefenseRefutable(GoBangBoard curBoard, DBNode root, DBNode goalnode) { // First create the goal path, that is, all nodes that lie on the // direct child path to the node. ArrayList gp = GBThreatSequence.GoalPath (root, goalnode); // Check if there is a clear refutable path node in the path and // return early if this is the case. //Console.WriteLine ("Path:"); foreach (DBNode gpN in gp) { //Console.WriteLine (" {0}", gpN); if (gpN.IsRefutePathRoot) { //Console.WriteLine ("DEBUG: node in refutepath"); return (null); } } // Now combine the operators and build a one-by-one threat sequence. GBThreatSequence seq = GBThreatSequence.BuildThreatSequence (gp); // Clone and flip board GoBangBoard gbFlipped = (GoBangBoard) curBoard.Clone (); gbFlipped.Flip (); Console.Write (" checking potential {0} pair-move sequence: ", gp.Count); Console.Out.Flush (); int refutes = DefenseRefutes (seq, gbFlipped); if (refutes < 0) { Console.WriteLine ("un-refutable"); return (seq); } Console.WriteLine ("refutable at pair-move {0}", refutes); // Mark root of refutation if (refutes < (gp.Count-1)) { DBNode refutePathRoot = (DBNode) gp[refutes+1]; refutePathRoot.IsRefutePathRoot = true; } return (null); }
public object Clone() { GoBangBoard gbNew = new GoBangBoard((int[, ])board.Clone()); return(gbNew); }
/** Check for refutability. * * @param seq The potential winning threat sequence to be checked. * @param curBoard The current board against which the sequence shall be * checked. * * @returns Negative value if the sequence is not refutable, otherwise the * value returned is the refutation depth. */ private static int DefenseRefutes(GBThreatSequence seq, GoBangBoard curBoard) { return (DefenseRefutes (seq, curBoard, 0)); }
public GCl(GoBangBoard gb, int gSize) { this.gb = gb; this.gSize = gSize; }
/** Check for refutability. * * @param seq The potential winning threat sequence to be checked. * @param curBoard The current board against which the sequence shall be * checked. * * @returns Negative value if the sequence is not refutable, otherwise the * value returned is the refutation depth. */ private static int DefenseRefutes(GBThreatSequence seq, GoBangBoard curBoard) { return(DefenseRefutes(seq, curBoard, 0)); }
public static void Main(string[] args) { 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; */ /* * // Testcase A * gb.board[4,9] = gb.board[5,6] = gb.board[6,8] = 1; * gb.board[7,7] = gb.board[8,6] = gb.board[9,5] = gb.board[9,6] = 1; * gb.board[9,9] = gb.board[10,11] = 1; * * gb.board[5,9] = gb.board[5,10] = -1; * gb.board[6,7] = gb.board[6,9] = -1; * gb.board[7,8] = gb.board[7,9] = gb.board[8,9] = -1; * gb.board[9,10] = gb.board[10,4] = -1; */ /* * // Testcase B * gb.board[5,5] = gb.board[4,6] = gb.board[7,5] = gb.board[7,6] = 1; * gb.board[5,6] = gb.board[6,6] = -1; */ /* * gb.board[5,6] = gb.board[8,6] = gb.board[9,6] = 1; */ /* * // FIXME: this sequence is not found as un-refutable, while it is in * // fact (magic case, we know exactly what it is caused by and this is * // unlikely to appear in a real game and difficult to fix (though * // possible)) * // 138, figure 5.5 * gb.board[0,0] = gb.board[1,1] = gb.board[2,2] = gb.board[5,13] = -1; * gb.board[6,9] = gb.board[7,7] = gb.board[7,8] = -1; * gb.board[8,6] = gb.board[8,12] = -1; * gb.board[10,7] = gb.board[10,9] = -1; * gb.board[10,2] = gb.board[11,1] = gb.board[12,0] = -1; * * gb.board[2,12] = gb.board[3,12] = 1; * gb.board[6,6] = gb.board[6,7] = gb.board[7,6] = gb.board[7,10] = 1; * gb.board[8,8] = gb.board[8,11] = gb.board[9,8] = 1; */ // 127b gb.board[5, 6] = gb.board[6, 9] = gb.board[7, 7] = gb.board[8, 8] = 1; gb.board[8, 9] = 1; gb.board[6, 6] = gb.board[6, 8] = gb.board[7, 6] = gb.board[7, 10] = -1; gb.board[8, 6] = -1; /* * // 127a * 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; */ Console.WriteLine("Starting winning threat sequence search..."); GBThreatSearch gts = new GBThreatSearch(gb, false); GBThreatSequence seq = gts.FindWinningThreatSeqOTF(); if (seq != null) { Console.WriteLine("Board:"); Console.WriteLine(gb); Console.WriteLine(); Console.WriteLine("winning threat sequence found:"); Console.WriteLine(seq); } GBThreatSearch gts2 = new GBThreatSearch(gb, true); GBThreatSequence seq2 = gts2.FindWinningThreatSeqOTF(); if (seq2 != null) { Console.WriteLine("Board:"); Console.WriteLine(gb); Console.WriteLine(); Console.WriteLine("winning threat sequence found:"); Console.WriteLine(seq2); } }
/** 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); * } */ }
public void CombineCheck(ArrayList[,] affect) { int patternG5 = 0; GoBangBoard board = new GoBangBoard (); ArrayList[] affecting = new ArrayList[5]; foreach (GoBangBoard.StoneSet ss in board.G5) { for (int n = 0 ; n < ss.stones.Length ; ++n) affecting[n] = affect[ss.y + n*ss.ay, ss.x + n*ss.ax]; // Now in positions we have 'oneBits' number of positions. CheckC2 (affecting); #if false // Do a pre-filtering of sensible patterns in this G_5 bool[] fivePatterns = new bool[1 << 5]; for (int p = 0 ; p < fivePatterns.Length ; ++p) { fivePatterns[p] = false; for (int n = 0 ; n < 5 ; ++n) { ss.stones[n] = (p & (1 << n)) == 0 ? 0 : 1; if (ss.stones[n] == 1 && affecting[n].Count == 0) goto nextPattern; } /* Console.Write ("A pattern {0}: ", p); for (int n = 0 ; n < 5 ; ++n) Console.Write ("{0}", ss.stones[n] == 1 ? "O" : "."); Console.WriteLine (); */ GBOperatorFive[] fiveP = GBOperatorFive.GetOperatorsIfValid (ss); GBOperatorFour[] fourP = GBOperatorFour.GetOperatorsIfValid (ss); /* Console.WriteLine (" pattern {0}: {1} fives, {2} fours", p, (fiveP == null) ? "-" : String.Format ("{0}", fiveP.Length), (fourP == null) ? "-" : String.Format ("{0}", fourP.Length)); */ // Only if we trigger a pattern, we mark it for later action. if ((fiveP != null && fiveP.Length > 0) || (fourP != null && fourP.Length > 0)) { fivePatterns[p] = true; //Console.WriteLine (" pattern {0} OK", p); } nextPattern: ; } for (int p = 0 ; p < fivePatterns.Length ; ++p) { if (fivePatterns[p] == false) continue; // Now examine the pattern really. Console.WriteLine ("pattern {0} success", p); Console.WriteLine (" a[0 to 4]: {0}, {1}, {2}, {3}, {4}", affecting[0].Count, affecting[1].Count, affecting[2].Count, affecting[3].Count, affecting[4].Count); patternG5 += 1; // TODO // Now we have an array of list of affecting moves plus a // pattern they may trigger. We know that those moves in the // same array element are conflicting, so we do not need to // check those. Also, we know the new operators are // independent of exchange of operators (commutative), so we // must only check each combination once, regardless of the // order. int oneBits = 0; for (int n = 0 ; n < 5 ; ++n) { if ((p & (1 << n)) != 0) oneBits += 1; } int[] positions = new int[oneBits]; int oneBitPos = 0; for (int n = 0 ; n < 5 ; ++n) { if ((p & (1 << n)) == 0) continue; positions[oneBitPos] = n; oneBitPos += 1; } } #endif } //Console.WriteLine ("G5 patterns: {0}", patternG5); }
// Check if there are no conflicting stones. public bool CompatibleWith(GoBangBoard b2) { for (int y = 0 ; y < boardDim ; ++y) { for (int x = 0 ; x < boardDim ; ++x) { if (board[y,x] == 0 || b2.board[y,x] == 0 || board[y,x] == b2.board[y,x]) continue; return (false); } } return (true); }
/** 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); } */ }
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 object Clone() { GoBangBoard gbNew = new GoBangBoard ((int[,]) board.Clone ()); return (gbNew); }
public void AddExtraStones(GoBangBoard b2) { for (int y = 0 ; y < boardDim ; ++y) { for (int x = 0 ; x < boardDim ; ++x) { if (board[y,x] == 0 && b2.board[y,x] != 0) board[y,x] = b2.board[y,x]; } } }
public GBSpaceState(GoBangBoard gb, int maxCat) : this(gb, null, null, maxCat) { }
public GBSpaceState(GoBangBoard gb, GBOperator lastOperator, GBSpaceState lastState, int maxCat) : this(gb, lastOperator, lastState, null) { this.legalOperators = GBOperator.LegalOperators (this, maxCat); }
public GClEnumerator(GoBangBoard gb, int gSize) { this.gb = gb; this.gSize = gSize; }