Ara modificarem el programa perquè també es pugui jugar contra l'aplicació. En aquesta versió, l'aplicació posarà la seva fitxa en qualsevol posició lliure, escollida aleatòriament. La persona serà sempre el jugador 1 i el jugador 2 serà automàtic.
Crearem una variable per emmagatzemar el nombre de jugadors de la partida. Aquesta variable valdrà 0 fins que no s'hagi triat una de les dues opcions. Modificarem el botó de la versió anterior i en posarem un altre similar; aquests serviran per triar el mode de joc. Atès que els dos botons fan coses molt similars, hem creat la funció inici, per no haver-ho de repetir dos cops. Mentre duri la partida, el botó del mode triat es mantindrà en color; però no farà res.
La funció tirAuto és la que posarà les fitxes de manera automàtica. Comptarà quantes caselles buides hi ha, generarà un nombre aleatori i posarà la fitxa en la posició que correspongui.
pant_principal.dart
import 'dart:math'; 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 numJugadors = 0; // Cal esperar que es premi un botó
int jugadorActual = 0; // No hi ha jugador fins que es prem un botó
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: "1 jugador", enUs: numJugadors != 2, accio: () {
setState(() {
inici(1);
});
},),
SizedBox(
width: 20,
),
Boto(textBoto: "2 jugadors", enUs: numJugadors != 1, accio: () {
setState(() {
inici(2);
});
},)
],
),
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) && (numJugadors > 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();
// Si només hi ha un jugador, l'altre es tira automàticament
if((quiGuanya == 0) && (numJugadors == 1)){
tirAuto(jugadorActual);
if(jugadorActual == 1) {
jugadorActual = 2;
} else {
jugadorActual = 1;
}
quiGuanya = guanyador();
}
}
});
},
),
],
);
}
void inici(int numJug){
if(numJugadors == 0){
numJugadors = numJug;
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:";
}
}
void tirAuto(int jug){
int opcions = comptaCaselles(0);
int pos = Random().nextInt(opcions);
int posAct = 0;
for(int i = 0; i < 3; i++){
for(int j = 0; j < 3; j++){
if(estatCaselles[i][j] == 0){
if(posAct == pos){
estatCaselles[i][j] = jug;
}
posAct++;
}
}
}
}
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){
numJugadors = 0;
if(guanya == 3){
notificacio = "Empat!";
jugadorActual = 0;
} else {
notificacio = "Guanya:";
jugadorActual = guanya;
}
}
return guanya;
}
}
Si el sistema automàtic fa una tirada aleatòria, és fàcil guanyar-lo. En la propera versió farem servir un algorisme que intenta guanyar.

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