diff --git a/lib/main.dart b/lib/main.dart index 34f2240..8f9251f 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -10,12 +10,12 @@ class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { return MaterialApp( - title: 'Flutter Demo', + title: 'Super Tic-Tac-Toe', theme: ThemeData( colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple), useMaterial3: true, ), - home: const MyHomePage(title: 'Flutter Demo Home Page'), + home: const MyHomePage(title: 'Local Tic Tac Toe'), ); } } @@ -30,19 +30,85 @@ class MyHomePage extends StatefulWidget { } class _MyHomePageState extends State { - List data = [ - TTCState.empty, - TTCState.empty, - TTCState.empty, - TTCState.empty, - TTCState.empty, - TTCState.empty, - TTCState.empty, - TTCState.empty, - TTCState.empty, - ]; - TTCState turn = TTCState.x; + late TTCGame game; + + String get turnText => switch (turn) { + TTCState.empty => "", + TTCState.x => "X", + TTCState.o => "O", + }; + + void onTurnEnd() { + setState(() { + turn = switch (turn) { + TTCState.x => TTCState.o, + TTCState.o => TTCState.x, + _ => TTCState.x + }; + }); + } + + @override + void initState() { + super.initState(); + game = TTCGame( + turn: turn, + onClick: onTurnEnd, + ); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: Text(widget.title), + backgroundColor: Theme.of(context).colorScheme.inversePrimary, + ), + body: Padding( + padding: const EdgeInsets.all(10), + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + const Spacer(flex: 5), + Center( + child: Text( + "$turnText's turn", + style: + const TextStyle(fontSize: 30, fontWeight: FontWeight.bold), + )), + const Spacer(flex: 1), + game, + const Spacer(flex: 5), + ], + )), + ); + } +} + +enum TTCState { empty, x, o } + +class TTCGame extends StatefulWidget { + const TTCGame({ + super.key, + required this.turn, + this.data, + this.onClick, + }); + + final TTCState turn; + final Function? onClick; + final List? data; + + /// hook to retrieve the turn state of the game + + @override + State createState() => _TTCGameState(); +} + +class _TTCGameState extends State { + late TTCState turn; + late List data; void setCellState(int index) { setState(() { @@ -54,19 +120,38 @@ class _MyHomePageState extends State { TTCState.empty => TTCState.empty, }; }); + widget.onClick?.call(); } Widget _genCell(int index, TTCState state) => Container( decoration: BoxDecoration(border: Border.all()), - child: Center( - child: TTCCell( + child: TTCCell( state: state, stateSetCallback: () { setCellState(index); }, - ))); + )); - Widget _genGridvew() { + @override + void initState() { + super.initState(); + turn = widget.turn; + data = widget.data ?? + [ + TTCState.empty, + TTCState.empty, + TTCState.empty, + TTCState.empty, + TTCState.empty, + TTCState.empty, + TTCState.empty, + TTCState.empty, + TTCState.empty, + ]; + } + + @override + Widget build(BuildContext context) { List cells = []; for (final (index, state) in data.indexed) { cells.add(_genCell(index, state)); @@ -77,53 +162,30 @@ class _MyHomePageState extends State { children: cells, ); } - - String _turnText(TTCState state) => switch (state) { - TTCState.x => "X", - TTCState.o => "O", - TTCState.empty => "O", - }; - - @override - Widget build(BuildContext context) { - return Scaffold( - appBar: AppBar( - backgroundColor: Theme.of(context).colorScheme.inversePrimary, - ), - body: Padding( - padding: EdgeInsets.all(10), - child: Column( - mainAxisSize: MainAxisSize.min, - children: [ - const Spacer(flex: 5), - Center( - child: Text( - "${_turnText(turn)}'s turn", - style: - const TextStyle(fontSize: 30, fontWeight: FontWeight.bold), - )), - const Spacer(flex: 1), - _genGridvew(), - const Spacer(flex: 5), - ], - )), - ); - } } -enum TTCState { empty, x, o } - class TTCCell extends StatelessWidget { - const TTCCell({super.key, required this.state, this.stateSetCallback}); + const TTCCell({ + super.key, + required this.state, + this.stateSetCallback, + this.textStyle, + }); final TTCState state; final VoidCallback? stateSetCallback; + final TextStyle? textStyle; + + String get text => switch (state) { + TTCState.empty => "", + TTCState.x => "X", + TTCState.o => "O", + }; @override - Widget build(BuildContext context) => switch (state) { - TTCState.empty => ElevatedButton( - onPressed: stateSetCallback, child: const Text("none")), - TTCState.x => const Text("X"), - TTCState.o => const Text("O"), - }; + Widget build(BuildContext context) => InkWell( + onTap: stateSetCallback, + child: Center( + child: Text(text, style: textStyle), + )); }