Compare commits
4 Commits
66a85f2360
...
5c2fce0fa7
Author | SHA1 | Date |
---|---|---|
Jaculabilis | 5c2fce0fa7 | |
Jaculabilis | 171a675595 | |
Jaculabilis | 3cde558d33 | |
Jaculabilis | 26329e9186 |
|
@ -0,0 +1,27 @@
|
||||||
|
{
|
||||||
|
// Use IntelliSense to learn about possible attributes.
|
||||||
|
// Hover to view descriptions of existing attributes.
|
||||||
|
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
|
||||||
|
"version": "0.2.0",
|
||||||
|
"configurations": [
|
||||||
|
{
|
||||||
|
"name": ".NET Core Launch (console)",
|
||||||
|
"type": "coreclr",
|
||||||
|
"request": "launch",
|
||||||
|
"preLaunchTask": "build",
|
||||||
|
"program": "${workspaceFolder}/MultiversalDiplomacy/bin/Debug/net6.0/MultiversalDiplomacy.dll",
|
||||||
|
"args": ["repl"],
|
||||||
|
"cwd": "${workspaceFolder}/MultiversalDiplomacy",
|
||||||
|
"console": "internalConsole",
|
||||||
|
"stopAtEntry": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": ".NET Core Attach",
|
||||||
|
"type": "coreclr",
|
||||||
|
"request": "attach"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"logging": {
|
||||||
|
"engineLogging": true
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,41 @@
|
||||||
|
{
|
||||||
|
"version": "2.0.0",
|
||||||
|
"tasks": [
|
||||||
|
{
|
||||||
|
"label": "build",
|
||||||
|
"command": "dotnet",
|
||||||
|
"type": "process",
|
||||||
|
"args": [
|
||||||
|
"build",
|
||||||
|
"${workspaceFolder}/MultiversalDiplomacy/MultiversalDiplomacy.csproj",
|
||||||
|
"/property:GenerateFullPaths=true",
|
||||||
|
"/consoleloggerparameters:NoSummary"
|
||||||
|
],
|
||||||
|
"problemMatcher": "$msCompile"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"label": "publish",
|
||||||
|
"command": "dotnet",
|
||||||
|
"type": "process",
|
||||||
|
"args": [
|
||||||
|
"publish",
|
||||||
|
"${workspaceFolder}/MultiversalDiplomacy/MultiversalDiplomacy.csproj",
|
||||||
|
"/property:GenerateFullPaths=true",
|
||||||
|
"/consoleloggerparameters:NoSummary"
|
||||||
|
],
|
||||||
|
"problemMatcher": "$msCompile"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"label": "watch",
|
||||||
|
"command": "dotnet",
|
||||||
|
"type": "process",
|
||||||
|
"args": [
|
||||||
|
"watch",
|
||||||
|
"run",
|
||||||
|
"--project",
|
||||||
|
"${workspaceFolder}/MultiversalDiplomacy/MultiversalDiplomacy.csproj"
|
||||||
|
],
|
||||||
|
"problemMatcher": "$msCompile"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
|
@ -8,6 +8,18 @@ namespace MultiversalDiplomacy.Adjudicate;
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public interface IPhaseAdjudicator
|
public interface IPhaseAdjudicator
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Given a list of order sets, determine which entries are comprehensible as orders.
|
||||||
|
/// An order set entry may comprehensible as an order but not valid for the current
|
||||||
|
/// phase; these orders will be rejected by <see cref="ValidateOrders"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="world">The global game state.</param>
|
||||||
|
/// <param name="orderSets">The order sets to adjudicate.</param>
|
||||||
|
/// <returns>
|
||||||
|
/// A list of <see cref="Order"/> objects representing the orders parsed.
|
||||||
|
/// </returns>
|
||||||
|
public List<Order> ParseOrderSets(World world, List<OrderSet> orderSets);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Given a list of orders, determine which orders are valid for this adjudicator and
|
/// Given a list of orders, determine which orders are valid for this adjudicator and
|
||||||
/// which should be rejected before adjudication. Adjudication should be performed on
|
/// which should be rejected before adjudication. Adjudication should be performed on
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
using System.Linq;
|
||||||
|
|
||||||
using MultiversalDiplomacy.Adjudicate.Decision;
|
using MultiversalDiplomacy.Adjudicate.Decision;
|
||||||
using MultiversalDiplomacy.Adjudicate.Logging;
|
using MultiversalDiplomacy.Adjudicate.Logging;
|
||||||
using MultiversalDiplomacy.Model;
|
using MultiversalDiplomacy.Model;
|
||||||
|
@ -19,6 +21,36 @@ public class MovementPhaseAdjudicator : IPhaseAdjudicator
|
||||||
this.logger = logger;
|
this.logger = logger;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public List<Order> ParseOrderSets(World world, List<OrderSet> orderSets)
|
||||||
|
{
|
||||||
|
foreach (OrderSet orderSet in orderSets)
|
||||||
|
{
|
||||||
|
string[] lines = orderSet.Text.Split('\n');
|
||||||
|
string powerLine = lines[0];
|
||||||
|
// TODO verify
|
||||||
|
string powerName = powerLine.Substring("orders ".Length);
|
||||||
|
|
||||||
|
foreach (string line in lines.Skip(1))
|
||||||
|
{
|
||||||
|
// Individual order components do not have spaces in them
|
||||||
|
string[] tokens = line.Split(' ');
|
||||||
|
int i = 0;
|
||||||
|
|
||||||
|
// Check for a unit type
|
||||||
|
string[] unitTypes = new string[] { "a", "f"};
|
||||||
|
if (unitTypes.Contains(tokens[i].ToLowerInvariant()))
|
||||||
|
{
|
||||||
|
// yay
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
public List<OrderValidation> ValidateOrders(World world, List<Order> orders)
|
public List<OrderValidation> ValidateOrders(World world, List<Order> orders)
|
||||||
{
|
{
|
||||||
// The basic workflow of this function will be to look for invalid orders, remove these
|
// The basic workflow of this function will be to look for invalid orders, remove these
|
||||||
|
|
|
@ -1,4 +1,6 @@
|
||||||
|
using MultiversalDiplomacy.Adjudicate;
|
||||||
using MultiversalDiplomacy.Model;
|
using MultiversalDiplomacy.Model;
|
||||||
|
using MultiversalDiplomacy.Orders;
|
||||||
|
|
||||||
namespace MultiversalDiplomacy;
|
namespace MultiversalDiplomacy;
|
||||||
|
|
||||||
|
@ -21,9 +23,28 @@ public static class GameController
|
||||||
|
|
||||||
public static World AdjudicateOrders(World world)
|
public static World AdjudicateOrders(World world)
|
||||||
{
|
{
|
||||||
// TODO: Parse the order sets into orders
|
// Determine which phase the game is in, which determines how orders should be interpreted and adjudicated.
|
||||||
// TODO: Execute the correct adjudicator for the current world state
|
PhaseType phaseType = world.GetNextPhaseType();
|
||||||
// TODO: Update the world
|
|
||||||
return world;
|
IPhaseAdjudicator adjudicator = phaseType switch {
|
||||||
|
PhaseType.Movement => MovementPhaseAdjudicator.Instance,
|
||||||
|
PhaseType.Retreat => throw new NotImplementedException(),
|
||||||
|
PhaseType.Build => throw new NotImplementedException(),
|
||||||
|
PhaseType.Sustain => throw new NotImplementedException(),
|
||||||
|
_ => throw new InvalidOperationException(phaseType.ToString()),
|
||||||
|
};
|
||||||
|
|
||||||
|
// Parse the order sets into actual orders.
|
||||||
|
List<Order> parsedOrders = adjudicator.ParseOrderSets(world, world.OrderSets.ToList());
|
||||||
|
|
||||||
|
// Validate the orders.
|
||||||
|
var orderValidations = adjudicator.ValidateOrders(world, parsedOrders);
|
||||||
|
|
||||||
|
// Adjudicate the orders.
|
||||||
|
var validOrders = orderValidations.Where(v => v.Valid).Select(v => v.Order).ToList();
|
||||||
|
var results = adjudicator.AdjudicateOrders(world, validOrders);
|
||||||
|
|
||||||
|
// Update the world.
|
||||||
|
return adjudicator.UpdateWorld(world, results);
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -0,0 +1,9 @@
|
||||||
|
namespace MultiversalDiplomacy.Model;
|
||||||
|
|
||||||
|
public enum PhaseType
|
||||||
|
{
|
||||||
|
Movement = 1,
|
||||||
|
Retreat = 2,
|
||||||
|
Build = 3,
|
||||||
|
Sustain = 4,
|
||||||
|
}
|
|
@ -309,6 +309,17 @@ public class World
|
||||||
return foundUnit;
|
return foundUnit;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public PhaseType GetNextPhaseType()
|
||||||
|
{
|
||||||
|
// TODO: Figure how to order build and sustain phases in a staggered multiverse
|
||||||
|
if (RetreatingUnits.Any())
|
||||||
|
{
|
||||||
|
return PhaseType.Retreat;
|
||||||
|
}
|
||||||
|
|
||||||
|
return PhaseType.Movement;
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The standard Diplomacy provinces.
|
/// The standard Diplomacy provinces.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
|
@ -30,8 +30,31 @@ public class GameScriptHandler : IScriptHandler
|
||||||
case "help":
|
case "help":
|
||||||
case "?":
|
case "?":
|
||||||
Console.WriteLine("commands:");
|
Console.WriteLine("commands:");
|
||||||
|
Console.WriteLine(" adjudicate: adjudicate the current orders");
|
||||||
|
Console.WriteLine(" assert: assert about the state of the game");
|
||||||
Console.WriteLine(" list: list things in a game category");
|
Console.WriteLine(" list: list things in a game category");
|
||||||
Console.WriteLine(" orders: submit order sets");
|
Console.WriteLine(" orders: submit order sets");
|
||||||
|
Console.WriteLine(" status: overview of the state of the game");
|
||||||
|
break;
|
||||||
|
|
||||||
|
case "adjudicate":
|
||||||
|
World = GameController.AdjudicateOrders(World);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case "assert" when args.Length == 1:
|
||||||
|
Console.WriteLine("usage:");
|
||||||
|
Console.WriteLine(" assert timeline [timeline]@[turn]: timeline exists");
|
||||||
|
Console.WriteLine(" assert unit [unit spec]: unit exists");
|
||||||
|
break;
|
||||||
|
|
||||||
|
case "assert" when args[1] == "timeline":
|
||||||
|
// TODO: raise an error if the timeline doesn't exist
|
||||||
|
Console.WriteLine("WIP");
|
||||||
|
break;
|
||||||
|
|
||||||
|
case "assert" when args[1] == "unit":
|
||||||
|
// TODO: raise an error if the unit doesn't exist
|
||||||
|
Console.WriteLine("WIP");
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case "list" when args.Length == 1:
|
case "list" when args.Length == 1:
|
||||||
|
@ -70,6 +93,17 @@ public class GameScriptHandler : IScriptHandler
|
||||||
Console.WriteLine("Unrecognized power");
|
Console.WriteLine("Unrecognized power");
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case "status":
|
||||||
|
foreach (Season season in World.Seasons)
|
||||||
|
{
|
||||||
|
Console.WriteLine($"{season}");
|
||||||
|
foreach (Unit unit in World.Units.Where(u => u.Season == season))
|
||||||
|
{
|
||||||
|
Console.WriteLine($" {unit}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
Console.WriteLine("Unrecognized command");
|
Console.WriteLine("Unrecognized command");
|
||||||
break;
|
break;
|
||||||
|
|
96
README.md
96
README.md
|
@ -22,8 +22,102 @@ When a unit changes the outcome of a battle in the past, only the timeline of th
|
||||||
|
|
||||||
Since there are many ways to create new timelines, the game would rapidly expand beyond all comprehension if this were not counterbalanced in some way. This happens during the _sustain phase_, which occurs after the fall movement and retreat phases and before the winter buid/disband phase.
|
Since there are many ways to create new timelines, the game would rapidly expand beyond all comprehension if this were not counterbalanced in some way. This happens during the _sustain phase_, which occurs after the fall movement and retreat phases and before the winter buid/disband phase.
|
||||||
|
|
||||||
(TODO)
|
WIP: the sustain phase has not been implemented yet
|
||||||
|
|
||||||
### Victory conditions
|
### Victory conditions
|
||||||
|
|
||||||
The Great Powers of Europe can only wage multiversal wars because they are lead by extradimensional beings masquerading as human politicians. When a country is eliminated in one timeline, its extradimensional leader is executed, killing them in all timelines.
|
The Great Powers of Europe can only wage multiversal wars because they are lead by extradimensional beings masquerading as human politicians. When a country is eliminated in one timeline, its extradimensional leader is executed, killing them in all timelines.
|
||||||
|
|
||||||
|
### Unit designations
|
||||||
|
|
||||||
|
In _Diplomacy_, orders refer to provinces, such as "A Mun-Tyr". In _5D Diplomacy with Multiversal Time Travel_, this is insufficient to unambiguously identify a province, since the province exists in multiple timelines across multiple turns. The convention for identifying a multiversal location is `timeline:province:turn`, where `timeline` is the timeline's identifier and `turn` is the turn's identifier. Thus, an army in Munich in timeline "bravo" in Spring 1902 is referenced as "A b:Mun:S02".
|
||||||
|
|
||||||
|
(Why this order? Short representations for timelines and turns can be confused for each other, especially for timelines designated with `foxtrot` or `sierra` and turns in Fall or Spring. _5D Diplomacy with Multiversal Time Travel_ is already complicated enough, so the timeline and turn are put on either side of the province.)
|
||||||
|
|
||||||
|
WIP: parsing of turn designations has not been implemented yet
|
||||||
|
|
||||||
|
### Open convoys
|
||||||
|
|
||||||
|
The standard _Diplomacy_ rules require that a convoy order include the convoyed unit's origin and destination. This is hard to coordinate once there are multiple turns and timelines involved. _5D Diplomacy with Multiversal Time Travel_ thus introduces the concept of an _open convoy_, a nonspecific convoy order that can become part of a convoy later.
|
||||||
|
|
||||||
|
WIP: open convoys have not been implemented yet
|
||||||
|
|
||||||
|
## DATC compliance
|
||||||
|
|
||||||
|
WIP
|
||||||
|
|
||||||
|
## 5dp script
|
||||||
|
|
||||||
|
Order notation is case-insensitive.
|
||||||
|
|
||||||
|
### Order element grammar
|
||||||
|
|
||||||
|
A unit type is specified with a single letter.
|
||||||
|
```
|
||||||
|
<unit-spec> = "A" / "F"
|
||||||
|
```
|
||||||
|
|
||||||
|
A timeline is specified with a primary designation initial, plus a secondary designation if there are enough timelines.
|
||||||
|
```
|
||||||
|
<timeline-spec> = <tl-primary> <tl-secondary>
|
||||||
|
<tl-primary> = "a" / "b" / ...
|
||||||
|
<tl-secondary> = "" / "1" / "2" / ...
|
||||||
|
```
|
||||||
|
|
||||||
|
A province is specified with a known three-letter abbreviation. A named location in a province may optionally be specfied with its abbreviation. A named location is not necessary for the _form_ of a province to be valid, though an order may be invalid if the omission creates an ambiguity.
|
||||||
|
```
|
||||||
|
<province-spec> = <province> ["/" <location>]
|
||||||
|
<province> = "MUN" / "TYR" / ...
|
||||||
|
<location> = "nc" / "sc" / ...
|
||||||
|
```
|
||||||
|
|
||||||
|
A turn is specified with the season's initial and the short form of the year. Winter is numbered in the year of the previous Fall.
|
||||||
|
```
|
||||||
|
<turn-spec> = <season> <year>
|
||||||
|
<season> = "S" / "F" / "W"
|
||||||
|
<year> = "01" / "02" / ...
|
||||||
|
```
|
||||||
|
|
||||||
|
A multiversal location is a timeline, a province, and a turn separated by a colon.
|
||||||
|
```
|
||||||
|
<multiverse-spec> = <timeline-spec> ":" <province-spec> ":" <turn-spec>
|
||||||
|
```
|
||||||
|
|
||||||
|
Thus, `b1:IRI:F02` represents the Irish Sea, in Fall 1902, in timeline bravo-prime.
|
||||||
|
|
||||||
|
### Order formats
|
||||||
|
|
||||||
|
Note that DATC 4.C makes unit designations superfluous outside some build order cases. Thus, the `<unit-spec>` is considered optional in the orders below.
|
||||||
|
|
||||||
|
Hold orders require the unit and an indication of a hold order.
|
||||||
|
```
|
||||||
|
<hold-order> = [<unit-spec> " "] <multiverse-spec> " " <hold-token>
|
||||||
|
<hold-token> = "hold" / "holds"
|
||||||
|
```
|
||||||
|
|
||||||
|
Move orders require the unit, target, and an indication of movement instead of support.
|
||||||
|
```
|
||||||
|
<move-order> = [<unit-spec> " "] <multiverse-spec> <move-token> <multiverse-spec>
|
||||||
|
<move-token> = "-" / " to "
|
||||||
|
```
|
||||||
|
|
||||||
|
Support-hold orders require the unit, target, and an indication of support instead of movement.
|
||||||
|
```
|
||||||
|
<support-hold-order> = [<unit-spec> " "] <multiverse-spec> <support-token> <multiverse-spec>
|
||||||
|
<support-token> = " S " / " support " / " supports "
|
||||||
|
```
|
||||||
|
|
||||||
|
Support-move orders require the unit, target, and the support and move indicators.
|
||||||
|
```
|
||||||
|
<support-move-order> = [<unit-spec> " "] <multiverse-spec> <support-token> <move-order>
|
||||||
|
```
|
||||||
|
|
||||||
|
Convoy orders WIP.
|
||||||
|
|
||||||
|
Retreat orders WIP.
|
||||||
|
|
||||||
|
Build orders WIP.
|
||||||
|
|
||||||
|
Disband orders WIP.
|
||||||
|
|
||||||
|
Sustain orders WIP.
|
|
@ -0,0 +1,12 @@
|
||||||
|
new custom
|
||||||
|
unit Germany Army Berlin
|
||||||
|
unit Austria Army Tyrolia
|
||||||
|
|
||||||
|
orders Germany
|
||||||
|
BER - TYR
|
||||||
|
|
||||||
|
orders Austria
|
||||||
|
TYR hold
|
||||||
|
|
||||||
|
list ordersets
|
||||||
|
adjudicate
|
Loading…
Reference in New Issue