summaryrefslogtreecommitdiff
path: root/src/LivingVillage.Kernel
diff options
context:
space:
mode:
Diffstat (limited to 'src/LivingVillage.Kernel')
-rw-r--r--src/LivingVillage.Kernel/LivingVillage.Kernel.fsproj1
-rw-r--r--src/LivingVillage.Kernel/Rng.fs24
-rw-r--r--src/LivingVillage.Kernel/Sim.fs40
3 files changed, 56 insertions, 9 deletions
diff --git a/src/LivingVillage.Kernel/LivingVillage.Kernel.fsproj b/src/LivingVillage.Kernel/LivingVillage.Kernel.fsproj
index a8ed312..8a4fad1 100644
--- a/src/LivingVillage.Kernel/LivingVillage.Kernel.fsproj
+++ b/src/LivingVillage.Kernel/LivingVillage.Kernel.fsproj
@@ -5,6 +5,7 @@
</PropertyGroup>
<ItemGroup>
+ <Compile Include="Rng.fs" />
<Compile Include="Sim.fs" />
</ItemGroup>
diff --git a/src/LivingVillage.Kernel/Rng.fs b/src/LivingVillage.Kernel/Rng.fs
new file mode 100644
index 0000000..9564b56
--- /dev/null
+++ b/src/LivingVillage.Kernel/Rng.fs
@@ -0,0 +1,24 @@
+namespace LivingVillage.Kernel
+
+[<Struct>]
+type RngState =
+ { State: uint64 }
+
+module Rng =
+
+ let goldenGamma = 0x9E3779B97F4A7C15UL
+
+ let ofSeed (seed: uint64) : RngState = { State = seed }
+
+ let nextUInt64 (rng: RngState) : uint64 * RngState =
+ let s = rng.State + goldenGamma
+ let mutable z = s
+ z <- (z ^^^ (z >>> 30)) * 0xBF58476D1CE4E5B9UL
+ z <- (z ^^^ (z >>> 27)) * 0x94D049BB133111EBUL
+ let out = z ^^^ (z >>> 31)
+ out, { State = s }
+
+ let nextFloat32 (rng: RngState) : float32 * RngState =
+ let z, rng' = nextUInt64 rng
+ let bits = uint32 (z >>> 40)
+ float32 bits / 16777216.0f, rng'
diff --git a/src/LivingVillage.Kernel/Sim.fs b/src/LivingVillage.Kernel/Sim.fs
index d1b2e57..0e3683b 100644
--- a/src/LivingVillage.Kernel/Sim.fs
+++ b/src/LivingVillage.Kernel/Sim.fs
@@ -2,10 +2,12 @@ namespace LivingVillage.Kernel
module Sim =
+ [<Struct>]
type Vec2 =
{ X: float32
Y: float32 }
+ [<Struct>]
type Avatar =
{ Pos: Vec2 }
@@ -14,33 +16,53 @@ module Sim =
MoveY: float32 }
type TimeStep =
- { Dt: float32
- Input: Input }
+ { Input: Input }
+ [<Struct>]
+ type NoHost =
+ { Reserved: uint64 }
+
+ [<Struct>]
type World =
{ Tick: int64
- Avatar: Avatar }
+ Time: float
+ Rng: RngState
+ Avatar: Avatar
+ NoHost: NoHost }
+
+ let ticksPerSecond = 60L
+ let secondsPerDay = 86400L
+ let ticksPerDay = secondsPerDay * ticksPerSecond
+ let dtSeconds = 1.0 / float ticksPerSecond
+ let dtSecondsF = 1.0f / float32 ticksPerSecond
let mapWidthTiles = 64
let mapHeightTiles = 48
let tilePixels = 32
let avatarSpeed = 160.0f
- let initialWorld () : World =
+ let initialWorld (seed: uint64) : World =
let centerX = float32 (mapWidthTiles * tilePixels / 2 - tilePixels / 2)
let centerY = float32 (mapHeightTiles * tilePixels / 2 - tilePixels / 2)
{ Tick = 0L
- Avatar = { Pos = { X = centerX; Y = centerY } } }
+ Time = 0.0
+ Rng = Rng.ofSeed seed
+ Avatar = { Pos = { X = centerX; Y = centerY } }
+ NoHost = { Reserved = 0UL } }
let clamp v lo hi = if v < lo then lo elif v > hi then hi else v
let step (ts: TimeStep) (world: World) : World =
+ let tick = world.Tick + 1L
let maxX = float32 (mapWidthTiles * tilePixels - tilePixels)
let maxY = float32 (mapHeightTiles * tilePixels - tilePixels)
- let dx = ts.Input.MoveX * avatarSpeed * ts.Dt
- let dy = ts.Input.MoveY * avatarSpeed * ts.Dt
- { Tick = world.Tick + 1L
+ let dx = ts.Input.MoveX * avatarSpeed * dtSecondsF
+ let dy = ts.Input.MoveY * avatarSpeed * dtSecondsF
+ { Tick = tick
+ Time = float tick * dtSeconds
+ Rng = world.Rng
Avatar =
{ Pos =
{ X = clamp (world.Avatar.Pos.X + dx) 0.0f maxX
- Y = clamp (world.Avatar.Pos.Y + dy) 0.0f maxY } } }
+ Y = clamp (world.Avatar.Pos.Y + dy) 0.0f maxY } }
+ NoHost = world.NoHost }