From 4c1ced7e637f9ab71e1912c411bab755c4d99f1b Mon Sep 17 00:00:00 2001 From: okaryo Date: Mon, 9 Oct 2023 17:33:36 +0900 Subject: [PATCH 1/2] =?UTF-8?q?feat:=20=E3=83=AD=E3=82=B8=E3=83=83?= =?UTF-8?q?=E3=82=AF=E3=82=92=E6=9C=80=E6=96=B0=E7=89=88=E3=81=AB=E5=A4=89?= =?UTF-8?q?=E6=9B=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/model/players.dart | 9 +++++ lib/model/tic_tac_toe.dart | 74 ++++++++++++++++++++++++++++++-------- 2 files changed, 68 insertions(+), 15 deletions(-) create mode 100644 lib/model/players.dart diff --git a/lib/model/players.dart b/lib/model/players.dart new file mode 100644 index 0000000..c4df92f --- /dev/null +++ b/lib/model/players.dart @@ -0,0 +1,9 @@ +class Players { + final String playerX; + final String playerO; + + Players({ + required this.playerX, + required this.playerO, + }); +} diff --git a/lib/model/tic_tac_toe.dart b/lib/model/tic_tac_toe.dart index 6c742d9..b5d36b8 100644 --- a/lib/model/tic_tac_toe.dart +++ b/lib/model/tic_tac_toe.dart @@ -1,24 +1,68 @@ +import 'package:tic_tac_toe_handson/model/players.dart'; + class TicTacToe { final List> board; + final Players players; final String currentPlayer; - factory TicTacToe.start() { - return TicTacToe._([ - ['', '', ''], - ['', '', ''], - ['', '', ''], - ], 'X'); + factory TicTacToe.start({ + playerX = 'X', + playerO = 'O', + }) { + final players = Players( + playerX: playerX, + playerO: playerO, + ); + + return TicTacToe( + [ + ['', '', ''], + ['', '', ''], + ['', '', ''], + ], + players, + players.playerX, + ); } - TicTacToe._(this.board, this.currentPlayer); + TicTacToe(this.board, this.players, this.currentPlayer); + + factory TicTacToe.fromJson(Map json) { + final flatBoard = List.from(json['board']); + + return TicTacToe( + [ + List.from(flatBoard.sublist(0, 3)), + List.from(flatBoard.sublist(3, 6)), + List.from(flatBoard.sublist(6, 9)), + ], + Players( + playerX: json['players']['playerX'], + playerO: json['players']['playerO'], + ), + json['currentPlayer'], + ); + } + + Map toJson() { + return { + // Firestoreではネストした配列を扱えないため、1次元配列に変換する + 'board': [...board[0], ...board[1], ...board[2]], + 'players': { + 'playerX': players.playerX, + 'playerO': players.playerO, + }, + 'currentPlayer': currentPlayer, + }; + } TicTacToe placeMark(int row, int col) { if (board[row][col].isEmpty) { final newBoard = List.of(board); - newBoard[row][col] = currentPlayer; - String nextPlayer = currentPlayer == 'X' ? 'O' : 'X'; + newBoard[row][col] = currentPlayer == players.playerX ? 'X' : 'O'; + String nextPlayer = currentPlayer == players.playerX ? players.playerO : players.playerX; - return TicTacToe._(newBoard, nextPlayer); + return TicTacToe(newBoard, players, nextPlayer); } return this; } @@ -27,20 +71,20 @@ class TicTacToe { for (int i = 0; i < 3; i++) { // row = i における横の判定 if (board[i][0] == board[i][1] && board[i][1] == board[i][2] && board[i][0].isNotEmpty) { - return board[i][0]; + return board[i][0] == 'X' ? players.playerX : players.playerO; } // col = i における縦の判定 if (board[0][i] == board[1][i] && board[1][i] == board[2][i] && board[0][i].isNotEmpty) { - return board[0][i]; + return board[0][i] == 'X' ? players.playerX : players.playerO; } } // 左上から右下への斜めの判定 if (board[0][0] == board[1][1] && board[1][1] == board[2][2] && board[0][0].isNotEmpty) { - return board[0][0]; + return board[0][0] == 'X' ? players.playerX : players.playerO; } // 右上から左下への斜めの判定 if (board[0][2] == board[1][1] && board[1][1] == board[2][0] && board[0][2].isNotEmpty) { - return board[0][2]; + return board[0][2] == 'X' ? players.playerX : players.playerO; } return ''; } @@ -50,6 +94,6 @@ class TicTacToe { } TicTacToe resetBoard() { - return TicTacToe.start(); + return TicTacToe.start(playerX: players.playerX, playerO: players.playerO); } } From 5801d77e6f1e66a07baff0122b5ba29e67ca288e Mon Sep 17 00:00:00 2001 From: okaryo Date: Mon, 9 Oct 2023 17:53:34 +0900 Subject: [PATCH 2/2] =?UTF-8?q?modify:=20StateNotifierProvider=E3=82=92?= =?UTF-8?q?=E3=80=81=E6=9C=80=E5=88=9D=E3=81=AEProvider=E3=81=A8=E3=81=97?= =?UTF-8?q?=E3=81=A6=E3=81=AF=E9=81=A9=E5=88=87=E3=81=AAStateProvider?= =?UTF-8?q?=E3=81=AB=E6=9B=B8=E3=81=8D=E6=8F=9B=E3=81=88?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/provider/tic_tac_toe_provider.dart | 16 ++--------- lib/view/board.dart | 7 +++-- test/place_mark_test.dart | 22 +++++++------- test/reset_board_test.dart | 40 +++++++++++++------------- 4 files changed, 37 insertions(+), 48 deletions(-) diff --git a/lib/provider/tic_tac_toe_provider.dart b/lib/provider/tic_tac_toe_provider.dart index 9eb8ef2..d8e5ffe 100644 --- a/lib/provider/tic_tac_toe_provider.dart +++ b/lib/provider/tic_tac_toe_provider.dart @@ -1,18 +1,6 @@ import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:tic_tac_toe_handson/model/tic_tac_toe.dart'; -final ticTacToeProvider = StateNotifierProvider.autoDispose((ref) { - return TicTacToeProvider(); +final ticTacToeProvider = StateProvider.autoDispose((ref) { + return TicTacToe.start(); }); - -class TicTacToeProvider extends StateNotifier { - TicTacToeProvider() : super(TicTacToe.start()); - - placeMark(int row, int col) { - state = state.placeMark(row, col); - } - - resetBoard() { - state = state.resetBoard(); - } -} diff --git a/lib/view/board.dart b/lib/view/board.dart index dfab25d..19c8abf 100644 --- a/lib/view/board.dart +++ b/lib/view/board.dart @@ -12,7 +12,8 @@ class Board extends ConsumerWidget { return Padding( padding: const EdgeInsets.all(16), - child: SingleChildScrollView(child: Column( + child: SingleChildScrollView( + child: Column( mainAxisAlignment: MainAxisAlignment.center, crossAxisAlignment: CrossAxisAlignment.center, children: [ @@ -38,7 +39,7 @@ class Board extends ConsumerWidget { onTap: () { final winner = ticTacToe.getWinner(); if (mark.isEmpty && winner.isEmpty) { - ref.read(ticTacToeProvider.notifier).placeMark(row, col); + ref.read(ticTacToeProvider.notifier).state = ticTacToe.placeMark(row, col); } }, child: Container( @@ -60,7 +61,7 @@ class Board extends ConsumerWidget { width: double.infinity, child: ElevatedButton( onPressed: () { - ref.read(ticTacToeProvider.notifier).resetBoard(); + ref.read(ticTacToeProvider.notifier).state = ticTacToe.resetBoard(); }, child: const Text('ゲームをリセット'), ), diff --git a/test/place_mark_test.dart b/test/place_mark_test.dart index 57d7499..6a01716 100644 --- a/test/place_mark_test.dart +++ b/test/place_mark_test.dart @@ -1,10 +1,10 @@ import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:flutter_test/flutter_test.dart'; - +import 'package:tic_tac_toe_handson/model/tic_tac_toe.dart'; import 'package:tic_tac_toe_handson/provider/tic_tac_toe_provider.dart'; void main() { - late TicTacToeProvider target; + late StateController target; setUp(() { final container = ProviderContainer(); @@ -17,7 +17,7 @@ void main() { ['', '', ''], ['', '', ''], ]); - target.placeMark(0, 0); + target.state = target.state.placeMark(0, 0); expect(target.state.board, [ ['X', '', ''], ['', '', ''], @@ -31,7 +31,7 @@ void main() { ['', '', ''], ['', '', ''], ]); - target.placeMark(0, 1); + target.state = target.state.placeMark(0, 1); expect(target.state.board, [ ['', 'X', ''], ['', '', ''], @@ -45,7 +45,7 @@ void main() { ['', '', ''], ['', '', ''], ]); - target.placeMark(0, 2); + target.state = target.state.placeMark(0, 2); expect(target.state.board, [ ['', '', 'X'], ['', '', ''], @@ -59,7 +59,7 @@ void main() { ['', '', ''], ['', '', ''], ]); - target.placeMark(1, 0); + target.state = target.state.placeMark(1, 0); expect(target.state.board, [ ['', '', ''], ['X', '', ''], @@ -73,7 +73,7 @@ void main() { ['', '', ''], ['', '', ''], ]); - target.placeMark(1, 1); + target.state = target.state.placeMark(1, 1); expect(target.state.board, [ ['', '', ''], ['', 'X', ''], @@ -87,7 +87,7 @@ void main() { ['', '', ''], ['', '', ''], ]); - target.placeMark(1, 2); + target.state = target.state.placeMark(1, 2); expect(target.state.board, [ ['', '', ''], ['', '', 'X'], @@ -101,7 +101,7 @@ void main() { ['', '', ''], ['', '', ''], ]); - target.placeMark(2, 0); + target.state = target.state.placeMark(2, 0); expect(target.state.board, [ ['', '', ''], ['', '', ''], @@ -115,7 +115,7 @@ void main() { ['', '', ''], ['', '', ''], ]); - target.placeMark(2, 1); + target.state = target.state.placeMark(2, 1); expect(target.state.board, [ ['', '', ''], ['', '', ''], @@ -129,7 +129,7 @@ void main() { ['', '', ''], ['', '', ''], ]); - target.placeMark(2, 2); + target.state = target.state.placeMark(2, 2); expect(target.state.board, [ ['', '', ''], ['', '', ''], diff --git a/test/reset_board_test.dart b/test/reset_board_test.dart index 463152f..d9214ab 100644 --- a/test/reset_board_test.dart +++ b/test/reset_board_test.dart @@ -1,10 +1,10 @@ import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:flutter_test/flutter_test.dart'; - +import 'package:tic_tac_toe_handson/model/tic_tac_toe.dart'; import 'package:tic_tac_toe_handson/provider/tic_tac_toe_provider.dart'; void main() { - late TicTacToeProvider target; + late StateController target; setUp(() { final container = ProviderContainer(); @@ -12,13 +12,13 @@ void main() { }); test("resetBoard test - row: 0, col: 0", () { - target.placeMark(0, 0); + target.state = target.state.placeMark(0, 0); expect(target.state.board, [ ['X', '', ''], ['', '', ''], ['', '', ''], ]); - target.resetBoard(); + target.state = target.state.resetBoard(); expect(target.state.board, [ ['', '', ''], ['', '', ''], @@ -27,13 +27,13 @@ void main() { }); test("resetBoard test - row: 0, col: 1", () { - target.placeMark(0, 1); + target.state = target.state.placeMark(0, 1); expect(target.state.board, [ ['', 'X', ''], ['', '', ''], ['', '', ''], ]); - target.resetBoard(); + target.state = target.state.resetBoard(); expect(target.state.board, [ ['', '', ''], ['', '', ''], @@ -42,13 +42,13 @@ void main() { }); test("resetBoard test - row: 0, col: 2", () { - target.placeMark(0, 2); + target.state = target.state.placeMark(0, 2); expect(target.state.board, [ ['', '', 'X'], ['', '', ''], ['', '', ''], ]); - target.resetBoard(); + target.state = target.state.resetBoard(); expect(target.state.board, [ ['', '', ''], ['', '', ''], @@ -57,13 +57,13 @@ void main() { }); test("resetBoard test - row: 1, col: 0", () { - target.placeMark(1, 0); + target.state = target.state.placeMark(1, 0); expect(target.state.board, [ ['', '', ''], ['X', '', ''], ['', '', ''], ]); - target.resetBoard(); + target.state = target.state.resetBoard(); expect(target.state.board, [ ['', '', ''], ['', '', ''], @@ -72,13 +72,13 @@ void main() { }); test("resetBoard test - row: 1, col: 1", () { - target.placeMark(1, 1); + target.state = target.state.placeMark(1, 1); expect(target.state.board, [ ['', '', ''], ['', 'X', ''], ['', '', ''], ]); - target.resetBoard(); + target.state = target.state.resetBoard(); expect(target.state.board, [ ['', '', ''], ['', '', ''], @@ -87,13 +87,13 @@ void main() { }); test("resetBoard test - row: 1, col: 2", () { - target.placeMark(1, 2); + target.state = target.state.placeMark(1, 2); expect(target.state.board, [ ['', '', ''], ['', '', 'X'], ['', '', ''], ]); - target.resetBoard(); + target.state = target.state.resetBoard(); expect(target.state.board, [ ['', '', ''], ['', '', ''], @@ -102,13 +102,13 @@ void main() { }); test("resetBoard test - row: 2, col: 0", () { - target.placeMark(2, 0); + target.state = target.state.placeMark(2, 0); expect(target.state.board, [ ['', '', ''], ['', '', ''], ['X', '', ''], ]); - target.resetBoard(); + target.state = target.state.resetBoard(); expect(target.state.board, [ ['', '', ''], ['', '', ''], @@ -117,13 +117,13 @@ void main() { }); test("resetBoard test - row: 2, col: 1", () { - target.placeMark(2, 1); + target.state = target.state.placeMark(2, 1); expect(target.state.board, [ ['', '', ''], ['', '', ''], ['', 'X', ''], ]); - target.resetBoard(); + target.state = target.state.resetBoard(); expect(target.state.board, [ ['', '', ''], ['', '', ''], @@ -132,13 +132,13 @@ void main() { }); test("resetBoard test - row: 2, col: 2", () { - target.placeMark(2, 2); + target.state = target.state.placeMark(2, 2); expect(target.state.board, [ ['', '', ''], ['', '', ''], ['', '', 'X'], ]); - target.resetBoard(); + target.state = target.state.resetBoard(); expect(target.state.board, [ ['', '', ''], ['', '', ''],