// 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 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 GBOperator[] LegalOperators(GBSpaceState state, int maxCat) { ArrayList opersGoal = new ArrayList(); ArrayList opersFours = new ArrayList(); ArrayList opersThrees = new ArrayList(); // Check G_5 for operators foreach (GoBangBoard.StoneSet ss in state.GB.G5) { if (IsLastOperatorDependent(ss, state.LastOperator) == false) { continue; } GBOperatorFive[] fives = null; if (maxCat >= 0) { fives = GBOperatorFive.GetOperatorsIfValid(ss); } GBOperatorFour[] fours = null; if (maxCat >= 1) { fours = GBOperatorFour.GetOperatorsIfValid(ss); } if (fives != null) { opersGoal.AddRange(fives); } if (fours != null) { opersFours.AddRange(fours); } } bool Three2Applicable = false; if (maxCat >= 2) { // Check G_7 for operators foreach (GoBangBoard.StoneSet ss in state.GB.G7) { if (IsLastOperatorDependent(ss, state.LastOperator) == false) { continue; } /* * Console.Write ("7ss: "); * for (int n = 0 ; n < ss.stones.Length ; ++n) * Console.Write ("{0} ", ss.stones[n] == 1 ? "O" : * (ss.stones[n] == -1 ? "X" : ".")); * Console.WriteLine (); */ GBOperatorThree2[] three2 = GBOperatorThree2.GetOperatorsIfValid(ss); if (three2 != null) { Three2Applicable = true; opersThrees.AddRange(three2); } } } // Check G_6 for operators if (maxCat >= 1) { foreach (GoBangBoard.StoneSet ss in state.GB.G6) { if (IsLastOperatorDependent(ss, state.LastOperator) == false) { continue; } GBOperatorStraightFour[] sfours = null; if (maxCat >= 1) { sfours = GBOperatorStraightFour.GetOperatorsIfValid(ss); } GBOperatorBrokenThree[] bthrees = null; GBOperatorThree3[] three3s = null; if (maxCat >= 2) { bthrees = GBOperatorBrokenThree.GetOperatorsIfValid(ss); } // Heuristic "restricted trees", page 141. // HEURISTIC // FIXME: re-enable this after testing. if (maxCat >= 2 /*&& Three2Applicable == false*/) { three3s = GBOperatorThree3.GetOperatorsIfValid(ss); } if (sfours != null) { opersGoal.AddRange(sfours); } if (bthrees != null) { opersThrees.AddRange(bthrees); } if (three3s != null) { opersThrees.AddRange(three3s); } } } // Order: goal, fours, threes opersGoal.AddRange(opersFours); opersGoal.AddRange(opersThrees); if (opersGoal.Count > 0) { return((GBOperator[])opersGoal.ToArray(typeof(GBOperator))); } return(null); }
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")); }