Skip to content
Snippets Groups Projects
Commit 4b98c7ce authored by Benoît Harrault's avatar Benoît Harrault
Browse files

First commit, init application

parent 94edb0c7
No related branches found
No related tags found
No related merge requests found
Pipeline #790 failed
import 'dart:math';
import 'package:flutter/material.dart';
import 'package:puissance4/cpu.dart';
import 'match_page.dart';
class CpuLevelPage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
elevation: 0,
),
backgroundColor: Colors.blue,
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisSize: MainAxisSize.max,
children: <Widget>[
FlatButton(
color: Colors.yellow,
child: Text(
'DUMB',
style: Theme.of(context)
.textTheme
.display2
.copyWith(color: Colors.black),
),
onPressed: () {
Navigator.pushNamed(
context,
'/match',
arguments: {
'mode': Mode.PVC,
'cpu':
DumbCpu(Random().nextBool() ? Color.RED : Color.YELLOW),
},
);
},
),
FlatButton(
color: Colors.red,
child: Text(
'HARD',
style: Theme.of(context)
.textTheme
.display2
.copyWith(color: Colors.white),
),
onPressed: () {
Navigator.pushNamed(
context,
'/match',
arguments: {
'mode': Mode.PVC,
'cpu': HarderCpu(
Random().nextBool() ? Color.RED : Color.YELLOW),
},
);
},
),
FlatButton(
color: Colors.deepPurpleAccent,
child: Text(
'HARDEST',
style: Theme.of(context)
.textTheme
.display2
.copyWith(color: Colors.white),
),
onPressed: () {
Navigator.pushNamed(
context,
'/match',
arguments: {
'mode': Mode.PVC,
'cpu': HardestCpu(
Random().nextBool() ? Color.RED : Color.YELLOW),
},
);
},
),
],
),
),
);
}
}
import 'package:flutter/material.dart';
import 'match_page.dart';
class GameChip extends StatelessWidget {
const GameChip({
Key key,
this.translation,
@required this.color,
}) : super(key: key);
final Animation<double> translation;
final Color color;
@override
Widget build(BuildContext context) {
return Center(
child: Container(
transform: Matrix4.translationValues(
0,
((translation?.value ?? 1) * 400) - 400,
0,
),
height: 40,
width: 40,
child: Material(
shape: CircleBorder(),
color: color == Color.RED ? Colors.red : Colors.yellow,
),
),
);
}
}
import 'dart:math';
import 'package:flutter/material.dart';
class HolePainter extends CustomPainter {
@override
void paint(Canvas canvas, Size size) {
final paint = Paint();
paint.color = Colors.blue;
paint.style = PaintingStyle.fill;
final center = Offset(size.height / 2, size.width / 2);
final circleBounds = Rect.fromCircle(center: center, radius: 20);
final topPath = Path()
..moveTo(-1, -1)
..lineTo(-1, (size.height / 2) + 1)
..arcTo(circleBounds, -pi, pi, false)
..lineTo(size.width + 1, (size.height / 2) + 1)
..lineTo(size.width + 1, -1)
..close();
final bottomPath = Path()
..moveTo(-1, size.height)
..lineTo(-1, (size.height / 2) - 1)
..arcTo(circleBounds, pi, -pi, false)
..lineTo(size.width + 1, (size.height / 2) - 1)
..lineTo(size.width + 1, size.height + 1)
..close();
canvas.drawPath(topPath, paint);
canvas.drawPath(bottomPath, paint);
}
@override
bool shouldRepaint(CustomPainter oldDelegate) {
return false;
}
}
import 'dart:math';
import 'package:flutter/material.dart';
import 'package:puissance4/cpu.dart';
import 'match_page.dart';
class HomePage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.blue,
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisSize: MainAxisSize.max,
children: <Widget>[
FlatButton(
color: Colors.green,
child: Text(
'VS PLAYER',
style: Theme.of(context)
.textTheme
.display2
.copyWith(color: Colors.white),
),
onPressed: () {
Navigator.pushNamed(
context,
'/match',
arguments: {
'mode': Mode.PVP,
},
);
},
),
FlatButton(
color: Colors.black,
child: Text(
'VS CPU',
style: Theme.of(context)
.textTheme
.display2
.copyWith(color: Colors.white),
),
onPressed: () {
Navigator.pushNamed(
context,
'/cpu-level',
arguments: {
'mode': Mode.PVC,
},
);
},
),
FlatButton(
color: Colors.white,
child: Text(
'DEMO',
style: Theme.of(context)
.textTheme
.display2
.copyWith(color: Colors.black),
),
onPressed: () {
final harderCpu =
HarderCpu(Random().nextBool() ? Color.RED : Color.YELLOW);
Navigator.pushNamed(
context,
'/match',
arguments: {
'mode': Mode.DEMO,
'cpu': harderCpu,
'cpu2': HardestCpu(harderCpu.otherPlayer),
},
);
},
),
],
),
),
);
}
}
import 'package:flutter/material.dart';
import 'package:puissance4/cpu_level_page.dart';
import 'package:puissance4/home_page.dart';
import 'package:puissance4/match_page.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter fiar',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: HomePage(),
onGenerateRoute: (settings) {
final args = settings.arguments as Map<String, dynamic>;
if (settings.name == '/match') {
return MaterialPageRoute(
builder: (context) => MatchPage(
mode: args['mode'],
cpu: args['cpu'],
cpu2: args['cpu2'],
),
);
} else if (settings.name == '/cpu-level') {
return MaterialPageRoute(
builder: (context) => CpuLevelPage(),
);
}
return null;
},
);
}
}
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
.display3
.copyWith(color: Colors.white),
)
: Column(
children: <Widget>[
Text(
'${turn == Color.RED ? 'RED' : 'YELLOW'} SPEAKS',
textAlign: TextAlign.center,
style: Theme.of(context)
.textTheme
.title
.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.title.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();
});
}
}
import 'package:puissance4/match_page.dart';
abstract class Player {
final Color player;
Player(this.player);
}
# Generated by pub
# See https://dart.dev/tools/pub/glossary#lockfile
packages:
async:
dependency: transitive
description:
name: async
url: "https://pub.dartlang.org"
source: hosted
version: "2.5.0"
boolean_selector:
dependency: transitive
description:
name: boolean_selector
url: "https://pub.dartlang.org"
source: hosted
version: "2.1.0"
characters:
dependency: transitive
description:
name: characters
url: "https://pub.dartlang.org"
source: hosted
version: "1.1.0"
charcode:
dependency: transitive
description:
name: charcode
url: "https://pub.dartlang.org"
source: hosted
version: "1.2.0"
clock:
dependency: transitive
description:
name: clock
url: "https://pub.dartlang.org"
source: hosted
version: "1.1.0"
collection:
dependency: transitive
description:
name: collection
url: "https://pub.dartlang.org"
source: hosted
version: "1.15.0"
fake_async:
dependency: transitive
description:
name: fake_async
url: "https://pub.dartlang.org"
source: hosted
version: "1.2.0"
flutter:
dependency: "direct main"
description: flutter
source: sdk
version: "0.0.0"
flutter_test:
dependency: "direct dev"
description: flutter
source: sdk
version: "0.0.0"
matcher:
dependency: transitive
description:
name: matcher
url: "https://pub.dartlang.org"
source: hosted
version: "0.12.10"
meta:
dependency: transitive
description:
name: meta
url: "https://pub.dartlang.org"
source: hosted
version: "1.3.0"
path:
dependency: transitive
description:
name: path
url: "https://pub.dartlang.org"
source: hosted
version: "1.8.0"
sky_engine:
dependency: transitive
description: flutter
source: sdk
version: "0.0.99"
source_span:
dependency: transitive
description:
name: source_span
url: "https://pub.dartlang.org"
source: hosted
version: "1.8.1"
stack_trace:
dependency: transitive
description:
name: stack_trace
url: "https://pub.dartlang.org"
source: hosted
version: "1.10.0"
stream_channel:
dependency: transitive
description:
name: stream_channel
url: "https://pub.dartlang.org"
source: hosted
version: "2.1.0"
string_scanner:
dependency: transitive
description:
name: string_scanner
url: "https://pub.dartlang.org"
source: hosted
version: "1.1.0"
term_glyph:
dependency: transitive
description:
name: term_glyph
url: "https://pub.dartlang.org"
source: hosted
version: "1.2.0"
test_api:
dependency: transitive
description:
name: test_api
url: "https://pub.dartlang.org"
source: hosted
version: "0.2.19"
typed_data:
dependency: transitive
description:
name: typed_data
url: "https://pub.dartlang.org"
source: hosted
version: "1.3.0"
vector_math:
dependency: transitive
description:
name: vector_math
url: "https://pub.dartlang.org"
source: hosted
version: "2.1.0"
sdks:
dart: ">=2.12.0-0.0 <3.0.0"
name: puissance4
description: puissance4
version: 1.0.0+1
environment:
sdk: ">=2.2.2 <3.0.0"
dependencies:
flutter:
sdk: flutter
dev_dependencies:
flutter_test:
sdk: flutter
flutter:
uses-material-design: true
web/icons/Icon-192.png

5.23 KiB

web/icons/Icon-512.png

17.2 KiB

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta content="IE=Edge" http-equiv="X-UA-Compatible">
<meta name="description" content="A new Flutter project.">
<!-- iOS meta tags & icons -->
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-status-bar-style" content="black">
<meta name="apple-mobile-web-app-title" content="puissance4">
<link rel="apple-touch-icon" href="/icons/Icon-192.png">
<title>puissance4</title>
<link rel="manifest" href="/manifest.json">
</head>
<body>
<!-- This script installs service_worker.js to provide PWA functionality to
application. For more information, see:
https://developers.google.com/web/fundamentals/primers/service-workers -->
<script>
if ('serviceWorker' in navigator) {
window.addEventListener('load', function () {
navigator.serviceWorker.register('/flutter_service_worker.js');
});
}
</script>
<script src="main.dart.js" type="application/javascript"></script>
</body>
</html>
{
"name": "puissance4",
"short_name": "puissance4",
"start_url": ".",
"display": "minimal-ui",
"background_color": "#0175C2",
"theme_color": "#0175C2",
"description": "puissance4",
"orientation": "portrait-primary",
"prefer_related_applications": false,
"icons": [
{
"src": "icons/Icon-192.png",
"sizes": "192x192",
"type": "image/png"
},
{
"src": "icons/Icon-512.png",
"sizes": "512x512",
"type": "image/png"
}
]
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment