5AAIYEWRNV2H5226AFCA3SNM44P6ENVRDXGOYENPSCJV6L2N62AAC import 'package:flutter_test/flutter_test.dart';import 'package:dartmcts/fourinarow.dart';import 'package:dartmcts/dartmcts.dart';void main() {test('new board is properly generated', () {var board = emptyBoard();expect(board.length, equals(6));expect(board[0].length, equals(7));});test('checkTopRow returns all open plays', () {var board = emptyBoard();expect(checkTopRow(board), equals([0, 1, 2, 3, 4, 5, 6]));board[0][3] = Player.FIRST;expect(checkTopRow(board), equals([0, 1, 2, 4, 5, 6]));});test('findRowForColumn works as expected', () {var o = Player.FIRST;var x = Player.SECOND;var _;Board board = [[o, o, _, _, _, x, x],[x, o, _, _, _, o, o],[o, x, o, _, _, x, x],[x, o, x, _, _, o, o],[o, x, o, _, _, x, x],[x, o, x, _, x, o, o]];expect(findRowForColumn(board, 2), equals(1));expect(() => findRowForColumn(board, 0), throwsException);expect(findRowForColumn(board, 3), equals(5));expect(findRowForColumn(board, 4), equals(4));expect(() => findRowForColumn(board, 5), throwsException);});test('cloneAndApplyMove works as expected', () {var o = Player.FIRST;var x = Player.SECOND;var _;Board board = [[_, _, _, _, _, _, _],[_, _, _, _, _, _, _],[_, _, _, _, _, _, _],[_, _, _, _, _, _, _],[_, _, _, _, _, _, _],[_, _, _, _, o, o, o]];var game = ConnectFourGame(board: board, bitboards: getBitBoards(board), scores: {});var game2 = game.cloneAndApplyMove(6);expect(game2.winner, isNull);expect(game2.board,equals([[_, _, _, _, _, _, _],[_, _, _, _, _, _, _],[_, _, _, _, _, _, _],[_, _, _, _, _, _, _],[_, _, _, _, _, _, o],[_, _, _, _, o, o, o]]));game = ConnectFourGame(board: board, bitboards: getBitBoards(board), scores: {});game = game.cloneAndApplyMove(3);expect(game.board,equals([[_, _, _, _, _, _, _],[_, _, _, _, _, _, _],[_, _, _, _, _, _, _],[_, _, _, _, _, _, _],[_, _, _, _, _, _, _],[_, _, _, o, o, o, o]]));expect(game.winner, equals(o));board = [[_, _, _, _, _, _, _],[_, _, _, _, _, _, _],[_, _, _, _, _, _, _],[_, _, _, _, _, x, o],[_, _, _, _, x, o, x],[_, _, _, x, o, o, o]];game = ConnectFourGame(board: board,bitboards: getBitBoards(board),currentPlayer: Player.SECOND,scores: {});game = game.cloneAndApplyMove(6);expect(game.winner, equals(Player.SECOND));});test('plays out a game from start to finish', () {int smartWins = 0;for (var _ = 0; _ < 100; _++) {ConnectFourGame game = ConnectFourGame.newGame();while (game.getMoves().length > 0) {MCTSResult<Move, Player> result;int iterations;if (game.currentPlayer == Player.FIRST) {iterations = 5;} else {iterations = 10;}result =MCTS(gameState: game).getSimulationResult(iterations: iterations);game = game.cloneAndApplyMove(result.move!);}if (_ == 99) {print(game.board);print(game.winner);}if (game.winner == Player.SECOND) {smartWins++;}}expect(smartWins, greaterThan(70));});}
}/* @Test@Testfun testWinningBoard() {val e = nullval r = FourInARowPlayer.REDval b = FourInARowPlayer.BLUEval board: FourInARowBoard = arrayOf(arrayOfNulls(7),arrayOfNulls(7),arrayOfNulls(7),arrayOfNulls(7),arrayOf(e, e, r, r, r, e, e),arrayOf(e, b, b, b, b, e, e))assertEquals(BigInteger("270549120"),getBitBoard(FourInARowPlayer.BLUE,board))assertEquals(true,winningBoard(FourInARowPlayer.BLUE,board))}@Testfun testOnlyDeterminedMovesAreFollowed() {result = (MCTS(GameWithManyMovesOnlyOneDetermined).get_simulation_result(100))self.assertEqual(result.root.children[0].move, 1)self.assertEqual(result.root.children[0].visits, 100)}@Testfun testFourInARowWithMCTS() {val e = nullval r = FourInARowPlayer.REDval b = FourInARowPlayer.BLUEval oneMoveFromWinning = FourInARowGame(board = arrayOf(arrayOfNulls(7),arrayOfNulls(7),arrayOfNulls(7),arrayOfNulls(7),arrayOf(e, e, r, r, r, e, e),arrayOf(e, e, b, b, b, e, e)),currentPlayer = FourInARowPlayer.BLUE)val result = MCTS(oneMoveFromWinning).getSimulationResult(maxSeconds = 10)assertTrue(result.move in listOf(1, 5))val board = arrayOf(arrayOfNulls(7),arrayOfNulls(7),arrayOfNulls(7),arrayOfNulls(7),arrayOf(e, e, r, r, r, e, e),arrayOf(e, e, b, b, b, b, e))assertEquals(BigInteger("34630287360"),getBitBoard(b, board))assertTrue(checkWin(getBitBoard(b,board)))}
import 'package:dartmcts/dartmcts.dart';const List<List<int>> bitboardLookup = [[5, 12, 19, 26, 33, 40, 47],[4, 11, 18, 25, 32, 39, 46],[3, 10, 17, 24, 31, 38, 45],[2, 9, 16, 23, 30, 37, 44],[1, 8, 15, 22, 29, 36, 43],[0, 7, 14, 21, 28, 35, 42],];typedef Move = int;typedef Board = List<List<Player?>>;enum Player {FIRST,SECOND,}Board emptyBoard() {return [for (var i = 0; i < 6; i++) [for (var _ = 0; _ < 7; _++) null]];}bool checkWin(int bitboard) {var height = 6;var h1 = height + 1;var h2 = height + 2;var diag1 = bitboard & (bitboard >> height);var hori = bitboard & (bitboard >> h1);var diag2 = bitboard & (bitboard >> h2);var vert = bitboard & (bitboard >> 1);return ((diag1 & (diag1 >> 2 * height)) |(hori & (hori >> 2 * h1)) |(diag2 & (diag2 >> 2 * h2)) |(vert & (vert >> 2))) >0;}List<int> checkTopRow(Board board) {return [for (var c = 0; c < 7; c++)if (board[0][c] == null) c];}Map<Player, int> getBitBoards(Board board) {Map<Player, int> bitboards = {Player.FIRST: 0, Player.SECOND: 0};for (var player in bitboards.keys) {for (var row = 5; row >= 0; row--) {for (var col = 0; col < 7; col++) {if (board[row][col] == player) {bitboards[player] =bitboards[player]! ^ (1 << bitboardLookup[row][col]);}}}}return bitboards;}int findRowForColumn(Board board, int column) {for (var row = 5; row >= 0; row--) {if (board[row][column] == null) {return row;}}throw Exception('No empty spot in that column');}class ConnectFourGame implements GameState<Move, Player> {Player? currentPlayer;Map<Player, int> bitboards;Board board;Player? winner;Map<Player, int> scores;ConnectFourGame({this.winner,required this.board,required this.bitboards,required this.scores,this.currentPlayer = Player.FIRST});static ConnectFourGame newGame() {return ConnectFourGame(board: emptyBoard(),bitboards: {Player.FIRST: 0, Player.SECOND: 0},scores: {Player.FIRST: 0, Player.SECOND: 0});}@overrideConnectFourGame cloneAndApplyMove(Move column) {var newBitboards = Map<Player, int>.from(bitboards);Board newBoard =Board.from([for (var row in board) List<Player?>.from(row)]);Player? newWinner;Player newPlayer;Map<Player, int> newScores = {Player.FIRST: 0,Player.SECOND: 0,};int row = findRowForColumn(board, column);newBoard[row][column] = currentPlayer;newBitboards[currentPlayer!] =newBitboards[currentPlayer]! ^ 1 << bitboardLookup[row][column];newBitboards.forEach((player, bitboard) {if (checkWin(bitboard)) {newWinner = player;newScores[player] = 1;}});if (currentPlayer == Player.FIRST) {newPlayer = Player.SECOND;} else {newPlayer = Player.FIRST;}return ConnectFourGame(board: newBoard,bitboards: newBitboards,winner: newWinner,scores: newScores,currentPlayer: newPlayer);}@overrideList<Move> getMoves() {if (winner != null) {return [];}return checkTopRow(board);}@overrideGameState<Move, Player> determine(GameState<Move, Player>? initialState) {return this;}}