classic game cleanup

This commit is contained in:
Andrei Stoica 2024-12-21 08:34:49 -05:00
parent 6caec73c0d
commit c9a43f505c
2 changed files with 81 additions and 33 deletions

View File

@ -1,6 +1,7 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'state.dart'; import 'state.dart';
import 'game.dart'; import 'game.dart';
import "util.dart";
class ClassicGame extends StatefulWidget { class ClassicGame extends StatefulWidget {
const ClassicGame({super.key}); const ClassicGame({super.key});
@ -22,6 +23,8 @@ class _ClassicGameState extends State<ClassicGame> {
TTCState.empty, TTCState.empty,
TTCState.empty, TTCState.empty,
]; ];
bool ended = false;
TTCState? winner;
String get turnText => switch (turn) { String get turnText => switch (turn) {
TTCState.empty => "", TTCState.empty => "",
@ -40,7 +43,7 @@ class _ClassicGameState extends State<ClassicGame> {
Widget _invalidChoiceAlert(TTCState existingValue) { Widget _invalidChoiceAlert(TTCState existingValue) {
return Dialog( return Dialog(
child: Padding( child: Padding(
padding: EdgeInsets.all(10), padding: const EdgeInsets.all(10),
child: Column( child: Column(
mainAxisSize: MainAxisSize.min, mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.center, crossAxisAlignment: CrossAxisAlignment.center,
@ -77,10 +80,40 @@ class _ClassicGameState extends State<ClassicGame> {
setState(() { setState(() {
data[index] = turn; data[index] = turn;
winner = Util.checkWin(data);
if (winner != null && winner != TTCState.empty) {
ended = true;
}
_nextTurn(); _nextTurn();
}); });
} }
void _endedCellOnTap(int index) {
showDialog(
context: context,
builder: (context) {
return Dialog(
child: Padding(
padding: const EdgeInsets.all(10),
child: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
const Text(
"GAME OVER",
style: TextStyle(fontWeight: FontWeight.bold),
),
Text("${winner?.name.toUpperCase()} has already won"),
ElevatedButton(
onPressed: () => Navigator.pop(context),
child: const Text("Ok")),
],
),
),
);
});
}
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Column( return Column(
@ -89,13 +122,13 @@ class _ClassicGameState extends State<ClassicGame> {
const Spacer(flex: 5), const Spacer(flex: 5),
Center( Center(
child: Text( child: Text(
"$turnText's turn", !ended ? "$turnText's turn" : "${winner?.name.toUpperCase()} wins",
style: const TextStyle(fontSize: 30, fontWeight: FontWeight.bold), style: const TextStyle(fontSize: 30, fontWeight: FontWeight.bold),
)), )),
const Spacer(flex: 1), const Spacer(flex: 1),
TTCGame( TTCGame(
turn: turn, turn: turn,
cellOnTapCallback: _cellOnTap, cellOnTapCallback: !ended ? _cellOnTap : _endedCellOnTap,
data: data, data: data,
cellTextStyle: const TextStyle(fontSize: 40), cellTextStyle: const TextStyle(fontSize: 40),
), ),

View File

@ -20,6 +20,27 @@ class TTCGame extends StatelessWidget {
/// hook into end of turn cycle; /// hook into end of turn cycle;
final Function cellOnTapCallback; final Function cellOnTapCallback;
@override
Widget build(BuildContext context) {
List<Widget> cells = data
.map((state) => Text(
state != TTCState.empty ? state.name.toUpperCase() : "",
style: cellTextStyle,
))
.toList();
return GameHash(
cellOnTapCallback: cellOnTapCallback,
children: cells,
);
}
}
class GameHash extends StatelessWidget {
const GameHash({super.key, required this.children, this.cellOnTapCallback});
final List<Widget> children;
final Function? cellOnTapCallback;
Border _genCellBorder( Border _genCellBorder(
int index, { int index, {
BorderSide borderSide = const BorderSide(), BorderSide borderSide = const BorderSide(),
@ -32,52 +53,46 @@ class TTCGame extends StatelessWidget {
); );
} }
Widget _genCell(int index, TTCState state) => Container( MapEntry<int, Widget> _genCell(int index, Widget content) {
decoration: BoxDecoration(border: _genCellBorder(index)), return MapEntry(
child: TTCCell( index,
state: state, Container(
textStyle: cellTextStyle, decoration: BoxDecoration(border: _genCellBorder(index)),
stateSetCallback: () { child: HashCell(
cellOnTapCallback(index); stateSetCallback: () {
}, if (cellOnTapCallback != null) {
)); cellOnTapCallback!(index);
}
},
child: content,
),
),
);
}
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
List<Widget> cells = [];
for (final (index, state) in data.indexed) {
cells.add(_genCell(index, state));
}
return GridView.count( return GridView.count(
crossAxisCount: 3, crossAxisCount: 3,
shrinkWrap: true, shrinkWrap: true,
children: cells, children: children.asMap().map(_genCell).values.toList(),
); );
} }
} }
class TTCCell extends StatelessWidget { class HashCell extends StatelessWidget {
const TTCCell({ const HashCell({
super.key, super.key,
required this.state, required this.child,
this.stateSetCallback, this.stateSetCallback,
this.textStyle,
}); });
final TTCState state; final Widget child;
final VoidCallback? stateSetCallback; final VoidCallback? stateSetCallback;
final TextStyle? textStyle;
String get text => switch (state) {
TTCState.empty => "",
TTCState.x => "X",
TTCState.o => "O",
};
@override @override
Widget build(BuildContext context) => InkWell( Widget build(BuildContext context) => InkWell(
onTap: stateSetCallback, onTap: stateSetCallback,
child: Center( child: Center(child: child),
child: Text(text, style: textStyle), );
));
} }