public static List <Mill> getMills(int[,] a, int player) { List <Mill> mills = new List <Mill>(); for (int ii = 1; ii < 25; ii++) { for (int jj = ii + 1; jj < 25; jj++) { for (int k = jj + 1; k < 25; k++) { var numbers = new int[] { ii, jj, k }; Array.Sort(numbers); Cell x = new Cell(numbers[0]); Cell y = new Cell(numbers[1]); Cell z = new Cell(numbers[2]); // check if the stones are different, neighbours and on the same row or column if ((k != ii) && (k != jj) && (Cell.neighbour(a, x, y)) && (Cell.neighbour(a, y, z)) && (a[x.i, x.j] == a[y.i, y.j]) && (a[x.i, x.j] == a[z.i, z.j]) && (a[x.i, x.j] == player) && Cell.consecutive(x, y, z)) { Mill m = new Mill(numbers[0], numbers[1], numbers[2]); if (!(mills.Contains(m))) { mills.Add(m); } } } } } return(mills); }
public override bool Equals(Object obj) { if (obj == null || this.GetType() != obj.GetType()) { return(false); } Mill m = (Mill)obj; return((this.start == m.start) && (this.middle == m.middle) && (this.stop == m.stop)); }
public static bool StonesOnlyInMills(int[,] a, int player) { // check if all the player stones from the board are inside mills List <Mill> Mills = Mill.getMills(a, player); HashSet <int> StonesInMills = new HashSet <int>(); foreach (Mill m in Mills) { StonesInMills.Add(m.start); StonesInMills.Add(m.middle); StonesInMills.Add(m.stop); } // if the number of stones from player inside mills is equal to the total number // of stones from player from the board then all the stones from the player are inside mills if (Cell.count(a, player) == StonesInMills.Count) { return(true); } else { return(false); } }
private void moveBlue() { // the blue oponent moves too fast, so a delay is added in order for the human to spot clearly what move has been made var timer = new DispatcherTimer { Interval = TimeSpan.FromSeconds(1) }; timer.Start(); timer.Tick += (sender, args) => { timer.Stop(); warning.Text = ""; warning.Visibility = System.Windows.Visibility.Hidden; int move = 0; // blue opponent's first move is random int i = 1, j = 2, index = 1; if (firstMoveBlue) { while (a[i, j] != 0) { index = rand.Next(1, 25); Cell c = new Cell(index); i = c.i; j = c.j; } a[i, j] = 2; firstMoveBlue = false; drawEllipse(ellipseV[index], 2, blueColor, 35, false); move = index; ballPlayer2 -= 1; } else if (thirdPhaseBlue) { // check if red will soon create a mill List <Cell> incompleteRedMill = Mill.checkDangerMill(a, 1); // check if blue will create soon a mill List <Cell> incompleteBlueMill = Mill.checkDangerMill(a, 2); List <Mill> blueMills = Mill.getMills(a, 2); Cell moved = Mill.getBlueStoneThirdPhase(a); if (incompleteBlueMill.Count != 0) { a[moved.i, moved.j] = 0; drawEllipse(ellipseV[Helper.toIJ(moved.i, moved.j)], 2, yellowColor, 15, false); int ii = incompleteBlueMill[0].i; int jj = incompleteBlueMill[0].j; drawEllipse(ellipseV[Helper.toIJ(ii, jj)], 2, blueColor, 35, false); a[ii, jj] = 2; } else if (incompleteRedMill.Count != 0) { a[moved.i, moved.j] = 0; drawEllipse(ellipseV[Helper.toIJ(moved.i, moved.j)], 2, yellowColor, 15, false); int ii = incompleteRedMill[0].i; int jj = incompleteRedMill[0].j; drawEllipse(ellipseV[Helper.toIJ(ii, jj)], 2, blueColor, 35, false); a[ii, jj] = 2; } else if (blueMills.Count != 0) { Cell x = new Cell(blueMills[0].start); for (int k = 1; k < 25; k++) { Cell n = new Cell(k); if (a[n.i, n.j] == 0) { a[n.i, n.j] = 2; a[x.i, x.j] = 0; drawEllipse(ellipseV[Helper.toIJ(x.i, x.j)], 2, yellowColor, 15, false); drawEllipse(ellipseV[Helper.toIJ(n.i, n.j)], 2, blueColor, 35, false); } } } else { int ct = 0; Cell first = new Cell(0); Cell second = new Cell(0); for (int k = 1; k < 25; k++) { Cell x = new Cell(k); if ((a[x.i, x.j] == 2) && (ct == 0)) { ct++; first = x; } else if ((a[x.i, x.j] == 2) && (ct == 1)) { second = x; a[first.i, first.j] = 0; drawEllipse(ellipseV[Helper.toIJ(first.i, first.j)], 2, yellowColor, 15, false); for (int n = 1; n < 25; n++) { Cell n_c = new Cell(n); if (Cell.neighbour(a, n_c, second) && (a[n_c.i, n_c.j] == 0)) { a[n_c.i, n_c.j] = 2; drawEllipse(ellipseV[Helper.toIJ(n_c.i, n_c.j)], 2, blueColor, 35, false); break; } } } } } } else // if the game is in phase 1 check whether red will soon form a mill (two neighbour red stones) // and whether blue will form soon a mill; // completing blue mill has preference over blocking formation of red mill because after // completing a blue mill, it will remove a red stone that is inside a dangerous/ incomplete red mill) if (ballPlayer2 > 0) { // check if red will soon create a mill List <Cell> incompleteRedMill = Mill.checkDangerMill(a, 1); // check if blue will create soon a mill List <Cell> incompleteBlueMill = Mill.checkDangerMill(a, 2); // try to build blue mill Cell aimBlueMill = Mill.goMill(a); // if no danger of red mill was detected and blue will not create soon a mill if (incompleteRedMill.Count == 0 && incompleteBlueMill.Count == 0) { if (aimBlueMill != null) { a[aimBlueMill.i, aimBlueMill.j] = 2; drawEllipse(ellipseV[Helper.toIJ(aimBlueMill.i, aimBlueMill.j)], 2, blueColor, 35, false); move = Helper.toIJ(aimBlueMill.i, aimBlueMill.j); } else { i = 1; j = 2; index = 1; while (a[i, j] != 0) { index = rand.Next(1, 25); Cell c = new Cell(index); i = c.i; j = c.j; } a[i, j] = 2; drawEllipse(ellipseV[index], 2, blueColor, 35, false); move = index; } } else if ((incompleteRedMill.Count != 0) && (incompleteBlueMill.Count == 0)) { // danger for red to create mill and blue will not create soon a mill // => move blue stone to block red mill a[incompleteRedMill[0].i, incompleteRedMill[0].j] = 2; drawEllipse(ellipseV[Helper.toIJ(incompleteRedMill[0].i, incompleteRedMill[0].j)], 2, blueColor, 35, false); move = Helper.toIJ(incompleteRedMill[0].i, incompleteRedMill[0].j); checkMill(2, ellipseV[Helper.toIJ(incompleteRedMill[0].i, incompleteRedMill[0].j)]); } else if ((incompleteRedMill.Count != 0) && (incompleteBlueMill.Count != 0)) { // danger for red to create mill and blue will create soon a mill // => complete blue mill a[incompleteBlueMill[0].i, incompleteBlueMill[0].j] = 2; drawEllipse(ellipseV[Helper.toIJ(incompleteBlueMill[0].i, incompleteBlueMill[0].j)], 2, blueColor, 35, false); move = Helper.toIJ(incompleteBlueMill[0].i, incompleteBlueMill[0].j); } else { // no danger for red to create mill and blue will create soon a mill a[incompleteBlueMill[0].i, incompleteBlueMill[0].j] = 2; drawEllipse(ellipseV[Helper.toIJ(incompleteBlueMill[0].i, incompleteBlueMill[0].j)], 2, blueColor, 35, false); move = Helper.toIJ(incompleteBlueMill[0].i, incompleteBlueMill[0].j); } ballPlayer2 -= 1; } else if (secondPhase) { List <Cell> blueDangerousMills = Mill.checkDangerMill(a, 2); List <Cell> redDangerousMills = Mill.checkDangerMill(a, 1); List <Mill> blueMills = Mill.getMills(a, 2); bool blueMoved = false; // search through all the blue mills to get a free neighbour position where to move // one of the blue stones from inside the mill (strategy for removing red stones => next move will close back the mill) if (!blueMoved && (!breakMill)) { HashSet <int> blueStones = new HashSet <int>(); foreach (Mill m in blueMills) { blueStones.Add(m.start); blueStones.Add(m.middle); blueStones.Add(m.stop); } if (blueStones.Count != 0) { foreach (int stone in blueStones) { if (!blueMoved) { for (int k = 1; k < 25; k++) { Cell n_k = new Cell(k); Cell n_s = new Cell(stone); if (Cell.neighbour(a, n_k, n_s) && (a[n_k.i, n_k.j] == 0)) { drawEllipse(ellipseV[Helper.toIJ(n_k.i, n_k.j)], 2, blueColor, 35, false); move = Helper.toIJ(n_k.i, n_k.j); drawEllipse(ellipseV[Helper.toIJ(n_s.i, n_s.j)], 2, yellowColor, 15, false); a[n_k.i, n_k.j] = 2; a[n_s.i, n_s.j] = 0; blueMoved = true; breakMill = true; break; } } } else { break; } } } } // try to find an incomplete blue mill and if a blue stone is in the neighbourhood, move it to complete the mill if (!blueMoved && breakMill) { HashSet <int> StonesInMills = new HashSet <int>(); foreach (Mill m in blueMills) { StonesInMills.Add(m.start); StonesInMills.Add(m.middle); StonesInMills.Add(m.stop); } foreach (Cell blue in blueDangerousMills) { for (int k = 1; k < 25; k++) { if (!blueMoved) { Cell n = new Cell(k); if (Cell.neighbour(a, n, blue) && (a[n.i, n.j] == 2) && (!StonesInMills.Contains(k))) { drawEllipse(ellipseV[Helper.toIJ(blue.i, blue.j)], 2, blueColor, 35, false); move = Helper.toIJ(blue.i, blue.j); drawEllipse(ellipseV[Helper.toIJ(n.i, n.j)], 2, yellowColor, 15, false); a[n.i, n.j] = 0; a[blue.i, blue.j] = 2; blueMoved = true; breakMill = false; break; // found a good position to move the blue stone, so stop searching } } else { break; // break from the outer loop after finding a good postion to move } } } } // if the precedent case didn't result in a position where to move the blue stone // then search through all incomplete red mills for a position that has in // the neighbourhood a blue stone and if one is found, move blue stone to block forming a red mill if (!blueMoved) { foreach (Cell red in redDangerousMills) { for (int k = 1; k < 25; k++) { if (!blueMoved) { Cell n = new Cell(k); if (Cell.neighbour(a, n, red) && (a[n.i, n.j] == 2)) { drawEllipse(ellipseV[Helper.toIJ(red.i, red.j)], 2, blueColor, 35, false); move = Helper.toIJ(red.i, red.j); drawEllipse(ellipseV[Helper.toIJ(n.i, n.j)], 2, yellowColor, 15, false); a[n.i, n.j] = 0; a[red.i, red.j] = 2; blueMoved = true; break; } } else { break; } } } } while (!blueMoved) { index = rand.Next(1, 25); for (int k = 1; k < 25; k++) { Cell n_k = new Cell(k); Cell c = new Cell(index); if ((a[c.i, c.j] == 2) && (Cell.neighbour(a, n_k, c)) && (a[n_k.i, n_k.j] == 0)) { a[n_k.i, n_k.j] = 2; a[c.i, c.j] = 0; drawEllipse(ellipseV[k], 2, blueColor, 35, false); drawEllipse(ellipseV[index], 2, yellowColor, 15, false); move = index; blueMoved = true; } } } } Helper.printBoard(a); blueMill = false; checkMill(2, ellipseV[move]); oldBlueMills = bMills.Count; bMills = Mill.getMills(a, 2); newBlueMills = bMills.Count; if (oldBlueMills - newBlueMills == 1) { removedRedStone--; // blue moved so that one mill is broken } if (newBlueMills != removedRedStone) { Cell red = Mill.removeRedStone(a); warning.SetResourceReference(TextBox.TextProperty, "redStoneRemoved"); warning.Visibility = System.Windows.Visibility.Visible; a[red.i, red.j] = 0; Helper.printBoard(a); drawEllipse(ellipseV[Helper.toIJ(red.i, red.j)], 1, yellowColor, 15, false); removedRedStone++; } }; }
private void ellipse_MouseDown(object sender, MouseButtonEventArgs e) { e.Handled = true; selectedNodeEllipse = (Ellipse)sender; Cell currentCell = new Cell((int)selectedNodeEllipse.Tag); checkMill(2, selectedNodeEllipse); // if blue reached phase 3 having only 3 blue stones left, move to form mills or block red mills if ((Cell.count(a, 2) == 3) && (secondPhase)) { thirdPhaseBlue = true; } if ((Cell.count(a, 1) == 3) && (secondPhase)) { thirdPhaseRed = true; } // blue player lost if (secondPhase && ((Cell.count(a, 2) < 3) || (!Mill.playerCanMove(a, 2)))) { gameOver("redWon"); } else // red player lost if (secondPhase && ((Cell.count(a, 1) < 3) || (!Mill.playerCanMove(a, 1)))) { gameOver("blueWon"); } else // if the game reached 70 moves (sum of both players moves) and no player won, it is a draw if (countMoves == 70) { gameOver("draw"); } else // if red formed mill and user clicked on blue stone then remove the blue stone if (redMill && (a[currentCell.i, currentCell.j] == 2)) { // remove blue stone that is not inside a mill or if all the blue stones are inside mills, allow to remove from mill if ((!blueMill) || (blueMill && Mill.StonesOnlyInMills(a, 2))) { drawEllipse(selectedNodeEllipse, 2, yellowColor, 15, false); redMill = false; removedBlueStone = true; moveBlue(); a[currentCell.i, currentCell.j] = 0; warning.SetResourceReference(TextBox.TextProperty, "blueStoneRemoved"); warning.Visibility = System.Windows.Visibility.Visible; } else { warning.SetResourceReference(TextBox.TextProperty, "stoneNotInMill"); warning.Visibility = System.Windows.Visibility.Visible; } } else if (!redMill) { removedBlueStone = false; if (secondPhase && (secondClick == false)) { if (a[currentCell.i, currentCell.j] == 1) { secondClick = true; previousEllipse = selectedNodeEllipse; selectedNodeEllipse.Stroke = Brushes.Yellow; selectedNodeEllipse.StrokeThickness = 2; } } else if (secondPhase && secondClick) { Cell previousCell = new Cell((int)previousEllipse.Tag); if (currentCell.Equals(previousCell)) { selectedNodeEllipse.Stroke = Brushes.Transparent; warning.Text = ""; warning.Visibility = System.Windows.Visibility.Hidden; secondClick = false; } else if ((a[currentCell.i, currentCell.j] == 0 && Cell.neighbour(a, previousCell, currentCell) && (!thirdPhaseRed)) || (a[currentCell.i, currentCell.j] == 0 && thirdPhaseRed)) { a[previousCell.i, previousCell.j] = 0; warning.Text = ""; warning.Visibility = System.Windows.Visibility.Hidden; drawEllipse(previousEllipse, 1, yellowColor, 15, false); moveRed(selectedNodeEllipse); secondClick = false; } else if (a[currentCell.i, currentCell.j] != 0 || (!Cell.neighbour(a, previousCell, currentCell)) && (!currentCell.Equals(previousCell)) && (!thirdPhaseRed)) { warning.SetResourceReference(TextBox.TextProperty, "invalidMove"); warning.Visibility = System.Windows.Visibility.Visible; // previousEllipse = selectedNodeEllipse; } } if (!secondPhase) { moveRed(selectedNodeEllipse); } } }
public static Cell removeRedStone(int[,] a) { // returns what red stone should be removed in case blue formed a mill // check if red could create soon a mill (two red stones in vecinity) // else remove random red stone List <Cell> redDangerousMills = Mill.checkDangerMill(a, 1); List <Mill> redMills = Mill.getMills(a, 1); HashSet <int> redStonesInMills = new HashSet <int>(); int stone = 0; foreach (Mill m in redMills) { redStonesInMills.Add(m.start); redStonesInMills.Add(m.middle); redStonesInMills.Add(m.stop); stone = m.start; } foreach (int s in redStonesInMills) { Console.Out.WriteLine(s + " "); } if (redDangerousMills.Count != 0) { // remove red stone that is inside an incomplete mill foreach (Cell incomplete in redDangerousMills) { // find its neighbours that could form a mill for (int i = 1; i < 25; i++) { for (int j = i + 1; j < 25; j++) { int k = Helper.toIJ(incomplete.i, incomplete.j); var numbers = new int[] { i, j, k }; Array.Sort(numbers); Cell x = new Cell(numbers[0]); Cell y = new Cell(numbers[1]); Cell z = new Cell(numbers[2]); // check if the stones are different, neighbours and on the same row or column if ((k != i) && (k != j) && (Cell.neighbour(a, x, y)) && (Cell.neighbour(a, y, z)) && Cell.consecutive(x, y, z)) { if (a[x.i, x.j] == 1 && (!redStonesInMills.Contains(numbers[0]))) { return(x); } else if (a[y.i, y.j] == 1 && (!redStonesInMills.Contains(numbers[1]))) { return(y); } else if (a[z.i, z.j] == 1 && (!redStonesInMills.Contains(numbers[2]))) { return(z); } } } } } // remove red stone that is in the vecinity of an incomplete mill, regardless of row or column foreach (Cell incomplete in redDangerousMills) { for (int k = 1; k < 25; k++) { Cell c = new Cell(k); if (Cell.neighbour(a, incomplete, c) && (a[c.i, c.j] == 1) && (!redStonesInMills.Contains(k))) { return(c); } } } } for (int index = 1; index < 25; index++) { Cell w = new Cell(index); if ((a[w.i, w.j] == 1) && (!redStonesInMills.Contains(index))) { return(w); } } return(new Cell(stone)); }