Compare commits

...

2 Commits

Author SHA1 Message Date
Tim Van Baak 5b32786904 Implement support-move parsing 2024-09-05 05:27:48 +00:00
Tim Van Baak ae5eb22010 Implement support-hold parsing 2024-09-05 05:22:07 +00:00
4 changed files with 151 additions and 104 deletions

View File

@ -214,7 +214,8 @@ public class OrderParser(World world)
return true;
}
public static bool TryParseOrder(World world, string power, string command, [NotNullWhen(true)] out Order? order) {
public static bool TryParseOrder(World world, string power, string command, [NotNullWhen(true)] out Order? order)
{
order = null;
OrderParser re = new(world);
@ -346,7 +347,19 @@ public class OrderParser(World world)
{
order = null;
var support = ParseSupportHold(match);
throw new NotImplementedException();
if (!TryParseOrderSubject(world, support.timeline, support.turn, support.province, out Unit? subject)) {
return false;
}
if (!TryParseOrderSubject(
world, support.targetTimeline, support.targetTurn, support.targetProvince, out Unit? target))
{
return false;
}
order = new SupportHoldOrder(power, subject, target);
return true;
}
public static bool TryParseSupportMoveOrder(
@ -357,9 +370,60 @@ public class OrderParser(World world)
{
order = null;
var support = ParseSupportMove(match);
throw new NotImplementedException();
// It is possible to support a move to an inaccessible coast if another coast is accessible to the subject.
// DATC 4.B.4 prefers that automatic adjudicators strictly require matching coasts in supports.
if (!TryParseOrderSubject(world, support.timeline, support.turn, support.province, out Unit? subject)) {
return false;
}
if (!TryParseOrderSubject(
world, support.targetTimeline, support.targetTurn, support.targetProvince, out Unit? target))
{
return false;
}
string destTimeline = support.destTimeline.Length > 0
? support.destTimeline
// If the destination is unspecified, use the target's
: target.Season.Timeline;
int destTurn = support.destTurn.Length > 0
? int.Parse(support.destTurn)
// If the destination is unspecified, use the unit's
: target.Season.Turn;
var destProvince = world.Map.Provinces.Single(province => province.Is(support.destProvince));
// DATC 4.B.6 requires that "irrelevant" locations like army to Spain nc be ignored.
// To satisfy this, any location of the wrong type is categorically ignored, so for an army the
// "north coast" location effectively doesn't exist here.
// Note that target is used instead of subject, since it is possible to support a move to an inaccessible
// coast as long as the subject can reach the province and the target can reach the location.
var unitLocations = destProvince.Locations.Where(loc => loc.Type switch {
LocationType.Land => target.Type == UnitType.Army,
LocationType.Water => target.Type == UnitType.Fleet,
_ => false,
});
// DATC 4.6.B also requires that unknown coasts be ignored. To satisfy this, an additional filter by name.
// Doing both of these filters means "A - Spain/nc" is as meaningful as "F - Spain/wc".
var matchingLocations = unitLocations.Where(loc => loc.Is(support.destLocation));
// If one location matched, use that location. If the coast is inaccessible to the target, the order will
// be invalidated by a path check later to satisfy DATC 4.B.3.
string? destLocationKey = matchingLocations.FirstOrDefault(defaultValue: null)?.Key;
if (destLocationKey is null) {
// If no location matched, location was omitted, nonexistent, or the wrong type.
// If one location is accessible, DATC 4.B.2 requires that it be used.
// If more than one location is accessible, DATC 4.B.1 requires the order fail.
// TODO check which locations are accessible per the above
destLocationKey = unitLocations.First().Key;
// return false;
}
var destLocation = world.Map.GetLocation(destLocationKey);
order = new SupportMoveOrder(power, subject, target, new(destTimeline, destTurn), destLocation);
return true;
}
}

View File

@ -120,10 +120,8 @@ public class AdjudicationQueryScriptHandler(
return ScriptResult.Succeed(this);
case "holds":
// Assert a unit successfully held
case "dislodged":
// Assert a unit was dislodged
return ScriptResult.Fail($"Unknown assertion \"{args[0]}\"", this);
case "moves":
case "no-move":
@ -163,11 +161,9 @@ public class AdjudicationQueryScriptHandler(
}
return ScriptResult.Succeed(this);
case "supports":
// Assert a unit's support was given
case "cut":
// Assert a unit's support was cut
case "support-given":
case "support-cut":
return ScriptResult.Fail($"Unknown assertion \"{args[0]}\"", this);
default:
return ScriptResult.Fail($"Unknown assertion \"{args[0]}\"", this);

View File

@ -17,7 +17,7 @@ public class ReplDriver(IScriptHandler initialHandler, bool echo = false)
public ReplDriver ExecuteAll(string multiline)
{
var lines = multiline.Split('\n', StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries);
var lines = multiline.Split('\n', StringSplitOptions.TrimEntries);
return lines.Aggregate(this, (repl, line) => repl.Execute(line));
}

View File

@ -162,9 +162,8 @@ public class ReplTest
}
[Test]
public void AssertDislodged()
public void AssertSupportHold()
{
Assert.Ignore();
var repl = StandardRepl();
repl.ExecuteAll("""
@ -172,100 +171,88 @@ public class ReplTest
unit Germany A Boh
unit Austria A Tyr
---
Germany Mun s Boh
---
""");
// Support is given
repl.Execute("assert support-given Mun");
repl.AssertFails("assert support-cut Mun");
repl.ExecuteAll("""
---
Germany Mun s Boh
Austria Tyr - Mun
---
""");
// Support is cut
repl.Execute("assert support-cut Mun");
repl.AssertFails("assert support-given Mun");
}
[Test]
public void AssertSupportMove()
{
var repl = StandardRepl();
repl.ExecuteAll("""
unit Germany A Berlin
unit Germany A Bohemia
unit Austria A Tyrolia
---
Germany:
Berlin - Silesia
Bohemia s Berlin - Silesia
---
""");
// Support is given
repl.Execute("assert support-given Boh");
repl.AssertFails("assert support-cut Boh");
repl.ExecuteAll("""
---
Germany:
Silesia - Munich
Bohemia s Silesia - Munich
Austria Tyrolia - Bohemia
---
""");
// Support is cut
repl.AssertFails("assert support-given Boh");
repl.Execute("assert support-cut Boh");
}
[Test]
public void AssertDislodged()
{
var repl = StandardRepl();
repl.ExecuteAll("""
unit Germany A Mun
unit Germany A Boh
unit Austria A Tyr
---
Germany Mun - Tyr
---
""");
// Move repelled
repl.Execute("assert holds Tyr");
repl.AssertFails("assert dislodged Tyr");
repl.ExecuteAll("""
---
Germany Mun - Tyr
Germany Boh s Mun - Tyr
---
""");
// Assertion should pass for a dislodge
// Move succeeds
repl.Execute("assert dislodged Tyr");
// Assertion should fail for a repelled move
repl.AssertFails("assert holds Tyr");
}
[Test]
public void AssertMoves()
{
Assert.Ignore();
var repl = StandardRepl();
repl.ExecuteAll("""
unit Germany A Mun
---
Germany Mun - Tyr
---
""");
// Assertion should pass for a move
repl.Execute("assert moves Mun");
// Assertion should fail for a successful move
repl.AssertFails("assert no-move Mun");
}
[Test]
public void AssertRepelled()
{
Assert.Ignore();
var repl = StandardRepl();
repl.ExecuteAll("""
unit Germany A Mun
unit Austria A Tyr
---
Germany Mun - Tyr
---
""");
// Assertion should pass for a repelled move
repl.Execute("assert no-move Mun");
// Assertion should fail for no move
repl.AssertFails("assert moves Mun");
}
[Test]
public void AssertSupports()
{
Assert.Ignore();
var repl = StandardRepl();
repl.ExecuteAll("""
unit Germany A Mun
unit Germany A Boh
unit Austria A Tyr
---
Germany:
Mun - Tyr
Boh s Mun - Tyr
---
""");
// `supports` and `cut` are opposites
repl.Execute("assert supports Boh");
repl.AssertFails("assert cut Boh");
}
[Test]
public void AssertCutSupport()
{
Assert.Ignore();
var repl = StandardRepl();
repl.ExecuteAll("""
unit Germany A Mun
unit Germany A Boh
unit Austria A Tyr
unit Italy A Vienna
---
Germany:
Mun - Tyr
Boh s Mun - Tyr
Italy Vienna - Boh
---
""");
// `supports` and `cut` are opposites
repl.Execute("assert cut Boh");
repl.AssertFails("assert supports Boh");
}
}