Auto-sync: 20260324_125426

This commit is contained in:
Paolo 2026-03-24 12:58:56 +01:00
parent 4b9d4930cd
commit 1395fc32f6
7 changed files with 11423 additions and 53 deletions

BIN
.DS_Store vendored

Binary file not shown.

View file

@ -1391,7 +1391,7 @@ PODS:
- gRPC-Core/Privacy (= 1.69.0)
- gRPC-Core/Interface (1.69.0)
- gRPC-Core/Privacy (1.69.0)
- GTMSessionFetcher/Core (5.1.0)
- GTMSessionFetcher/Core (5.2.0)
- leveldb-library (1.22.6)
- nanopb (3.30910.0):
- nanopb/decode (= 3.30910.0)
@ -1501,7 +1501,7 @@ SPEC CHECKSUMS:
GoogleUtilities: 00c88b9a86066ef77f0da2fab05f65d7768ed8e1
"gRPC-C++": cc207623316fb041a7a3e774c252cf68a058b9e8
gRPC-Core: 860978b7db482de8b4f5e10677216309b5ff6330
GTMSessionFetcher: b8ab00db932816e14b0a0664a08cb73dda6d164b
GTMSessionFetcher: 904bdd2a82c635bcd6f44edf94cc8775c5d1d6e6
leveldb-library: cc8b8f8e013647a295ad3f8cd2ddf49a6f19be19
nanopb: fad817b59e0457d11a5dfbde799381cd727c1275
package_info_plus: af8e2ca6888548050f16fa2f1938db7b5a5df499

View file

@ -9,7 +9,7 @@ class _ClosureResult {
final bool closesSomething;
final int netValue;
final bool causesSwap;
final bool isIceTrap; // NUOVO: Identifica le mosse suicide sul ghiaccio
final bool isIceTrap;
_ClosureResult(this.closesSomething, this.netValue, this.causesSwap, this.isIceTrap);
}
@ -30,24 +30,30 @@ class AIEngine {
int myScore = board.currentPlayer == Player.red ? board.scoreRed : board.scoreBlue;
int oppScore = board.currentPlayer == Player.red ? board.scoreBlue : board.scoreRed;
// --- NUOVA LOGICA: GESTIONE INVERSIONE (TACTICAL FEEDING) ---
// Se c'è un numero dispari di caselle Scambio aperte, il gioco è "invertito".
// I punti accumulati andranno in regalo all'avversario!
int swapCount = board.boxes.where((b) => b.type == BoxType.swap && !b.isClosed()).length;
bool isInverted = swapCount % 2 != 0;
List<Line> goodClosingMoves = [];
List<Line> badClosingMoves = [];
List<Line> iceTraps = []; // Le mosse da evitare assolutamente
List<Line> iceTraps = [];
for (var line in availableLines) {
var result = _checkClosure(board, line);
var result = _checkClosure(board, line, isInverted);
if (result.isIceTrap) {
iceTraps.add(line); // Segna la linea come trappola e passa alla prossima
iceTraps.add(line);
continue;
}
if (result.closesSomething) {
if (result.causesSwap) {
if (myScore < oppScore) {
goodClosingMoves.add(line);
goodClosingMoves.add(line); // Se perdiamo, lo scambio è la mossa vincente!
} else {
badClosingMoves.add(line);
badClosingMoves.add(line); // Se vinciamo, NON tocchiamo lo scambio!
}
} else {
if (result.netValue >= 0) {
@ -66,10 +72,10 @@ class AIEngine {
}
}
// --- REGOLA 2: Mosse Sicure (Ora include le esche del ghiaccio!) ---
// --- REGOLA 2: Mosse Sicure ---
List<Line> safeMoves = [];
for (var line in availableLines) {
if (!badClosingMoves.contains(line) && !goodClosingMoves.contains(line) && !iceTraps.contains(line) && _isSafeMove(board, line, myScore, oppScore)) {
if (!badClosingMoves.contains(line) && !goodClosingMoves.contains(line) && !iceTraps.contains(line) && _isSafeMove(board, line, myScore, oppScore, isInverted)) {
safeMoves.add(line);
}
}
@ -92,17 +98,16 @@ class AIEngine {
}
}
// Ultima spiaggia prima del disastro: qualsiasi cosa tranne bombe e trappole ghiacciate
// Ultima spiaggia
List<Line> nonTerribleMoves = availableLines.where((l) => !badClosingMoves.contains(l) && !iceTraps.contains(l)).toList();
if (nonTerribleMoves.isNotEmpty) {
return nonTerribleMoves[random.nextInt(nonTerribleMoves.length)];
}
// Se l'IA è messa all'angolo ed è costretta a suicidarsi... pesca a caso
return availableLines[random.nextInt(availableLines.length)];
}
static _ClosureResult _checkClosure(GameBoard board, Line line) {
static _ClosureResult _checkClosure(GameBoard board, Line line, bool isInverted) {
int netValue = 0;
bool closesSomething = false;
bool causesSwap = false;
@ -120,23 +125,27 @@ class AIEngine {
if (linesCount == 4) {
if (box.type == BoxType.ice && !line.isIceCracked) {
// L'IA capisce che questa mossa non chiuderà il box, ma le farà perdere il turno.
isIceTrap = true;
} else {
closesSomething = true;
if (box.hiddenJokerOwner == board.currentPlayer) {
netValue += 2;
if (box.type == BoxType.swap) {
causesSwap = true;
} else {
if (box.type == BoxType.gold) netValue += 2;
else if (box.type == BoxType.bomb) netValue -= 1;
else if (box.type == BoxType.swap) netValue += 0;
else if (box.type == BoxType.ice) netValue += 0; // Rompere il ghiaccio vale 0 punti, ma fa rigiocare
else if (box.type == BoxType.multiplier) netValue += 1; // Leggero boost per dare priorità al x2
else netValue += 1;
}
int boxValue = 0;
if (box.hiddenJokerOwner == board.currentPlayer) {
boxValue = 2;
} else {
if (box.type == BoxType.gold) boxValue = 2;
else if (box.type == BoxType.bomb) boxValue = -1;
else if (box.type == BoxType.ice) boxValue = 0;
else if (box.type == BoxType.multiplier) boxValue = 1;
else boxValue = 1;
}
if (box.type == BoxType.swap) causesSwap = true;
// LA MAGIA: Se il gioco è invertito, fare punti positivi viene calcolato come MALUS per l'IA!
netValue += isInverted ? -boxValue : boxValue;
}
}
}
}
@ -144,7 +153,7 @@ class AIEngine {
return _ClosureResult(closesSomething, netValue, causesSwap, isIceTrap);
}
static bool _isSafeMove(GameBoard board, Line line, int myScore, int oppScore) {
static bool _isSafeMove(GameBoard board, Line line, int myScore, int oppScore, bool isInverted) {
for (var box in board.boxes) {
if (box.type == BoxType.invisible) continue;
@ -156,37 +165,35 @@ class AIEngine {
if (box.right.owner != Player.none) currentLinesCount++;
if (currentLinesCount == 2) {
// L'IA valuta cosa succede se lascia questa casella con 3 linee all'avversario
int valueForOpponent = 0;
if (box.type == BoxType.ice) {
// Il ghiaccio è la trappola perfetta. Lasciarlo con 3 linee spingerà l'avversario a incrinarlo e a perdere il turno.
// L'IA valuta questa mossa come SICURISSIMA!
valueForOpponent = -5;
} else if (box.type == BoxType.swap) {
if (myScore < oppScore) {
continue; // Sicuro lasciarlo: se lo prende perde i punti.
} else {
return false; // Pericoloso: se lo prende ci ruba il vantaggio!
}
} else if (box.hiddenJokerOwner == board.currentPlayer) {
valueForOpponent = -1;
} else {
if (box.type == BoxType.gold) valueForOpponent = 2;
else if (box.type == BoxType.bomb) valueForOpponent = -1;
else if (box.type == BoxType.swap) valueForOpponent = 0;
else if (box.type == BoxType.multiplier) valueForOpponent = 1;
else valueForOpponent = 1;
}
// Se per l'avversario è una trappola (bomba o ghiaccio), lascia pure la mossa libera
// LA MAGIA 2: Se il tabellone è invertito, regalare un punto all'avversario è un'ottima esca!
if (isInverted && box.type != BoxType.swap && box.type != BoxType.ice) {
valueForOpponent = -valueForOpponent;
}
if (valueForOpponent < 0) {
continue;
continue; // Mossa considerata sicura (trappola perfetta)
}
if (box.type == BoxType.swap) {
if (myScore < oppScore) {
continue;
} else {
return false;
}
}
return false; // La mossa regalerebbe punti, quindi NON è sicura
return false;
}
}
}

View file

@ -5,7 +5,7 @@
import 'dart:math';
enum Player { red, blue, none }
enum BoxType { normal, gold, bomb, invisible, swap, ice, multiplier } // Aggiunti ice e multiplier
enum BoxType { normal, gold, bomb, invisible, swap, ice, multiplier }
enum ArenaShape { classic, cross, donut, hourglass, chaos }
class Dot {
@ -24,7 +24,7 @@ class Line {
final Dot p2;
Player owner = Player.none;
bool isPlayable = false;
bool isIceCracked = false; // NUOVO: Stato per il blocco di ghiaccio
bool isIceCracked = false;
Line(this.p1, this.p2);
@ -55,7 +55,7 @@ class Box {
}
if (type == BoxType.gold) return 2;
if (type == BoxType.bomb) return -1;
if (type == BoxType.swap || type == BoxType.ice || type == BoxType.multiplier) return 0; // Il moltiplicatore e il ghiaccio non danno punti base
if (type == BoxType.swap || type == BoxType.ice || type == BoxType.multiplier) return 0;
return 1;
}
}
@ -80,7 +80,6 @@ class GameBoard {
Line? lastMove;
// Variabili per il Moltiplicatore
bool redHasMultiplier = false;
bool blueHasMultiplier = false;
@ -158,13 +157,23 @@ class GameBoard {
if (chance < 0.08) box.type = BoxType.gold;
else if (chance > 0.92) box.type = BoxType.bomb;
else if (level >= 5 && chance > 0.88 && chance <= 0.92) box.type = BoxType.swap;
else if (level >= 10 && chance > 0.83 && chance <= 0.88) box.type = BoxType.ice; // Nuova Scatola Ghiaccio
else if (level >= 15 && chance > 0.78 && chance <= 0.83) box.type = BoxType.multiplier; // Nuova Scatola x2
else if (level >= 10 && chance > 0.83 && chance <= 0.88) box.type = BoxType.ice;
else if (level >= 15 && chance > 0.78 && chance <= 0.83) box.type = BoxType.multiplier;
}
boxes.add(box);
}
}
// =========================================================
// NUOVO BLOCCO: ELIMINAZIONE SCAMBI PARI
// =========================================================
int swapCount = boxes.where((b) => b.type == BoxType.swap).length;
if (swapCount > 0 && swapCount % 2 == 0) {
Box lastSwap = boxes.lastWhere((b) => b.type == BoxType.swap);
lastSwap.type = BoxType.normal;
}
// =========================================================
for (var box in boxes) {
Dot tl = _getOrAddDot(box.x, box.y);
Dot tr = _getOrAddDot(box.x + 1, box.y);
@ -220,14 +229,13 @@ class GameBoard {
}
if (closesIce && !actualLine.isIceCracked) {
actualLine.isIceCracked = true; // Si incrina ma non si chiude!
actualLine.isIceCracked = true;
lastMove = actualLine;
if (forcedPlayer == null) currentPlayer = (currentPlayer == Player.red) ? Player.blue : Player.red;
else currentPlayer = (forcedPlayer == Player.red) ? Player.blue : Player.red;
return true; // Mossa valida, ma turno finito.
return true;
}
// Mossa normale o secondo colpo al ghiaccio
actualLine.isIceCracked = false;
actualLine.owner = playerMakingMove;
lastMove = actualLine;
@ -249,13 +257,12 @@ class GameBoard {
if (playerMakingMove == Player.red) redHasMultiplier = true;
else blueHasMultiplier = true;
} else if (points != 0) {
// Se la scatola chiusa punti e il giocatore ha un x2 attivo...
if (playerMakingMove == Player.red && redHasMultiplier) {
points *= 2;
redHasMultiplier = false; // Si consuma
redHasMultiplier = false;
} else if (playerMakingMove == Player.blue && blueHasMultiplier) {
points *= 2;
blueHasMultiplier = false; // Si consuma
blueHasMultiplier = false;
}
}

View file

@ -1,7 +1,7 @@
name: tetraq
description: A new Flutter project.
publish_to: 'none'
version: 1.1.7+1
version: 1.1.8+2
environment:
sdk: ^3.10.7

File diff suppressed because it is too large Load diff

54
report/codice_recap.txt Normal file
View file

@ -0,0 +1,54 @@
PROJECT_NAME=$(basename "$PWD")
TIMESTAMP=$(date +"%d-%m-%y_%H.%M")
OUTPUT_FILE="./report/${PROJECT_NAME}_${TIMESTAMP}.txt"
mkdir -p ./report && {
echo "=== FLUTTER PROJECT BACKUP ==="
echo ""
echo "=== PROJECT STRUCTURE (LIB, ASSETS & PUBLIC) ==="
find lib assets public -type f 2>/dev/null | sort
echo ""
echo "=== pubspec.yaml ==="
cat pubspec.yaml 2>/dev/null
echo ""
echo "=== MAC OS CONFIG ==="
echo "--- Info.plist ---"
cat macos/Runner/Info.plist 2>/dev/null
echo "--- Entitlements ---"
cat macos/Runner/*.entitlements 2>/dev/null
echo "--- Podfile ---"
cat macos/Podfile 2>/dev/null
echo ""
echo "=== IOS CONFIG ==="
echo "--- Info.plist ---"
cat ios/Runner/Info.plist 2>/dev/null
echo "--- Podfile ---"
cat ios/Podfile 2>/dev/null
echo ""
echo "=== ANDROID CONFIG ==="
echo "--- AndroidManifest.xml ---"
cat android/app/src/main/AndroidManifest.xml 2>/dev/null
echo "--- build.gradle / build.gradle.kts ---"
cat android/app/build.gradle 2>/dev/null
cat android/app/build.gradle.kts 2>/dev/null
echo ""
echo "=== WEB / FIREBASE (public/) ==="
find public -type f \( -name "*.html" -o -name "*.js" -o -name "*.css" -o -name "*.json" \) 2>/dev/null | sort | while read -r file; do
echo ""
echo "// ==========================================================================="
echo "// FILE: $file"
echo "// ==========================================================================="
echo ""
cat "$file"
done
echo ""
echo "=== SOURCE CODE (lib/) ==="
find lib -type f -name "*.dart" 2>/dev/null | sort | while read -r file; do
echo ""
echo "// ==========================================================================="
echo "// FILE: $file"
echo "// ==========================================================================="
echo ""
cat "$file"
done
} > "$OUTPUT_FILE" && echo "Backup completato! Artefatto salvato in: $OUTPUT_FILE"