diff --git a/MultiversalDiplomacy/Model/Power.cs b/MultiversalDiplomacy/Model/Power.cs
new file mode 100644
index 0000000..ebcb555
--- /dev/null
+++ b/MultiversalDiplomacy/Model/Power.cs
@@ -0,0 +1,17 @@
+namespace MultiversalDiplomacy.Model;
+
+///
+/// One of the rival nations vying for control of the map.
+///
+public class Power
+{
+ ///
+ /// The power's name.
+ ///
+ public string Name { get; }
+
+ public Power(string name)
+ {
+ this.Name = name;
+ }
+}
diff --git a/MultiversalDiplomacy/Model/Unit.cs b/MultiversalDiplomacy/Model/Unit.cs
new file mode 100644
index 0000000..4b89ad6
--- /dev/null
+++ b/MultiversalDiplomacy/Model/Unit.cs
@@ -0,0 +1,54 @@
+namespace MultiversalDiplomacy.Model;
+
+///
+/// Represents a unit at a particular point in time.
+///
+public class Unit
+{
+ ///
+ /// The previous iteration of a unit. This is null if the unit was just built.
+ ///
+ public Unit? Past { get; }
+
+ ///
+ /// The location on the map where the unit is.
+ ///
+ public Location Location { get; }
+
+ ///
+ /// The season in time when the unit is.
+ ///
+ public Season Season { get; }
+
+ ///
+ /// The allegiance of the unit.
+ ///
+ public Power Power { get; }
+
+ ///
+ /// The type of unit.
+ ///
+ public UnitType Type { get; }
+
+ private Unit(Unit? past, Location location, Season season, Power power, UnitType type)
+ {
+ this.Past = past;
+ this.Location = location;
+ this.Season = season;
+ this.Power = power;
+ this.Type = type;
+ }
+
+ ///
+ /// Create a new unit. No validation is performed; the adjudicator should only call this
+ /// method after accepting a build order.
+ ///
+ public static Unit Build(Location location, Season season, Power power, UnitType type)
+ => new Unit(past: null, location, season, power, type);
+
+ ///
+ /// Advance this unit's timeline to a new location and season.
+ ///
+ public Unit Next(Location location, Season season)
+ => new Unit(past: this, location, season, this.Power, this.Type);
+}
diff --git a/MultiversalDiplomacy/Model/UnitType.cs b/MultiversalDiplomacy/Model/UnitType.cs
new file mode 100644
index 0000000..6bc824b
--- /dev/null
+++ b/MultiversalDiplomacy/Model/UnitType.cs
@@ -0,0 +1,17 @@
+namespace MultiversalDiplomacy.Model;
+
+///
+/// The type of a unit.
+///
+public enum UnitType
+{
+ ///
+ /// A unit that moves on land.
+ ///
+ Army = 0,
+
+ ///
+ /// A unit that moves in oceans and along coasts and can convoy armies.
+ ///
+ Fleet = 1,
+}
diff --git a/MultiversalDiplomacyTests/TestMap.cs b/MultiversalDiplomacyTests/TestMap.cs
new file mode 100644
index 0000000..7bdf68e
--- /dev/null
+++ b/MultiversalDiplomacyTests/TestMap.cs
@@ -0,0 +1,32 @@
+using MultiversalDiplomacy.Map;
+using MultiversalDiplomacy.Model;
+
+namespace MultiversalDiplomacyTests;
+
+public class TestMap : Map
+{
+ public override IEnumerable Provinces { get; }
+
+ public static TestMap Instance { get; } = new TestMap();
+
+ private TestMap()
+ {
+ Provinces = new List()
+ {
+ Province.Supply("Left", "LEF")
+ .AddLandLocation(),
+ Province.Supply("Right", "RIG")
+ .AddLandLocation(),
+ Province.Empty("Center", "CEN")
+ .AddLandLocation(),
+ };
+ Land("LEF").AddBorder(Land("RIG"));
+ Land("LEF").AddBorder(Land("CEN"));
+
+ Land("RIG").AddBorder(Land("LEF"));
+ Land("RIG").AddBorder(Land("CEN"));
+
+ Land("CEN").AddBorder(Land("LEF"));
+ Land("CEN").AddBorder(Land("RIG"));
+ }
+}
diff --git a/MultiversalDiplomacyTests/UnitTests.cs b/MultiversalDiplomacyTests/UnitTests.cs
new file mode 100644
index 0000000..91ee6ab
--- /dev/null
+++ b/MultiversalDiplomacyTests/UnitTests.cs
@@ -0,0 +1,37 @@
+using MultiversalDiplomacy.Map;
+using MultiversalDiplomacy.Model;
+
+using NUnit.Framework;
+
+namespace MultiversalDiplomacyTests;
+
+public class UnitTests
+{
+ [Test]
+ public void MovementTest()
+ {
+ Map map = TestMap.Instance;
+ Location left = map.Land("LEF"), right = map.Land("RIG"), center = map.Land("CEN");
+ Power pw1 = new Power("First");
+ Season s1 = Season.MakeRoot();
+ Unit u1 = Unit.Build(left, s1, pw1, UnitType.Army);
+
+ Season s2 = s1.MakeNext();
+ Unit u2 = u1.Next(right, s2);
+
+ Season s3 = s2.MakeNext();
+ Unit u3 = u2.Next(center, s3);
+
+ Assert.That(u3.Past, Is.EqualTo(u2), "Missing unit past");
+ Assert.That(u2.Past, Is.EqualTo(u1), "Missing unit past");
+ Assert.That(u1.Past, Is.Null, "Unexpected unit past");
+
+ Assert.That(u1.Season, Is.EqualTo(s1), "Unexpected unit season");
+ Assert.That(u2.Season, Is.EqualTo(s2), "Unexpected unit season");
+ Assert.That(u3.Season, Is.EqualTo(s3), "Unexpected unit season");
+
+ Assert.That(u1.Location, Is.EqualTo(left), "Unexpected unit location");
+ Assert.That(u2.Location, Is.EqualTo(right), "Unexpected unit location");
+ Assert.That(u3.Location, Is.EqualTo(center), "Unexpected unit location");
+ }
+}
\ No newline at end of file