/// <summary> /// Un joueur tente de jouer un coup. Joue le coup et change de tour si possible. /// Si l'autre joueur doit passer, reviens au premier joueur. /// Si la partie est terminée, affichage des score et du gagnant. /// </summary> private void Pawn_Click(object sender, RoutedEventArgs e) { contextPlayers.Timer.Stop(); CellButton cellButton = (CellButton)sender; int c = cellButton.C; int l = cellButton.L; if (board.PlayMove(c, l, whiteTurn)) { // Coup jouable et joué cellButton.Val = board.GetBoard()[c, l]; whiteTurn = !whiteTurn; var newWhiteTurn = whiteTurn; CheckFinished(); // L'IA joue que si elle n'a pas passé son tour (donc whiteTurn n'a pas été modifié dans CheckFinished().) if (playAgainstIA && newWhiteTurn == whiteTurn) { PlayIAMove(); CheckFinished(); } } else { // Impossible de jouer ce coup } }
/// <summary> /// Refresh the button of the grid according to the board state /// </summary> public void UpdateGridValue() { int[,] gridBoard = board.GetBoard(); int numPlayableTiles = 0; int numEmptyTiles = 0; for (int y = 0; y < Constants.GRID_SIZE; y++) { for (int x = 0; x < Constants.GRID_SIZE; x++) { //Set the playable tiles if (board.IsPlayable(x, y, board.GetTurn())) { tiles[x, y].IsPlayable = true; numPlayableTiles++; } else { tiles[x, y].IsPlayable = false; } if (gridBoard[x, y] == -1) { numEmptyTiles++; } tiles[x, y].State = gridBoard[x, y]; } } updateImagePlayer(); checkGameEnd(numPlayableTiles, numEmptyTiles); }
public Board(Board boardSource) { board = (int[, ])boardSource.GetBoard().Clone(); playerWhite = boardSource.PlayerWhite; playerBlack = boardSource.PlayerBlack; isWhite = boardSource.GetTurn(); }
static void Main(string[] args) { var boardInput = new List<string>(); string current; using (var reader = new System.IO.StringReader(input)) { current = reader.ReadLine(); string line; while ((line = reader.ReadLine()) != null) { boardInput.Add(line); } } var board = Board.GetBoard(boardInput); }
/// <summary> /// Creates and displays board /// </summary> private void PrintBoard() { canBoard.Children.Clear(); //Getting board canvas dimensions int canvasHeight = (int)canBoard.ActualHeight; int canvasWidth = (int)canBoard.ActualWidth; //Background Rectangle bg = new Rectangle { Height = canvasHeight, Width = canvasWidth }; //Modifying canvas based on background Canvas.SetTop(bg, 0); Canvas.SetLeft(bg, 0); bg.Fill = Brushes.White; canBoard.Children.Add(bg); //Brush Brush myBrush = new SolidColorBrush(Color.FromArgb(100, 200, 10, 10)); //Painting board lines for (int i = 0; i < 4; i++) { Line myLine = new Line { Stroke = myBrush, X1 = 0, X2 = canvasWidth, Y1 = (canvasHeight / 4.0 * i) + (canvasWidth / 16.0), Y2 = (canvasHeight / 4.0 * i) + (canvasHeight / 16.0), StrokeThickness = (int)(canvasHeight / 8.0) }; canBoard.Children.Add(myLine); myLine = new Line { Stroke = myBrush, Y1 = 0, Y2 = canvasHeight, X1 = (canvasWidth / 4.0 * i) + (canvasWidth / 16.0), X2 = (canvasHeight / 4.0 * i) + (canvasHeight / 16.0), StrokeThickness = (int)(canvasWidth / 8.0) }; canBoard.Children.Add(myLine); } //Texture rectangle Rectangle textileFilter = new Rectangle { Height = canvasHeight, Width = canvasWidth }; //Modifying canvas based on rectangle Canvas.SetTop(textileFilter, 0); Canvas.SetLeft(textileFilter, 0); //Filling rectangle with texture image ImageBrush textileBrush = new ImageBrush { ImageSource = new BitmapImage(new Uri(@"imgs\texttexture.png", UriKind.Relative)) }; textileFilter.Fill = textileBrush; //Painting board squares canBoard.Children.Add(textileFilter); //Painting existing counters on board for (int i = 0; i < 8; i++) { for (int j = 0; j < 8; j++) { if (board.GetBoard()[i, j] >= 0) { Rectangle square = new Rectangle { Height = canvasHeight / 8.0, Width = canvasWidth / 8.0 }; Canvas.SetTop(square, j * canvasHeight / 8.0); Canvas.SetLeft(square, i * canvasWidth / 8.0); //Setting counter image based on player if (board.GetBoard()[i, j] == 0) { square.Fill = skinPlayer1.Clone(); } else { square.Fill = skinPlayer2.Clone(); } canBoard.Children.Add(square); } } } }
// Alpha beta searching with transposition table private double AlphaBeta(int[,] board, int color, int depth = 0, double alpha = double.NegativeInfinity, double beta = double.PositiveInfinity) { nodeCount += 1; evaluator.SetBoard(board); // Return evaluation value if reaching depth = depthMax or terminal node if (depth >= currentDepthMax) { return(evaluator.Evaluate(selfColor)); } // Return evaluation when game ends List <Pos> newOptions = evaluator.Availables(color); List <Pos> oppNewOptions = evaluator.Availables(StoneColor.OppColor(color)); if (newOptions.Count == 0 && oppNewOptions.Count == 0) { int selfStones = evaluator.CountStones(selfColor); int oppStones = evaluator.CountStones(StoneColor.OppColor(selfColor)); if (selfStones > oppStones) { return(double.PositiveInfinity); } else if (selfStones < oppStones) { return(double.NegativeInfinity); } else { return(evaluator.Evaluate(selfColor)); } } // When only the opponent can put stone, go to next depth if (newOptions.Count == 0) { depth += 1; color = StoneColor.OppColor(color); newOptions = oppNewOptions; } // Expand board and store the all child boards in children list // Associate the child and the action of that time List <int[, ]> children = new List <int[, ]>(); Dictionary <int[, ], Pos> actionChildTable = new Dictionary <int[, ], Pos>(); foreach (Pos action in newOptions) { Board childBoard = new Board(); childBoard.SetBoard(board); childBoard.UpdateBoard(action, color); children.Add(childBoard.GetBoard()); actionChildTable.Add(childBoard.GetBoard(), action); } // Sort children in order of the score // In descending order when self turn and in ascending order when opponent turn st.Start(); if (depth <= 3) { children = OrderBoards(children, color); } st.Stop(); // Alpha beta searching if (color == selfColor) { // In self turn, search max value of children double score = double.NegativeInfinity; foreach (int[,] child in children) { // Check if the child is stored in transposition table and the node type is EXACT // If it does, set the value for the score // If not, start alpha-beta-searching in next depth and store the score string childHash = BoardToHash(child); if (transpositionTable.ContainsKey(childHash) && transpositionTable[childHash].Depth >= currentDepthMax && transpositionTable[childHash].NodeType == "EXACT") { transpositionCutCount += 1; score = transpositionTable[childHash].Score; } else { score = AlphaBeta(child, StoneColor.OppColor(color), depth + 1, alpha, beta); transpositionTable[childHash] = new TranspositionTableEntry(child, currentDepthMax, score); } if (score > alpha) { alpha = score; // Get best action if (depth == 0) { foreach (KeyValuePair <int[, ], Pos> kvp in actionChildTable) { if (kvp.Key.Cast <int>().SequenceEqual(child.Cast <int>())) { bestAction = kvp.Value; } } } } // Beta cut if (alpha >= beta) { betaCutCount += 1; break; } } return(alpha); } else { // If the opponent turn, search minimum value of children double score = double.PositiveInfinity; foreach (int[,] child in children) { string childHash = BoardToHash(child); if (transpositionTable.ContainsKey(childHash) && transpositionTable[childHash].Depth >= currentDepthMax && transpositionTable[childHash].NodeType == "EXACT") { transpositionCutCount += 1; score = transpositionTable[childHash].Score; } else { score = AlphaBeta(child, StoneColor.OppColor(color), depth + 1, alpha, beta); transpositionTable[childHash] = new TranspositionTableEntry(child, currentDepthMax, score); } beta = Math.Min(beta, score); // Alpha cut if (beta <= alpha) { alphaCutCount += 1; break; } } return(beta); } }
/// <summary> /// Demande à l'IA de jouer un coup. /// Méthode asynchrone pour permettre l'affichage du coup du joueur avant que l'IA joue. /// </summary> private void PlayIAMove() { int difficulty = 2; // Le joueur humain est bloqué foreach (var cell in cells) { cell.IsEnabled = false; } // Copie des variables utilisées dans un BackgroundWorker pour éviter la concurrence Board copyBoard = new Board(board); bool copyWhiteTurn = whiteTurn; int copyDifficulty = difficulty; Tuple <int, int> move = null; BackgroundWorker bgWorker = new BackgroundWorker(); // On fait réfléchir l'IA dans un BackgroudWorker bgWorker.DoWork += (sender, ev) => { Thread.Sleep(1000); move = copyBoard.GetNextMove(copyBoard.GetBoard(), copyDifficulty, copyWhiteTurn); }; // Quand elle trouve un coup, on met à jour le board bgWorker.RunWorkerCompleted += (sender, ev) => { int c = move.Item1; int l = move.Item2; // Vérifie que l'IA n'a pas passé son tour if (c >= 0 && l >= 0) { if (board.PlayMove(c, l, whiteTurn)) { // Coup jouable et joué whiteTurn = !whiteTurn; } else { // Impossible de jouer ce coup } } var newWhiteTurn = whiteTurn; CheckFinished(); if (newWhiteTurn != whiteTurn) { // Le joueur a passé son tour (whiteTurn a été modifié dans CheckFinished()) PlayIAMove(); } // Débloque le joueur humain foreach (var cell in cells) { cell.IsEnabled = true; } }; // On lance le background worker bgWorker.RunWorkerAsync(); }
/// <summary> /// Commence ou recommence une partie. /// </summary> private void StartGame() { UpdateTitle(); // Le joueur noir commence toujours whiteTurn = false; // Création du contexte pour les infos des joueurs contextPlayers = new ContextPlayers(2, 2); // On bind les infos au DataContext de la fenêtre. DataContext = contextPlayers; // Nouveau plateau de jeu board = new Board(); cells = new CellButton[8, 8]; // Style des boutons (pions) Style resource = (Style)FindResource("PawnStyle"); var tabBoard = board.GetBoard(); for (int c = 0; c < 8; c++) { for (int l = 0; l < 8; l++) { // Création et ajout du pion dans le plateau de jeu var val = tabBoard[c, l]; CellButton pawnBtn = new CellButton(c, l, val) { Style = resource }; pawnBtn.Click += Pawn_Click; cells[c, l] = pawnBtn; // Ajout graphique du pion : Border(Grid(bouton transparent, ellipse visible)) Border border = new Border { BorderBrush = Brushes.White, BorderThickness = new Thickness(1, 1, 0, 0) }; if (c == 0) { border.BorderThickness = new Thickness(0, 1, 0, 0); if (l == 0) { border.BorderThickness = new Thickness(0, 0, 0, 0); } } else if (l == 0) { border.BorderThickness = new Thickness(1, 0, 0, 0); } Grid grid = new Grid { Background = Brushes.Green }; Viewbox viewbox = new Viewbox { Child = pawnBtn.Ellipse, Margin = new Thickness(4) }; grid.Children.Add(viewbox); grid.Children.Add(pawnBtn); border.Child = grid; Grid.SetColumn(border, c + 1); Grid.SetRow(border, l + 1); gridBoard.Children.Add(border); } } // Ajout des en-têtes au plateau (A-H dans les colonnes, 1-8 pour les lignes) AddHeader(); // Refresh de la GUI UpdateUI(false); }