112 lines
7.8 KiB
C#
112 lines
7.8 KiB
C#
using System;
|
|
using System.Linq;
|
|
using MagnetismHeroes.Core;
|
|
using MagnetismHeroes.UnityRuntime.StageAssets;
|
|
using NUnit.Framework;
|
|
using UnityEditor;
|
|
|
|
namespace MagnetismHeroes.Tests
|
|
{
|
|
public sealed class ContentSessionTests
|
|
{
|
|
private sealed class Store : IProgressStore
|
|
{
|
|
public ProgressSave Saved = new ProgressSave();
|
|
public bool TryLoad(out ProgressSave save, out string error) { save = Saved; error = null; return true; }
|
|
public bool TrySave(ProgressSave save, out string error) { Saved = save; error = null; return true; }
|
|
}
|
|
private static StageDefinition[] Definitions() => Enumerable.Range(1,30).Select(id =>
|
|
AssetDatabase.LoadAssetAtPath<StageAsset>($"Assets/MagnetismHeroes/UnityRuntime/StageAssets/Stage{id:D2}.asset").ToDefinition()).ToArray();
|
|
private static void Apply(GameSession session, BoardHint hint)
|
|
{
|
|
Assert.That(hint, Is.Not.Null);
|
|
RuleResult result;
|
|
switch (hint.Kind)
|
|
{
|
|
case HintKind.Collect: result = session.MoveGroup(hint.FirstGroupId, new Position3(.1f,0,0)); break;
|
|
case HintKind.Count: result = session.Count(hint.BallIds[0]); break;
|
|
case HintKind.Merge: result = session.MoveAndMerge(hint.FirstGroupId, new Position3(.1f,0,0), hint.SecondGroupId); break;
|
|
default: result = session.SplitAndMove(hint.FirstGroupId, hint.BallIds, "hint-split-" + Guid.NewGuid().ToString("N"), new Position3(1,0,0)); break;
|
|
}
|
|
Assert.That(result.Accepted, Is.True, result.Reason.ToString());
|
|
}
|
|
[Test] public void FreshSaveSolvesAllThirtyThroughActualCoreCallsUnlocksNextAndNeverThirtyOne()
|
|
{
|
|
var definitions = Definitions(); var store = new Store(); var session = new GameSession(definitions, store);
|
|
Assert.That(Enumerable.Range(1,30).Where(session.IsUnlocked), Is.EqualTo(new[] {1}));
|
|
for (int id = 1; id <= 30; id++)
|
|
{
|
|
if (id == 1) Assert.That(session.StartStage(id), Is.True);
|
|
else Assert.That(session.StartNextStage(), Is.True);
|
|
Assert.That(session.Board.StageId, Is.EqualTo(id));
|
|
for (int step = 0; session.Screen == SessionScreen.Puzzle && step < 40; step++)
|
|
{
|
|
var before = UnityEngine.JsonUtility.ToJson(store.Saved); var ids = session.Board.Balls.Select(ball => ball.id).ToArray();
|
|
var hint = session.Hint;
|
|
Assert.That(UnityEngine.JsonUtility.ToJson(store.Saved), Is.EqualTo(before), "Help is read-only.");
|
|
Apply(session, hint); Assert.That(session.Board.Balls.Select(ball => ball.id), Is.EqualTo(ids));
|
|
}
|
|
Assert.That(session.Screen, Is.EqualTo(SessionScreen.FreePlay), $"Stage {id}");
|
|
Assert.That(store.Saved.completedStageIds, Is.EqualTo(Enumerable.Range(1,id)));
|
|
Assert.That(session.HasNextStage, Is.EqualTo(id < 30));
|
|
Assert.That(store.Saved.latestFreePlay.sourceStageId, Is.EqualTo(id));
|
|
session = new GameSession(definitions, store); Assert.That(session.ContinueFreePlay(), Is.True);
|
|
}
|
|
Assert.That(session.IsUnlocked(31), Is.False); Assert.That(session.StartNextStage(), Is.False); Assert.That(session.StartStage(31), Is.False);
|
|
Assert.That(session.StartStage(6), Is.True); session.MoveGroup(session.Board.Groups[0].id, new Position3(.2f,0,0)); session.ShowHome();
|
|
Assert.That(store.Saved.completedStageIds, Is.EqualTo(Enumerable.Range(1,30))); Assert.That(session.IsUnlocked(30), Is.True);
|
|
Assert.That(session.StartStage(6), Is.True); Assert.That(session.Board.Balls[0].position.x, Is.EqualTo(definitions[5].BallPositions[0].x+.2f));
|
|
}
|
|
[Test] public void NextPrefersSavedPuzzleAndHelpRecoversFromAlternativeDisconnectedPartitions()
|
|
{
|
|
var definitions = Definitions(); var store = new Store { Saved = new ProgressSave { completedStageIds = Enumerable.Range(1,29).ToArray() } };
|
|
var session = new GameSession(definitions,store); Assert.That(session.StartStage(30), Is.True);
|
|
var group = session.Board.Groups[0]; session.SplitAndMove(group.id,new[] {group.ballIds[0],group.ballIds[2]},"alternative",new Position3(0,2,0));
|
|
session.CommitCamera(new CameraState { distance=12 }); session.ShowHome();
|
|
Assert.That(session.StartStage(29), Is.True);
|
|
for (int i=0; session.Screen==SessionScreen.Puzzle && i<30; i++) Apply(session,session.Hint);
|
|
Assert.That(session.StartNextStage(), Is.True); Assert.That(session.Camera.distance, Is.EqualTo(12));
|
|
Assert.That(session.Board.Groups.Any(value=>value.id=="alternative"), Is.True);
|
|
for (int i=0; session.Screen==SessionScreen.Puzzle && i<30; i++) Apply(session,session.Hint);
|
|
Assert.That(session.Screen, Is.EqualTo(SessionScreen.FreePlay));
|
|
Assert.That(session.Board.Groups.Select(value=>value.ballIds.Length).OrderBy(size=>size), Is.EqualTo(new[] {5,5}));
|
|
}
|
|
[Test] public void AllIntegerPartitionsHaveLiveHintsThatReachEachCompositionTarget()
|
|
{
|
|
foreach (var definition in Definitions().Where(stage=>stage.Kind==StageKind.Composition))
|
|
foreach (var sizes in Partitions(definition.Total,1))
|
|
{
|
|
var board = new BoardRules(new StageDefinition(definition.Id,StageKind.Composition,sizes,definition.TargetGroups.ToArray()));
|
|
for (int i=0; !board.IsSolved && i<20; i++)
|
|
{
|
|
var hint=BoardHint.Find(board,definition); Assert.That(hint, Is.Not.Null);
|
|
var result=hint.Kind==HintKind.Merge ? board.TryMerge(hint.FirstGroupId,hint.SecondGroupId)
|
|
: board.TrySplit(hint.FirstGroupId,hint.BallIds,"split-"+i);
|
|
Assert.That(result.Accepted, Is.True);
|
|
}
|
|
Assert.That(board.IsSolved, Is.True, $"{definition.Id}: {string.Join(",",sizes)}");
|
|
}
|
|
}
|
|
private static System.Collections.Generic.IEnumerable<int[]> Partitions(int total,int minimum)
|
|
{
|
|
if (total==0) { yield return Array.Empty<int>(); yield break; }
|
|
for (int first=minimum; first<=total; first++)
|
|
foreach (var rest in Partitions(total-first,first)) yield return new[] {first}.Concat(rest).ToArray();
|
|
}
|
|
[Test] public void CountingHelpRejoinsCollectedSplitBeforeFindingOtherFriendsThenCountsOnlyUncountedId()
|
|
{
|
|
var definition=new StageDefinition(4,StageKind.Counting,new[] {1,1,1,1},new[] {4}); var board=new BoardRules(definition);
|
|
board.TryMerge(board.Groups[0].id,board.Groups[1].id); var collected=board.Groups.First(group=>group.ballIds.Length==2);
|
|
board.TrySplit(collected.id,new[] {collected.ballIds[0]},"resplit");
|
|
var hint=BoardHint.Find(board,definition); Assert.That(hint.Kind, Is.EqualTo(HintKind.Merge));
|
|
Assert.That(hint.BallIds.All(board.CollectedBallIds.Contains), Is.True); board.TryMerge(hint.FirstGroupId,hint.SecondGroupId);
|
|
Assert.That(BoardHint.Find(board,definition).Kind, Is.EqualTo(HintKind.Collect));
|
|
foreach (var group in board.Groups) board.TryMoveGroup(group.id,new Position3(.1f,0,0));
|
|
while (board.Groups.Length>1) board.TryMerge(board.Groups[0].id,board.Groups[1].id);
|
|
board.TryCount(board.Balls[0].id); hint=BoardHint.Find(board,definition);
|
|
Assert.That(hint.Kind, Is.EqualTo(HintKind.Count)); Assert.That(board.CountedBallIds, Does.Not.Contain(hint.BallIds[0]));
|
|
Assert.That(board.TryCount(hint.BallIds[0]).Accepted, Is.True);
|
|
}
|
|
}
|
|
}
|