Per completar l'aplicació per a dos jugadors, ens caldria alguna forma per tornar a començar un cop s'acaba la partida. Afegirem una filera sobre del text, on posarem un botó que permeti tornar a començar.
Definirem un botó genèric, que podrem personalitzar; així més endavant podrem afegir, si cal, algun botó més. El fitxer del botó anirà a la carpeta components. El botó tindrà tres paràmetres: el text que es mostra, un que controla si està en ús i la funció que s'executa quan es prem. El botó tindrà colors diferents segons si està en ús o no.
boto.dart
import 'package:flutter/material.dart'; import 'package:tres_linia/core/colors.dart'; import 'package:tres_linia/core/estils.dart';
class Boto extends StatefulWidget {
final String textBoto;
final bool enUs;
final Function accio;
const Boto({super.key, required this.textBoto,
required this.enUs, required this.accio});
@override
State<Boto> createState() => _BotoState();
}
class _BotoState extends State<Boto> {
@override
Widget build(BuildContext context) {
return GestureDetector(
onTap: () {
setState(() {
widget.accio();
});
},
child: Container(
alignment: Alignment.center,
decoration: BoxDecoration(
color: widget.enUs ? ColorsApp.botoEnUs : ColorsApp.botoBlocat,
borderRadius: BorderRadius.circular(12),
),
child: Padding(
padding: const EdgeInsets.all(10.0),
child: Text(widget.textBoto, style: Estils.estilTextBotons),
),
),
);
}
}
Hem d'afegir els estils i colors que fem servir en el botó.
colors.dart
import 'dart:ui';
class ColorsApp {
static const Color fons = Color(0xFF000000);
static const Color primari = Color(0xFF444444);
static const Color text = Color(0xFFFFFFFF);
static const Color component = Color(0xFF531C00);
static const Color botoEnUs = Color(0xFF008000);
static const Color botoBlocat = Color(0xFF808080);
static const List<Color> colsFitxes = [
Color(0x00FFFFFF), // transparent
Color(0xFF00FFFF), // cian
Color(0xFFFFFF00), // groc
];
}
estils.dart
import 'package:flutter/material.dart'; import 'package:tres_linia/core/colors.dart';
class Estils {
static const TextStyle estilTextInfo = TextStyle(
color: ColorsApp.text,
fontSize: 30,
fontWeight: FontWeight.bold,
);
static const TextStyle estilTextBotons = TextStyle(
color: ColorsApp.text,
fontSize: 20,
fontWeight: FontWeight.bold,
);
}
A la pantalla principal hi afegim la filera amb el botó.
pant_principal.dart
import 'package:flutter/material.dart'; import 'package:tres_linia/components/boto.dart'; import 'package:tres_linia/components/casella.dart'; import 'package:tres_linia/components/fitxa.dart'; import 'package:tres_linia/core/estils.dart';
class PantPral extends StatefulWidget {
const PantPral({super.key});
@override
State<PantPral> createState() => _PantPralState();
}
class _PantPralState extends State<PantPral> {
List<List<int>> estatCaselles = [[0, 0, 0], [0, 0, 0], [0, 0, 0]];
int jugadorActual = 1; // Comença el jugador 1
int quiGuanya = 0; // De moment, no hi ha guanyador
String notificacio = "Tira:";
@override
Widget build(BuildContext context) {
return Column(
children: [
SizedBox(
height: 20,
),
Row(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Boto(textBoto: "Iniciar", enUs: quiGuanya > 0, accio: () {
setState(() {
if(quiGuanya > 0){
estatCaselles = [[0, 0, 0], [0, 0, 0], [0, 0, 0]];
jugadorActual = 1; // Comença el jugador 1
quiGuanya = 0; // De moment, no hi ha guanyador
notificacio = "Tira:";
}
});
},)
],
),
SizedBox(
height: 20,
),
Row(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Text(
notificacio,
style: Estils.estilTextInfo
),
SizedBox(
width: 20,
),
Fitxa(estatAct: jugadorActual, mida: 25)
],
),
for(int i = 0; i < 3; i++) filera(i),
Expanded(child: Text(" "))
],
);
}
Row filera(int pY) {
return Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
crossAxisAlignment: CrossAxisAlignment.end,
children: [
for(int i = 0; i < 3; i++) Casella(posX: i, posY: pY, estAct: estatCaselles[pY][i],
posaFitxa: () {
setState(() {
// L'acció de picar la casella només es fa si la partida està en curs
if(quiGuanya == 0){
if(estatCaselles[pY][i] == 0) {
estatCaselles[pY][i] = jugadorActual;
if(jugadorActual == 1) {
jugadorActual = 2;
} else {
jugadorActual = 1;
}
}
// Després de cada tirada, mirem si hi ha guanyador
quiGuanya = guanyador();
}
});
},
),
],
);
}
int comptaCaselles(int val){
// Compta les caselles que tenen un determinat valor
int total = 0;
for(int i = 0; i < 3; i++){
for(int j = 0; j < 3; j++){
if(estatCaselles[i][j] == val){
total++;
}
}
}
return total;
}
int guanyador(){
int guanya = 0;
// Atès que només s'afegeix una fitxa cada cop, només hi pot haver un guanyador
// Primer mirem les diagonals
if((estatCaselles[0][0] != 0) && (estatCaselles[0][0] == estatCaselles[1][1])
&& (estatCaselles[0][0] == estatCaselles[2][2])){
guanya = estatCaselles[0][0];
}
if((estatCaselles[0][2] != 0) && (estatCaselles[0][2] == estatCaselles[1][1])
&& (estatCaselles[0][2] == estatCaselles[2][0])){
guanya = estatCaselles[0][2];
}
// Mirem fileres i columnes
for(int i = 0; i < 3; i++){
if((estatCaselles[i][0] != 0) && (estatCaselles[i][0] == estatCaselles[i][1])
&& (estatCaselles[i][0] == estatCaselles[i][2])){
guanya = estatCaselles[i][0];
}
}
for(int i = 0; i < 3; i++){
if((estatCaselles[0][i] != 0) && (estatCaselles[0][i] == estatCaselles[1][i])
&& (estatCaselles[0][i] == estatCaselles[2][i])){
guanya = estatCaselles[0][i];
}
}
// Si no hi ha guanyador, mirem si el taulell ja és ple
// Si ho és, hi ha empat
if((guanya == 0) && (comptaCaselles(0) == 0)){
guanya = 3;
}
// S'acaba la partida si hi ha guanyador o no hi ha caselles
// Es posa com a jugador al guanyador, per mostrar-lo
// En cas d'empat, es deixa buit
if(guanya > 0){
if(guanya == 3){
notificacio = "Empat!";
jugadorActual = 0;
} else {
notificacio = "Guanya:";
jugadorActual = guanya;
}
}
return guanya;
}
}

Aquesta obra d'Oriol Boix està llicenciada sota una llicència no importada Reconeixement-NoComercial-SenseObraDerivada 3.0.