Skip to content
Snippets Groups Projects
Commit d05ce606 authored by Benoît Harrault's avatar Benoît Harrault
Browse files

Merge branch '9-clean-code' into 'master'

Resolve "Clean code"

Closes #9

See merge request !8
parents fcf5c889 2a06224d
No related branches found
No related tags found
1 merge request!8Resolve "Clean code"
Pipeline #2912 passed
org.gradle.jvmargs=-Xmx1536M org.gradle.jvmargs=-Xmx1536M
android.useAndroidX=true android.useAndroidX=true
android.enableJetifier=true android.enableJetifier=true
app.versionName=0.0.5 app.versionName=0.0.6
app.versionCode=5 app.versionCode=6
Clean code, fix deprecations
Nettoyage de code, correction des deprecations
...@@ -133,8 +133,7 @@ class GameBoard { ...@@ -133,8 +133,7 @@ class GameBoard {
// flipped. If so, the method returns true, otherwise false. If [flip] is set // flipped. If so, the method returns true, otherwise false. If [flip] is set
// to true, the pieces are flipped in place to their new colors before the // to true, the pieces are flipped in place to their new colors before the
// method returns. // method returns.
bool _traversePath( bool _traversePath(int x, int y, int dx, int dy, PieceType player, bool flip) {
int x, int y, int dx, int dy, PieceType player, bool flip) {
var foundOpponent = false; var foundOpponent = false;
var curX = x + dx; var curX = x + dx;
var curY = y + dy; var curY = y + dy;
......
...@@ -39,7 +39,7 @@ class GameModel { ...@@ -39,7 +39,7 @@ class GameModel {
/// returned. If unsuccessful, null is returned. /// returned. If unsuccessful, null is returned.
GameModel updateForMove(int x, int y) { GameModel updateForMove(int x, int y) {
if (!board.isLegalMove(x, y, player)) { if (!board.isLegalMove(x, y, player)) {
return null!; return GameModel(board: board, player: player);
} }
final newBoard = board.updateForMove(x, y, player); final newBoard = board.updateForMove(x, y, player);
......
...@@ -7,7 +7,6 @@ import 'dart:async'; ...@@ -7,7 +7,6 @@ import 'dart:async';
import 'package:async/async.dart'; import 'package:async/async.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter/services.dart' show SystemChrome, DeviceOrientation; import 'package:flutter/services.dart' show SystemChrome, DeviceOrientation;
import 'package:flutter/widgets.dart';
import 'game_board.dart'; import 'game_board.dart';
import 'game_model.dart'; import 'game_model.dart';
...@@ -30,7 +29,6 @@ void main() { ...@@ -30,7 +29,6 @@ void main() {
class FlutterFlipApp extends StatelessWidget { class FlutterFlipApp extends StatelessWidget {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return MaterialApp( return MaterialApp(
debugShowCheckedModeBanner: false, debugShowCheckedModeBanner: false,
theme: ThemeData( theme: ThemeData(
...@@ -56,10 +54,8 @@ class GameScreen extends StatefulWidget { ...@@ -56,10 +54,8 @@ class GameScreen extends StatefulWidget {
/// sent downstream. [GameScreen] uses a [StreamBuilder] wired up to that stream /// sent downstream. [GameScreen] uses a [StreamBuilder] wired up to that stream
/// of models to build out its [Widget] tree. /// of models to build out its [Widget] tree.
class _GameScreenState extends State<GameScreen> { class _GameScreenState extends State<GameScreen> {
final StreamController<GameModel> _userMovesController = final StreamController<GameModel> _userMovesController = StreamController<GameModel>();
StreamController<GameModel>(); final StreamController<GameModel> _restartController = StreamController<GameModel>();
final StreamController<GameModel> _restartController =
StreamController<GameModel>();
Stream<GameModel>? _modelStream; Stream<GameModel>? _modelStream;
_GameScreenState() { _GameScreenState() {
...@@ -129,19 +125,18 @@ class _GameScreenState extends State<GameScreen> { ...@@ -129,19 +125,18 @@ class _GameScreenState extends State<GameScreen> {
// turn, this method will attempt to make the move, creating a new GameModel // turn, this method will attempt to make the move, creating a new GameModel
// in the process. // in the process.
void _attemptUserMove(GameModel model, int x, int y) { void _attemptUserMove(GameModel model, int x, int y) {
if (model.player == PieceType.black && if (model.player == PieceType.black && model.board.isLegalMove(x, y, model.player)) {
model.board.isLegalMove(x, y, model.player)) {
_userMovesController.add(model.updateForMove(x, y)); _userMovesController.add(model.updateForMove(x, y));
} }
} }
Widget _buildScoreBox(PieceType player, GameModel model) { Widget _buildScoreBox(PieceType player, GameModel model) {
var assetImageCode = player == PieceType.black ? 'black' : 'white'; var assetImageCode = player == PieceType.black ? 'black' : 'white';
String assetImageName = 'assets/skins/' + model.skin + '_tile_' + assetImageCode + '.png'; String assetImageName =
'assets/skins/' + model.skin + '_tile_' + assetImageCode + '.png';
var scoreText = player == PieceType.black var scoreText =
? '${model.blackScore}' player == PieceType.black ? '${model.blackScore}' : '${model.whiteScore}';
: '${model.whiteScore}';
return Container( return Container(
padding: const EdgeInsets.symmetric( padding: const EdgeInsets.symmetric(
...@@ -199,7 +194,11 @@ class _GameScreenState extends State<GameScreen> { ...@@ -199,7 +194,11 @@ class _GameScreenState extends State<GameScreen> {
for (var x = 0; x < GameBoard.width; x++) { for (var x = 0; x < GameBoard.width; x++) {
PieceType pieceType = model.board.getPieceAtLocation(x, y); PieceType pieceType = model.board.getPieceAtLocation(x, y);
String? assetImageCode = Styling.assetImageCodes[pieceType]; String? assetImageCode = Styling.assetImageCodes[pieceType];
String assetImageName = 'assets/skins/' + model.skin + '_tile_' + (assetImageCode != null ? assetImageCode : 'empty') + '.png'; String assetImageName = 'assets/skins/' +
model.skin +
'_tile_' +
(assetImageCode != null ? assetImageCode : 'empty') +
'.png';
Column cell = Column( Column cell = Column(
children: [ children: [
...@@ -215,7 +214,9 @@ class _GameScreenState extends State<GameScreen> { ...@@ -215,7 +214,9 @@ class _GameScreenState extends State<GameScreen> {
child: Image( child: Image(
image: AssetImage(assetImageName), image: AssetImage(assetImageName),
fit: BoxFit.fill, fit: BoxFit.fill,
key: ValueKey<int>(pieceType == PieceType.empty ? 0 : (pieceType == PieceType.black ? 1 : 2)), key: ValueKey<int>(pieceType == PieceType.empty
? 0
: (pieceType == PieceType.black ? 1 : 2)),
), ),
), ),
onTap: () { onTap: () {
...@@ -224,7 +225,7 @@ class _GameScreenState extends State<GameScreen> { ...@@ -224,7 +225,7 @@ class _GameScreenState extends State<GameScreen> {
), ),
), ),
) )
] ],
); );
cells.add(cell); cells.add(cell);
...@@ -233,10 +234,7 @@ class _GameScreenState extends State<GameScreen> { ...@@ -233,10 +234,7 @@ class _GameScreenState extends State<GameScreen> {
rows.add(TableRow(children: cells)); rows.add(TableRow(children: cells));
} }
return Table( return Table(defaultColumnWidth: IntrinsicColumnWidth(), children: rows);
defaultColumnWidth: IntrinsicColumnWidth(),
children: rows
);
} }
Widget _buildThinkingIndicator(GameModel model) { Widget _buildThinkingIndicator(GameModel model) {
...@@ -262,25 +260,20 @@ class _GameScreenState extends State<GameScreen> { ...@@ -262,25 +260,20 @@ class _GameScreenState extends State<GameScreen> {
Widget _buildEndGameWidget(GameModel model) { Widget _buildEndGameWidget(GameModel model) {
Image decorationImage = Image( Image decorationImage = Image(
image: AssetImage( image: AssetImage(model.gameResultString == 'black'
model.gameResultString == 'black'
? 'assets/icons/game_win.png' ? 'assets/icons/game_win.png'
: 'assets/icons/empty.png' : 'assets/icons/empty.png'),
),
fit: BoxFit.fill, fit: BoxFit.fill,
); );
return Container( return Container(
margin: EdgeInsets.all(2), margin: EdgeInsets.all(2),
padding: EdgeInsets.all(2), padding: EdgeInsets.all(2),
child: Table(defaultColumnWidth: IntrinsicColumnWidth(), children: [
child: Table(
defaultColumnWidth: IntrinsicColumnWidth(),
children: [
TableRow( TableRow(
children: [ children: [
Column(children: [ decorationImage ]), Column(children: [decorationImage]),
Column(children: [ decorationImage ]), Column(children: [decorationImage]),
Column(children: [ Column(children: [
GestureDetector( GestureDetector(
onTap: () { onTap: () {
...@@ -291,13 +284,11 @@ class _GameScreenState extends State<GameScreen> { ...@@ -291,13 +284,11 @@ class _GameScreenState extends State<GameScreen> {
child: _buildRestartGameWidget(), child: _buildRestartGameWidget(),
) )
]), ]),
Column(children: [ decorationImage ]), Column(children: [decorationImage]),
Column(children: [ decorationImage ]), Column(children: [decorationImage]),
], ],
), ),
] ]));
)
);
} }
// Builds out the Widget tree using the most recent GameModel from the stream. // Builds out the Widget tree using the most recent GameModel from the stream.
...@@ -305,7 +296,7 @@ class _GameScreenState extends State<GameScreen> { ...@@ -305,7 +296,7 @@ class _GameScreenState extends State<GameScreen> {
return Scaffold( return Scaffold(
appBar: AppBar( appBar: AppBar(
actions: [ actions: [
FlatButton( TextButton(
child: Container( child: Container(
decoration: BoxDecoration( decoration: BoxDecoration(
borderRadius: BorderRadius.circular(4), borderRadius: BorderRadius.circular(4),
...@@ -317,7 +308,7 @@ class _GameScreenState extends State<GameScreen> { ...@@ -317,7 +308,7 @@ class _GameScreenState extends State<GameScreen> {
margin: EdgeInsets.all(8), margin: EdgeInsets.all(8),
child: Image( child: Image(
image: AssetImage('assets/icons/button_restart.png'), image: AssetImage('assets/icons/button_restart.png'),
fit: BoxFit.fill fit: BoxFit.fill,
), ),
), ),
onPressed: () => _restartController.add(GameModel(board: GameBoard())), onPressed: () => _restartController.add(GameModel(board: GameBoard())),
...@@ -325,7 +316,11 @@ class _GameScreenState extends State<GameScreen> { ...@@ -325,7 +316,11 @@ class _GameScreenState extends State<GameScreen> {
], ],
), ),
body: Container( body: Container(
padding: EdgeInsets.only(top: 5.0, left: 5.0, right: 5.0), padding: EdgeInsets.only(
top: 5.0,
left: 5.0,
right: 5.0,
),
decoration: Styling.mainWidgetDecoration, decoration: Styling.mainWidgetDecoration,
child: SafeArea( child: SafeArea(
child: Column( child: Column(
......
...@@ -10,8 +10,7 @@ import 'game_board.dart'; ...@@ -10,8 +10,7 @@ import 'game_board.dart';
import 'game_board_scorer.dart'; import 'game_board_scorer.dart';
class MoveSearchArgs { class MoveSearchArgs {
MoveSearchArgs( MoveSearchArgs({required this.board, required this.player, required this.numPlies});
{required this.board, required this.player, required this.numPlies});
final GameBoard board; final GameBoard board;
final PieceType player; final PieceType player;
...@@ -29,8 +28,8 @@ class ScoredMove { ...@@ -29,8 +28,8 @@ class ScoredMove {
// The [compute] function requires a top-level method as its first argument. // The [compute] function requires a top-level method as its first argument.
// This is that method for [MoveFinder]. // This is that method for [MoveFinder].
Position? _findNextMove(MoveSearchArgs args) { Position? _findNextMove(MoveSearchArgs args) {
final bestMove = _performSearchPly( final bestMove =
args.board, args.player, args.player, args.numPlies - 1); _performSearchPly(args.board, args.player, args.player, args.numPlies - 1);
return bestMove?.move; return bestMove?.move;
} }
...@@ -48,9 +47,8 @@ ScoredMove? _performSearchPly( ...@@ -48,9 +47,8 @@ ScoredMove? _performSearchPly(
return null; return null;
} }
var score = (scoringPlayer == player) var score =
? GameBoardScorer.minScore (scoringPlayer == player) ? GameBoardScorer.minScore : GameBoardScorer.maxScore;
: GameBoardScorer.maxScore;
ScoredMove? bestMove; ScoredMove? bestMove;
for (var i = 0; i < availableMoves.length; i++) { for (var i = 0; i < availableMoves.length; i++) {
...@@ -66,8 +64,7 @@ ScoredMove? _performSearchPly( ...@@ -66,8 +64,7 @@ ScoredMove? _performSearchPly(
pliesRemaining - 1, pliesRemaining - 1,
)?.score ?? )?.score ??
0; 0;
} else if (pliesRemaining > 0 && } else if (pliesRemaining > 0 && newBoard.getMovesForPlayer(player).isNotEmpty) {
newBoard.getMovesForPlayer(player).isNotEmpty) {
// Opponent has no moves; player gets another turn. // Opponent has no moves; player gets another turn.
score = _performSearchPly( score = _performSearchPly(
newBoard, newBoard,
...@@ -84,8 +81,7 @@ ScoredMove? _performSearchPly( ...@@ -84,8 +81,7 @@ ScoredMove? _performSearchPly(
if (bestMove == null || if (bestMove == null ||
(score > bestMove.score && scoringPlayer == player) || (score > bestMove.score && scoringPlayer == player) ||
(score < bestMove.score && scoringPlayer != player)) { (score < bestMove.score && scoringPlayer != player)) {
bestMove = bestMove = ScoredMove(score, Position(availableMoves[i].x, availableMoves[i].y));
ScoredMove(score, Position(availableMoves[i].x, availableMoves[i].y));
} }
} }
......
...@@ -26,9 +26,8 @@ abstract class Styling { ...@@ -26,9 +26,8 @@ abstract class Styling {
), ),
); );
static const BoxDecoration mainWidgetDecoration = BoxDecoration( static const BoxDecoration mainWidgetDecoration =
color: Color(0xffffffff) BoxDecoration(color: Color(0xffffffff));
);
static const thinkingColor = Color(0xff2196f3); static const thinkingColor = Color(0xff2196f3);
......
...@@ -26,8 +26,7 @@ class ThinkingIndicator extends ImplicitlyAnimatedWidget { ...@@ -26,8 +26,7 @@ class ThinkingIndicator extends ImplicitlyAnimatedWidget {
ImplicitlyAnimatedWidgetState createState() => _ThinkingIndicatorState(); ImplicitlyAnimatedWidgetState createState() => _ThinkingIndicatorState();
} }
class _ThinkingIndicatorState class _ThinkingIndicatorState extends AnimatedWidgetBaseState<ThinkingIndicator> {
extends AnimatedWidgetBaseState<ThinkingIndicator> {
Tween<double>? _opacityTween; Tween<double>? _opacityTween;
@override @override
...@@ -85,16 +84,16 @@ class _AnimatedCirclesState extends State<_AnimatedCircles> ...@@ -85,16 +84,16 @@ class _AnimatedCirclesState extends State<_AnimatedCircles>
@override @override
void initState() { void initState() {
super.initState(); super.initState();
_thinkingController = AnimationController( _thinkingController =
duration: const Duration(milliseconds: 500), vsync: this) AnimationController(duration: const Duration(milliseconds: 500), vsync: this)
..addStatusListener((status) { ..addStatusListener((status) {
// This bit ensures that the animation reverses course rather than // This bit ensures that the animation reverses course rather than
// stopping. // stopping.
if (status == AnimationStatus.completed) _thinkingController.reverse(); if (status == AnimationStatus.completed) _thinkingController.reverse();
if (status == AnimationStatus.dismissed) _thinkingController.forward(); if (status == AnimationStatus.dismissed) _thinkingController.forward();
}); });
_thinkingAnimation = Tween(begin: 0.0, end: widget.height).animate( _thinkingAnimation = Tween(begin: 0.0, end: widget.height)
CurvedAnimation(parent: _thinkingController, curve: Curves.easeOut)); .animate(CurvedAnimation(parent: _thinkingController, curve: Curves.easeOut));
_thinkingController.forward(); _thinkingController.forward();
} }
......
...@@ -42,14 +42,14 @@ packages: ...@@ -42,14 +42,14 @@ packages:
name: collection name: collection
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "1.15.0" version: "1.16.0"
fake_async: fake_async:
dependency: transitive dependency: transitive
description: description:
name: fake_async name: fake_async
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "1.2.0" version: "1.3.0"
ffi: ffi:
dependency: transitive dependency: transitive
description: description:
...@@ -85,7 +85,7 @@ packages: ...@@ -85,7 +85,7 @@ packages:
name: js name: js
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "0.6.3" version: "0.6.4"
matcher: matcher:
dependency: transitive dependency: transitive
description: description:
...@@ -99,7 +99,7 @@ packages: ...@@ -99,7 +99,7 @@ packages:
name: material_color_utilities name: material_color_utilities
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "0.1.3" version: "0.1.4"
meta: meta:
dependency: transitive dependency: transitive
description: description:
...@@ -120,7 +120,7 @@ packages: ...@@ -120,7 +120,7 @@ packages:
name: path name: path
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "1.8.0" version: "1.8.1"
path_provider_linux: path_provider_linux:
dependency: transitive dependency: transitive
description: description:
...@@ -237,7 +237,7 @@ packages: ...@@ -237,7 +237,7 @@ packages:
name: source_span name: source_span
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "1.8.1" version: "1.8.2"
stack_trace: stack_trace:
dependency: transitive dependency: transitive
description: description:
...@@ -272,21 +272,14 @@ packages: ...@@ -272,21 +272,14 @@ packages:
name: test_api name: test_api
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "0.4.8" version: "0.4.9"
typed_data:
dependency: transitive
description:
name: typed_data
url: "https://pub.dartlang.org"
source: hosted
version: "1.3.0"
vector_math: vector_math:
dependency: transitive dependency: transitive
description: description:
name: vector_math name: vector_math
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "2.1.1" version: "2.1.2"
win32: win32:
dependency: transitive dependency: transitive
description: description:
...@@ -302,5 +295,5 @@ packages: ...@@ -302,5 +295,5 @@ packages:
source: hosted source: hosted
version: "0.2.0+1" version: "0.2.0+1"
sdks: sdks:
dart: ">=2.15.0 <3.0.0" dart: ">=2.17.0-0 <3.0.0"
flutter: ">=2.8.0" flutter: ">=2.8.0"
// This is a basic Flutter widget test.
//
// To perform an interaction with a widget in your test, use the WidgetTester
// utility that Flutter provides. For example, you can send tap and scroll
// gestures. You can also use WidgetTester to find child widgets in the widget
// tree, read text, and verify that the values of widget properties are correct.
import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:reversi/main.dart';
void main() {
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment