mirror of
https://github.com/Earth-Genesis-Games/Ajedrez_Purgatorio.git
synced 2026-09-11 09:47:35 +00:00
- Duel flow: mating piece vs boss while board collapses (PurgatoryDuelManager/Rules/UI/MuerteQuotes) - GameState.PurgatoryDuel + CampaignManager rescue/restart hooks + SquareClick routing - Dice-based rescue of most valuable dead identity; final defeat restarts Chapter 1 - 6 SFX clips wired in Ch1/2/3 via AudioClipAssigner - OptionsMenuController runtime audio/graphics panel, wired to MainMenu - Tests migrated to Assets/Tests/EditMode subfolders + PurgatoryDuelRulesTests (200 total) - Editor tools: DiagAssign, SpeakerDatabaseSetup, PurgatoryCanvasMaintenance
317 lines
9.4 KiB
C#
317 lines
9.4 KiB
C#
using NUnit.Framework;
|
|
using UnityEngine;
|
|
using UnityEngine.TestTools;
|
|
|
|
namespace AjedrezPurgatorio.Tests.Unit.Chess
|
|
{
|
|
[TestFixture]
|
|
[Category("Unit")]
|
|
[Category("Chess")]
|
|
[Category("DrawDetector")]
|
|
[Category("FastTests")]
|
|
public class DrawDetectorTests
|
|
{
|
|
private DrawDetector _detector;
|
|
private CheckDetector _checkDetector;
|
|
private Piece[,] _board;
|
|
private GameObject _root;
|
|
|
|
[SetUp]
|
|
public void Setup()
|
|
{
|
|
_detector = new DrawDetector();
|
|
_checkDetector = new CheckDetector();
|
|
_board = new Piece[8, 8];
|
|
_root = new GameObject("TestRoot");
|
|
}
|
|
|
|
[TearDown]
|
|
public void Teardown()
|
|
{
|
|
Object.DestroyImmediate(_root);
|
|
}
|
|
|
|
private T CreatePiece<T>(int x, int y, bool isWhite) where T : Piece
|
|
{
|
|
var go = new GameObject($"Piece_{typeof(T).Name}_{x}_{y}");
|
|
go.transform.SetParent(_root.transform);
|
|
var piece = go.AddComponent<T>();
|
|
piece.currentPos = new Vector2Int(x, y);
|
|
piece.isWhite = isWhite;
|
|
piece.hasMoved = true;
|
|
_board[x, y] = piece;
|
|
return piece;
|
|
}
|
|
|
|
#region IsInsufficientMaterial Tests
|
|
|
|
[Test]
|
|
public void IsInsufficientMaterial_KingVsKing_ReturnsTrue()
|
|
{
|
|
CreatePiece<King>(4, 0, true);
|
|
CreatePiece<King>(4, 7, false);
|
|
|
|
Assert.IsTrue(_detector.IsInsufficientMaterial(_board));
|
|
}
|
|
|
|
[Test]
|
|
public void IsInsufficientMaterial_KingBishopVsKing_ReturnsTrue()
|
|
{
|
|
CreatePiece<King>(4, 0, true);
|
|
CreatePiece<Bishop>(2, 0, true);
|
|
CreatePiece<King>(4, 7, false);
|
|
|
|
Assert.IsTrue(_detector.IsInsufficientMaterial(_board));
|
|
}
|
|
|
|
[Test]
|
|
public void IsInsufficientMaterial_KingKnightVsKing_ReturnsTrue()
|
|
{
|
|
CreatePiece<King>(4, 0, true);
|
|
CreatePiece<Knight>(1, 0, true);
|
|
CreatePiece<King>(4, 7, false);
|
|
|
|
Assert.IsTrue(_detector.IsInsufficientMaterial(_board));
|
|
}
|
|
|
|
[Test]
|
|
public void IsInsufficientMaterial_KingBishopVsKingBishop_SameSquareColor_ReturnsTrue()
|
|
{
|
|
CreatePiece<King>(0, 0, true);
|
|
CreatePiece<Bishop>(2, 2, true);
|
|
CreatePiece<King>(7, 7, false);
|
|
CreatePiece<Bishop>(5, 5, false);
|
|
|
|
Assert.IsTrue(_detector.IsInsufficientMaterial(_board));
|
|
}
|
|
|
|
[Test]
|
|
public void IsInsufficientMaterial_KingBishopVsKingBishop_DifferentSquareColors_ReturnsFalse()
|
|
{
|
|
CreatePiece<King>(0, 0, true);
|
|
CreatePiece<Bishop>(2, 2, true);
|
|
CreatePiece<King>(7, 7, false);
|
|
CreatePiece<Bishop>(4, 5, false);
|
|
|
|
Assert.IsFalse(_detector.IsInsufficientMaterial(_board));
|
|
}
|
|
|
|
[Test]
|
|
public void IsInsufficientMaterial_KingRookVsKing_ReturnsFalse()
|
|
{
|
|
CreatePiece<King>(4, 0, true);
|
|
CreatePiece<Rook>(0, 0, true);
|
|
CreatePiece<King>(4, 7, false);
|
|
|
|
Assert.IsFalse(_detector.IsInsufficientMaterial(_board));
|
|
}
|
|
|
|
[Test]
|
|
public void IsInsufficientMaterial_KingQueenVsKing_ReturnsFalse()
|
|
{
|
|
CreatePiece<King>(4, 0, true);
|
|
CreatePiece<Queen>(3, 0, true);
|
|
CreatePiece<King>(4, 7, false);
|
|
|
|
Assert.IsFalse(_detector.IsInsufficientMaterial(_board));
|
|
}
|
|
|
|
[Test]
|
|
public void IsInsufficientMaterial_NullBoard_ReturnsFalse()
|
|
{
|
|
LogAssert.Expect(LogType.Error, "[DrawDetector] Board es null.");
|
|
Assert.IsFalse(_detector.IsInsufficientMaterial(null));
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region IsStalemate Tests
|
|
|
|
[Test]
|
|
public void IsStalemate_NullBoard_ReturnsFalse()
|
|
{
|
|
LogAssert.Expect(LogType.Error, "[DrawDetector] Board o checkDetector es null.");
|
|
Assert.IsFalse(_detector.IsStalemate(null, true, _checkDetector));
|
|
}
|
|
|
|
[Test]
|
|
public void IsStalemate_NullCheckDetector_ReturnsFalse()
|
|
{
|
|
LogAssert.Expect(LogType.Error, "[DrawDetector] Board o checkDetector es null.");
|
|
Assert.IsFalse(_detector.IsStalemate(_board, true, null));
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Fifty Move Rule Tests
|
|
|
|
[Test]
|
|
public void IsFiftyMoveRule_Initially_ReturnsFalse()
|
|
{
|
|
Assert.IsFalse(_detector.IsFiftyMoveRule());
|
|
}
|
|
|
|
[Test]
|
|
public void IsFiftyMoveRule_At99HalfMoves_ReturnsFalse()
|
|
{
|
|
for (int i = 0; i < 99; i++)
|
|
{
|
|
_detector.RecordMove(_board, i % 2 == 0, null, false);
|
|
}
|
|
|
|
Assert.IsFalse(_detector.IsFiftyMoveRule());
|
|
}
|
|
|
|
[Test]
|
|
public void IsFiftyMoveRule_At100HalfMoves_ReturnsTrue()
|
|
{
|
|
for (int i = 0; i < 100; i++)
|
|
{
|
|
_detector.RecordMove(_board, i % 2 == 0, null, false);
|
|
}
|
|
|
|
Assert.IsTrue(_detector.IsFiftyMoveRule());
|
|
}
|
|
|
|
[Test]
|
|
public void IsFiftyMoveRule_CaptureResetsClock()
|
|
{
|
|
for (int i = 0; i < 80; i++)
|
|
{
|
|
_detector.RecordMove(_board, i % 2 == 0, null, false);
|
|
}
|
|
|
|
var go = new GameObject();
|
|
var pawn = go.AddComponent<Pawn>();
|
|
pawn.isWhite = true;
|
|
_detector.RecordMove(_board, true, pawn, true);
|
|
|
|
Assert.Less(_detector.HalfmoveClock, 100);
|
|
Assert.IsFalse(_detector.IsFiftyMoveRule());
|
|
}
|
|
|
|
[Test]
|
|
public void IsFiftyMoveRule_PawnMoveResetsClock()
|
|
{
|
|
for (int i = 0; i < 80; i++)
|
|
{
|
|
_detector.RecordMove(_board, i % 2 == 0, null, false);
|
|
}
|
|
|
|
var go = new GameObject();
|
|
var pawn = go.AddComponent<Pawn>();
|
|
pawn.isWhite = true;
|
|
_detector.RecordMove(_board, true, pawn, false);
|
|
|
|
Assert.AreEqual(0, _detector.HalfmoveClock);
|
|
Assert.IsFalse(_detector.IsFiftyMoveRule());
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Threefold Repetition Tests
|
|
|
|
[Test]
|
|
public void IsThreefoldRepetition_Initially_ReturnsFalse()
|
|
{
|
|
Assert.IsFalse(_detector.IsThreefoldRepetition());
|
|
}
|
|
|
|
[Test]
|
|
public void IsThreefoldRepetition_SamePositionThreeTimes_ReturnsTrue()
|
|
{
|
|
var king = CreatePiece<King>(4, 0, true);
|
|
var bk = CreatePiece<King>(4, 7, false);
|
|
|
|
// Mismo turno en las tres repeticiones: el hash incluye el turno,
|
|
// así que alternar blancas/negras serían posiciones distintas.
|
|
for (int i = 0; i < 3; i++)
|
|
{
|
|
_detector.RecordMove(_board, true, king, false);
|
|
}
|
|
|
|
Assert.IsTrue(_detector.IsThreefoldRepetition());
|
|
}
|
|
|
|
[Test]
|
|
public void IsThreefoldRepetition_DifferentPositions_ReturnsFalse()
|
|
{
|
|
var king = CreatePiece<King>(4, 0, true);
|
|
var bk = CreatePiece<King>(4, 7, false);
|
|
|
|
_detector.RecordMove(_board, true, king, false);
|
|
|
|
king.currentPos = new Vector2Int(4, 1);
|
|
_board[4, 0] = null;
|
|
_board[4, 1] = king;
|
|
_detector.RecordMove(_board, false, bk, false);
|
|
|
|
king.currentPos = new Vector2Int(4, 2);
|
|
_board[4, 1] = null;
|
|
_board[4, 2] = king;
|
|
_detector.RecordMove(_board, true, king, false);
|
|
|
|
Assert.IsFalse(_detector.IsThreefoldRepetition());
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Reset Tests
|
|
|
|
[Test]
|
|
public void Reset_ClearsAllState()
|
|
{
|
|
for (int i = 0; i < 50; i++)
|
|
{
|
|
_detector.RecordMove(_board, i % 2 == 0, null, false);
|
|
}
|
|
|
|
_detector.Reset();
|
|
|
|
Assert.AreEqual(0, _detector.HalfmoveClock);
|
|
Assert.AreEqual(0, _detector.PositionHistoryCount);
|
|
Assert.IsFalse(_detector.IsFiftyMoveRule());
|
|
Assert.IsFalse(_detector.IsThreefoldRepetition());
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Position Hash Stability Tests
|
|
|
|
[Test]
|
|
public void PositionHash_SameBoardSameTurn_SameHash()
|
|
{
|
|
var king = CreatePiece<King>(4, 0, true);
|
|
var bk = CreatePiece<King>(4, 7, false);
|
|
|
|
_detector.RecordMove(_board, true, king, false);
|
|
int countAfterFirst = _detector.PositionHistoryCount;
|
|
|
|
_detector.RecordMove(_board, true, king, false);
|
|
int countAfterSecond = _detector.PositionHistoryCount;
|
|
|
|
Assert.AreEqual(2, countAfterSecond);
|
|
|
|
_detector.RecordMove(_board, true, king, false);
|
|
|
|
Assert.AreEqual(3, _detector.PositionHistoryCount);
|
|
Assert.IsTrue(_detector.IsThreefoldRepetition());
|
|
}
|
|
|
|
[Test]
|
|
public void PositionHash_DifferentTurn_DifferentHash()
|
|
{
|
|
var king = CreatePiece<King>(4, 0, true);
|
|
var bk = CreatePiece<King>(4, 7, false);
|
|
|
|
_detector.RecordMove(_board, true, king, false);
|
|
_detector.RecordMove(_board, false, bk, false);
|
|
_detector.RecordMove(_board, true, king, false);
|
|
|
|
Assert.IsFalse(_detector.IsThreefoldRepetition());
|
|
}
|
|
|
|
#endregion
|
|
}
|
|
}
|