generated from me/template-mit
325 lines
9.0 KiB
Dart
325 lines
9.0 KiB
Dart
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");
|
|
}
|
|
print(": $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 StatelessWidget {
|
|
const GameBoard({super.key});
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
gameReset();
|
|
var text = "hello test lalala";
|
|
return Row(
|
|
mainAxisAlignment: MainAxisAlignment.center,
|
|
crossAxisAlignment: CrossAxisAlignment.center,
|
|
children: [
|
|
// Player 1 Goal
|
|
Column(
|
|
children: [Center(child: PlayerSpot(text: SCORE[0].toString()))],
|
|
),
|
|
// Center holes
|
|
Column(
|
|
//spacing: 2,
|
|
children: [
|
|
Row(
|
|
//spacing: 2,
|
|
mainAxisAlignment: MainAxisAlignment.center,
|
|
crossAxisAlignment: CrossAxisAlignment.center,
|
|
children: [
|
|
Column(
|
|
children: [BoardSpot(spot: 11, text: BOARD[11].toString())],
|
|
),
|
|
Column(
|
|
children: [BoardSpot(spot: 10, text: BOARD[10].toString())],
|
|
),
|
|
Column(
|
|
children: [BoardSpot(spot: 09, text: BOARD[09].toString())],
|
|
),
|
|
Column(
|
|
children: [BoardSpot(spot: 08, text: BOARD[08].toString())],
|
|
),
|
|
Column(
|
|
children: [BoardSpot(spot: 07, text: BOARD[07].toString())],
|
|
),
|
|
Column(
|
|
children: [BoardSpot(spot: 06, text: BOARD[06].toString())],
|
|
),
|
|
],
|
|
),
|
|
Row(
|
|
//spacing: 2,
|
|
mainAxisAlignment: MainAxisAlignment.center,
|
|
crossAxisAlignment: CrossAxisAlignment.center,
|
|
children: [
|
|
Column(
|
|
children: [BoardSpot(spot: 00, text: BOARD[00].toString())],
|
|
),
|
|
Column(
|
|
children: [BoardSpot(spot: 01, text: BOARD[01].toString())],
|
|
),
|
|
Column(
|
|
children: [BoardSpot(spot: 02, text: BOARD[02].toString())],
|
|
),
|
|
Column(
|
|
children: [BoardSpot(spot: 03, text: BOARD[03].toString())],
|
|
),
|
|
Column(
|
|
children: [BoardSpot(spot: 04, text: BOARD[04].toString())],
|
|
),
|
|
Column(
|
|
children: [BoardSpot(spot: 05, text: BOARD[05].toString())],
|
|
),
|
|
],
|
|
),
|
|
Text(text),
|
|
ButtonReset(),
|
|
],
|
|
),
|
|
// Player 2 Goal
|
|
Column(
|
|
children: [Center(child: PlayerSpot(text: SCORE[1].toString()))],
|
|
),
|
|
],
|
|
);
|
|
}
|
|
}
|
|
|
|
class BoardSpot extends StatefulWidget {
|
|
final String text;
|
|
final int spot;
|
|
final double w;
|
|
final double h;
|
|
|
|
BoardSpot({
|
|
super.key,
|
|
required this.text,
|
|
required this.spot,
|
|
this.w = 50,
|
|
this.h = 50,
|
|
});
|
|
|
|
@override
|
|
State<BoardSpot> createState() => _BoardSpotState();
|
|
}
|
|
|
|
class _BoardSpotState extends State<BoardSpot> {
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
return GestureDetector(
|
|
// 2. Handle the tap
|
|
onTap: () {
|
|
// 3. Update the state
|
|
setState(() {
|
|
if (widget.text == "Reset") {
|
|
gameReset();
|
|
}
|
|
if (widget.spot >= 12) {
|
|
null;
|
|
} else {
|
|
gameTurn(widget.spot, BOARD[widget.spot]);
|
|
}
|
|
});
|
|
},
|
|
// 4. The sized box containing the text
|
|
child: SizedBox(
|
|
width: widget.w,
|
|
height: widget.h,
|
|
child: Center(child: Text(widget.text, textAlign: TextAlign.center)),
|
|
),
|
|
);
|
|
}
|
|
}
|
|
|
|
class PlayerSpot extends StatelessWidget {
|
|
final String text;
|
|
|
|
PlayerSpot({super.key, required this.text});
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
return BoardSpot(w: 50, h: 100, text: text, spot: 50);
|
|
}
|
|
}
|
|
|
|
/* 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 removve 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;
|
|
}
|
|
*/
|
|
|
|
void gameTurn(int spot, int marbles) {
|
|
logger.d(method: "gameTurn", "spot = $spot, marbles = $marbles");
|
|
if ((boolTopPlayerTurn && spot <= 5) || (!boolTopPlayerTurn && spot >= 6)) {
|
|
logger.d("Not this player's turn, try again.");
|
|
return;
|
|
}
|
|
marbleRemove(spot, marbles);
|
|
while (marbles > 0) {
|
|
if (spot == 5 && !boolTopPlayerTurn) {
|
|
marbleReward(boolTopPlayerTurn, 1);
|
|
marbles--;
|
|
} else if (spot == 11 && boolTopPlayerTurn) {
|
|
marbleReward(boolTopPlayerTurn, 1);
|
|
marbles--;
|
|
}
|
|
if (marbles == 0) {
|
|
logger.d(
|
|
method: "gameTurn",
|
|
"Landed in player hole, go again! board = $BOARD, score = $SCORE",
|
|
);
|
|
return;
|
|
}
|
|
|
|
spot++;
|
|
marbleAdd(spot % 12);
|
|
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 % 12] == 1 &&
|
|
((boolTopPlayerTurn && spot >= 6) || (!boolTopPlayerTurn && spot <= 5))) {
|
|
// Spot 00 steals 11, 01 steals 10, ... 05 steals 06.
|
|
// This is a function of (spot_to_check = 11 - spot)
|
|
int spotToCheck = 11 - spot;
|
|
int theft = BOARD[spotToCheck];
|
|
marbleReward(boolTopPlayerTurn, theft);
|
|
marbleRemove(spotToCheck, marbles);
|
|
}
|
|
|
|
boolTopPlayerTurn = !boolTopPlayerTurn;
|
|
logger.d(method: "gameTurn", "Finished, board = $BOARD, score = $SCORE");
|
|
}
|
|
|
|
List<int> BOARD = [];
|
|
List<int> SCORE = [];
|
|
bool boolTopPlayerTurn = false;
|
|
|
|
void gameReset() {
|
|
logger.d(method: "gameReset", "Started");
|
|
BOARD = [];
|
|
for (int i = 0; i < 12; i++) {
|
|
BOARD.add(4);
|
|
}
|
|
SCORE = [0, 0];
|
|
logger.d(method: "gameReset", "Finished");
|
|
}
|
|
|
|
void marbleAdd(int spot) {
|
|
logger.d(method: "marbleAdd[spot=$spot]", "Started");
|
|
BOARD[spot]++;
|
|
logger.d(method: "marbleAdd[spot=$spot]", "Finished");
|
|
}
|
|
|
|
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");
|
|
}
|
|
|
|
void marbleRemove(int spot, int marbles) {
|
|
logger.d(method: "marbleRemove", "Started");
|
|
// 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;
|
|
logger.d(method: "marbleRemove", "Finished");
|
|
}
|
|
|
|
class ButtonReset extends StatelessWidget {
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
return BoardSpot(w: 50, h: 100, text: 'Reset', spot: 50);
|
|
}
|
|
}
|