Select Git revision
-
Benoît Harrault authoredBenoît Harrault authored
match_page.dart 7.53 KiB
import 'dart:math';
import 'package:flutter/material.dart';
import 'package:puissance4/coordinate.dart';
import 'board.dart';
import 'cpu.dart';
import 'game_chip.dart';
import 'hole_painter.dart';
enum Color {
YELLOW,
RED,
}
enum Mode {
PVP,
PVC,
DEMO,
}
class MatchPage extends StatefulWidget {
final Mode mode;
final Cpu cpu;
final Cpu cpu2;
const MatchPage({
Key key,
this.mode,
this.cpu,
this.cpu2,
}) : super(key: key);
@override
_MatchPageState createState() => _MatchPageState();
}
class _MatchPageState extends State<MatchPage> with TickerProviderStateMixin {
final board = Board();
Color turn;
Color winner;
List<List<Animation<double>>> translations = List.generate(
7,
(i) => List.generate(
7,
(i) => null,
),
);
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
elevation: 0,
),
backgroundColor: Colors.blue,
body: Padding(
padding: const EdgeInsets.all(16.0),
child: Flex(
direction: Axis.vertical,
mainAxisSize: MainAxisSize.max,
children: <Widget>[
Flexible(
flex: 2,
child: Container(
constraints: BoxConstraints.loose(
Size(
500,
532,
),
),
child: Padding(
padding: const EdgeInsets.only(top: 32.0),
child: Stack(
overflow: Overflow.clip,
fit: StackFit.loose,
children: <Widget>[
Positioned.fill(
child: Container(
color: Colors.white,
),
),
buildPieces(),
buildBoard(),
],
),
),
),
),
Flexible(
flex: 1,
child: Padding(
padding: const EdgeInsets.all(32.0),
child: winner != null
? Text(
'${winner == Color.RED ? 'RED' : 'YELLOW'} WINS',
textAlign: TextAlign.center,
style: Theme.of(context)
.textTheme
.headline6
.copyWith(color: Colors.white),
)
: Column(
children: <Widget>[
Text(
'${turn == Color.RED ? 'RED' : 'YELLOW'} SPEAKS',
textAlign: TextAlign.center,
style: Theme.of(context)
.textTheme
.headline5
.copyWith(color: Colors.white),
),
Padding(
padding: const EdgeInsets.all(8.0),
child: GameChip(color: turn),
),
_buildPlayerName(context),
],
),
),
),
],
),
),
);
}
Text _buildPlayerName(BuildContext context) {
String name;
if (widget.mode == Mode.PVC) {
if (turn == widget.cpu.color) {
name = 'CPU - ${widget.cpu.toString()}';
} else {
name = 'USER';
}
} else if (widget.mode == Mode.PVP) {
if (turn == Color.RED) {
name = 'PLAYER1';
} else {
name = 'PLAYER2';
}
} else {
if (turn == widget.cpu.color) {
name = 'CPU1 - ${widget.cpu.toString()}';
} else {
name = 'CPU2 - ${widget.cpu2.toString()}';
}
}
return Text(
name,
textAlign: TextAlign.center,
style: Theme.of(context)
.textTheme
.headline5
.copyWith(color: Colors.white),
);
}
@override
void initState() {
super.initState();
turn = widget.cpu?.otherPlayer ??
(Random().nextBool() ? Color.RED : Color.YELLOW);
if (widget.mode == Mode.PVC && turn == widget.cpu.color) {
cpuMove(widget.cpu);
} else if (widget.mode == Mode.DEMO) {
if (turn == widget.cpu.color) {
cpuMove(widget.cpu);
} else {
cpuMove(widget.cpu2);
}
}
}
GridView buildPieces() {
return GridView.custom(
padding: const EdgeInsets.all(0),
shrinkWrap: true,
physics: NeverScrollableScrollPhysics(),
gridDelegate:
SliverGridDelegateWithFixedCrossAxisCount(crossAxisCount: 7),
childrenDelegate: SliverChildBuilderDelegate(
(context, i) {
final col = i % 7;
final row = i ~/ 7;
if (board.getBox(Coordinate(col, row)) == null) {
return SizedBox();
}
return GameChip(
translation: translations[col][row],
color: board.getBox(Coordinate(col, row)),
);
},
childCount: 49,
),
);
}
GridView buildBoard() {
return GridView.custom(
padding: const EdgeInsets.all(0),
physics: NeverScrollableScrollPhysics(),
gridDelegate:
SliverGridDelegateWithFixedCrossAxisCount(crossAxisCount: 7),
shrinkWrap: true,
childrenDelegate: SliverChildBuilderDelegate(
(context, i) {
final col = i % 7;
return GestureDetector(
onTap: () {
if (winner == null) {
userMove(col);
}
},
child: CustomPaint(
size: Size(50, 50),
willChange: false,
painter: HolePainter(),
),
);
},
childCount: 49,
),
);
}
void userMove(int col) {
putChip(col);
if (winner == null && widget.mode == Mode.PVC) {
cpuMove(widget.cpu);
}
}
void cpuMove(Cpu cpu) async {
int col = await cpu.chooseCol(board);
putChip(col);
if (winner == null && widget.mode == Mode.DEMO) {
if (turn == widget.cpu.color) {
cpuMove(widget.cpu);
} else {
cpuMove(widget.cpu2);
}
}
}
void putChip(int col) {
final target = board.getColumnTarget(col);
final player = turn;
if (target == -1) {
return;
}
final controller = AnimationController(
vsync: this,
duration: Duration(seconds: 1),
)..addListener(() {
if (mounted) {
setState(() {});
}
});
if (mounted) {
setState(() {
board.setBox(Coordinate(col, target), turn);
turn = turn == Color.RED ? Color.YELLOW : Color.RED;
});
}
translations[col][target] = Tween(
begin: 0.0,
end: 1.0,
).animate(CurvedAnimation(
curve: Curves.bounceOut,
parent: controller,
))
..addStatusListener((status) {
if (status == AnimationStatus.completed) {
controller.dispose();
}
});
controller.forward().orCancel;
if (board.checkWinner(Coordinate(col, target), player)) {
showWinnerDialog(context, player);
}
}
void showWinnerDialog(BuildContext context, Color player) {
setState(() {
winner = player;
});
Future.delayed(
Duration(seconds: 5),
() => mounted ? Navigator.popUntil(context, (r) => r.isFirst) : null,
);
}
void resetBoard() {
setState(() {
winner = null;
board.reset();
});
}
}