import 'package:flutter/material.dart'; //import 'package:logger/logger.dart'; //final logger = Logger(); import 'dart:io'; class MyLogger { void d(String output, {String method = ""}) { stdout.write(DateTime.now()); if (method.isNotEmpty) { stdout.write(" - $method"); } debugPrint(": $output"); } } final logger = MyLogger(); void main() { runApp(const MainApp()); } class MainApp extends StatelessWidget { const MainApp({super.key}); @override Widget build(BuildContext context) { return const MaterialApp(home: Scaffold(body: GameBoard())); } } class GameBoard extends StatefulWidget { const GameBoard({super.key}); @override State createState() => _GameBoardState(); } class _GameBoardState extends State { var text = "hello test lalala"; List _BOARD = []; void updateBoard(List board) { setState(() { _BOARD = board; }); } final _myGlobalKey = GlobalKey(); @override Widget build(BuildContext context) { logger.d(method: "GameBoard.build", "Rebuilding everything."); return Row( key: _myGlobalKey, mainAxisAlignment: MainAxisAlignment.center, crossAxisAlignment: CrossAxisAlignment.center, children: [ // Player 1 Goal Column( children: [Center(child: PlayerSpot(spot: 0, board: _BOARD))], ), // Center holes Column( //spacing: 2, children: [ Row( //spacing: 2, mainAxisAlignment: MainAxisAlignment.center, crossAxisAlignment: CrossAxisAlignment.center, children: [ Column( children: [ BoardSpot( spot: 13, board: _BOARD, boardUpdate: updateBoard, ), ], ), Column( children: [ BoardSpot( spot: 12, board: _BOARD, boardUpdate: updateBoard, ), ], ), Column( children: [ BoardSpot( spot: 11, board: _BOARD, boardUpdate: updateBoard, ), ], ), Column( children: [ BoardSpot( spot: 10, board: _BOARD, boardUpdate: updateBoard, ), ], ), Column( children: [ BoardSpot( spot: 09, board: _BOARD, boardUpdate: updateBoard, ), ], ), Column( children: [ BoardSpot( spot: 08, board: _BOARD, boardUpdate: updateBoard, ), ], ), ], ), Row( //spacing: 2, mainAxisAlignment: MainAxisAlignment.center, crossAxisAlignment: CrossAxisAlignment.center, children: [ Column( children: [ BoardSpot( spot: 01, board: _BOARD, boardUpdate: updateBoard, ), ], ), Column( children: [ BoardSpot( spot: 02, board: _BOARD, boardUpdate: updateBoard, ), ], ), Column( children: [ BoardSpot( spot: 03, board: _BOARD, boardUpdate: updateBoard, ), ], ), Column( children: [ BoardSpot( spot: 04, board: _BOARD, boardUpdate: updateBoard, ), ], ), Column( children: [ BoardSpot( spot: 05, board: _BOARD, boardUpdate: updateBoard, ), ], ), Column( children: [ BoardSpot( spot: 06, board: _BOARD, boardUpdate: updateBoard, ), ], ), ], ), Text(text), TextButton( onPressed: () { setState(() { _BOARD = gameReset(_BOARD); }); }, child: Text("Reset"), ), TextButton( onPressed: () { setState(() { _BOARD = _BOARD; logger.d(method: "Refresh", "Refreshed!"); }); }, child: Text("Refresh"), ), ], ), // Player 2 Goal Column( children: [Center(child: PlayerSpot(spot: 07, board: _BOARD))], ), ], ); } } class BoardSpot extends StatefulWidget { final int spot; final List board; final double w; final double h; final ValueChanged>? boardUpdate; BoardSpot({ super.key, required this.board, required this.spot, required this.boardUpdate, this.w = 50, this.h = 50, }); @override State createState() => _BoardSpotState(); } class _BoardSpotState extends State { List BOARD = []; int _spot = -1; @override void initState() { BOARD = widget.board; setState(() { if (BOARD.isEmpty) { BOARD = gameReset(BOARD); } }); _spot = widget.spot; super.initState(); } void _playBoardSpot() { logger.d(method: "_playBoardSpot", "Playing spot '$_spot'"); setState(() { logger.d(method: "_playBoardSpot", "Inside setState()"); if (BOARD[_spot].toString() == "Reset") { BOARD = gameReset(BOARD); } else { BOARD = gameTurn(BOARD, _spot); } }); } @override Widget build(BuildContext context) { return SizedBox( width: widget.w, height: widget.h, child: TextButton( onPressed: _playBoardSpot, child: Center( child: Text(BOARD[_spot].toString(), textAlign: TextAlign.center), ), ), ); } } class PlayerSpot extends StatefulWidget { final int spot; final List board; PlayerSpot({super.key, required this.board, required this.spot}); @override State createState() => _PlayerSpotState(); } class _PlayerSpotState extends State { int _spot = -2; @override void initState() { _spot = widget.spot; super.initState(); } @override Widget build(BuildContext context) { return BoardSpot( w: 50, h: 100, spot: _spot, board: widget.board, boardUpdate: null, ); } } /* Gameplay Implementation Notes (2026-05-06) Initial thought is to have an array for all the holes, a method to tell which hole is being played, and a mnethod which gets passed the "next step" while the previous loops over the number of marbles. The next step one will call anther method which checks if the player hole needs to be filled or not, and it knows based on globl variables like who's turn it is and whether spot 5 or 11 are being played in the index (0-11, not 1-12). So, if the board was like this: 11 10 09 08 07 06 00 01 02 03 04 05 Bottom chooses 02 which passes (spot: 02, marbles:4) to Method1. If the player is Bottom, and the spot just went from 6 -> 7, give them a point and marble--. if the player is Top, and the spot just went from 11 -> 00, "". Soo... Method1 says while marbles > 0, check if player needs rearded, spot++, Method2(spot % 12), marbles--; Mathod2 simply adds a marble to the spot. Method3 simply adds a marble to the player's hole. Pseudo code... playMove (int spot, int marbles, bool topPlayer) { marbleReduce(spot, marbles) whie marbles > 0 { if (spot == 6 && !boolTopPlayerTurn) { rewardPlayer(boolTopPlayerTurn) marbles--; } else if (spot == 11 && boolTopPlayerTurn) { rewardPlayer(boolTopPlayerTurn) marbles-- } if (marbles == 0) { return; } spot++; addMarble(spot); marble--; } } marbleAdd (int: spot) { BOARD[spot]++; } marbleReward (bool boolTopPlayer, int marbles) { if (boolTopPlayer) { SCORE[0] += marbles; } else { SCORE[1] += marbles; } } Oh, also need too remove the marbles from the originally called spot befpre the while loop! marbleRemove (int spot, int marbles) { // This should always be taking it down to 0, but doing the math anyways // just t make sure nothing wonky is going on, like 4 being removed then // 5 being moved across the board or something. Which would likely be unrelated // code elsewhere, but oh well. BOARD[spot] -= marbles; } */ List gameTurn(List board, int spot) { if (board.isEmpty) { board = gameReset(board); } int marbles = board[spot]; logger.d(method: "gameTurn", "spot = $spot, marbles = $marbles"); if (spot == 00 || spot == 07) { logger.d(method: "gameTurn", "RETURN: Cannot play a player spot!"); return board; } if (marbles == 0) { logger.d(method: "gameTurn", "RETURN: Cannot play an empty hole!"); return board; } if ((boolTopPlayerTurn && spot <= 06) || (!boolTopPlayerTurn && spot >= 07)) { logger.d("Not this player's turn, try again."); return board; } board = marbleRemove(board, spot % 14); while (marbles > 0) { if (spot == 06 && !boolTopPlayerTurn) { board[07]++; marbles--; spot++; } else if (spot == 13 && boolTopPlayerTurn) { board[00]++; marbles--; spot++; } if (marbles == 0) { logger.d( method: "gameTurn", "Landed in player hole, go again! board = $board", ); return board; } spot++; board = marbleAdd(board, spot % 14); marbles--; } // TODO: Check if this is the only marble in the hole, and if it's on the player's side, and if so, steal all the marbles on the opposite side. if (board[spot % 14] == 1 && ((boolTopPlayerTurn && spot >= 7) || (!boolTopPlayerTurn && spot <= 6))) { // Spot 00 steals 11, 01 steals 10, ... 05 steals 06. // This is a function of (spot_to_check = 11 - spot) // Changed to 14 spots, so now using 13 rather than 11. int spotToCheck = 13 - spot; int theft = board[spotToCheck % 14]; if (boolTopPlayerTurn) { board[00] += theft; } else { board[07] += theft; } board = marbleRemove(board, spotToCheck % 14); } boolTopPlayerTurn = !boolTopPlayerTurn; logger.d(method: "gameTurn", "Finished, board = $board"); return board; } bool boolTopPlayerTurn = false; /* * / void gameReset() { logger.d(method: "gameReset", "Started"); BOARD = []; for (int i = 0; i < 12; i++) { BOARD.add(4); } logger.d(method: "gameReset", "Finished"); } // */ List gameReset(List BOARD) { logger.d(method: "gameReset", "Started, BOARD = $BOARD"); BOARD = []; for (int i = 0; i < 14; i++) { BOARD.add(4); } BOARD[00] = 0; BOARD[07] = 0; logger.d(method: "gameReset", "Finished, BOARD = $BOARD"); return BOARD; } List marbleAdd(List BOARD, int spot) { logger.d(method: "marbleAdd[spot=$spot]", "Started"); BOARD[spot]++; logger.d(method: "marbleAdd[spot=$spot]", "Finished"); return BOARD; } /* * / void marbleReward(bool boolTopPlayer, int marbles) { logger.d(method: "marbleReward[$boolTopPlayer, $marbles]", "Started"); if (boolTopPlayer) { SCORE[0] += marbles; } else { SCORE[1] += marbles; } logger.d(method: "marbleReward[$boolTopPlayer, $marbles]", "Finished"); } // */ List marbleRemove(List BOARD, int spot) { logger.d(method: "marbleRemove", "Started"); BOARD[spot] = 0; logger.d(method: "marbleRemove", "Finished"); return BOARD; } /* * / class ButtonReset extends StatelessWidget { @override Widget build(BuildContext context) { return BoardSpot(w: 50, h: 100, text: 'Reset', spot: 50); } } // */