- Go 1.27 + Ebitengine v2.10, intern upplösning 320x180 med heltalsskalning - internal/res (resursuppslag), internal/rng (seedad slump), internal/level (banformat, validering, BFS-lösbarhet) med tester; internal/archtest kontrollerar att bara presentationslagret beror på Ebitengine - tools/build: debug -> build/debug/, release -> build/release/<os>-<arch>/ med resources/ bredvid binären; Windows korsbyggs utan C-verktyg - VS Code tasks (build/test/release) och launch (dlv) - Första banan 001-flygplatsen, sv/en-texter, skyltordbok, placeholder-sprite - doc/: spelbeskrivning (renskriven), mål och tester, roadmap med teknikval (M0–M12), plan.md; README med bygg- och beroendeinformation Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
49 lines
1.6 KiB
Go
49 lines
1.6 KiB
Go
// Package rng ger seedade slumptalsgeneratorer.
|
|
//
|
|
// Allt som ska vara reproducerbart (minispel, oändligt läge, event-timing)
|
|
// måste ta sin slump härifrån med en känd seed, aldrig från den globala
|
|
// generatorn. Seeden sparas i sparfilen så att en laddad omgång ger samma
|
|
// utfall som den avbrutna.
|
|
package rng
|
|
|
|
import (
|
|
crand "crypto/rand"
|
|
"encoding/binary"
|
|
"math/rand/v2"
|
|
)
|
|
|
|
// Seed är en 64-bitars seed. Två värden för att kunna avleda del-seeds
|
|
// (t.ex. per bana eller per minispel) utan att de påverkar varandra.
|
|
type Seed struct {
|
|
A, B uint64
|
|
}
|
|
|
|
// NewSeed drar en färsk slumpmässig seed från operativsystemet.
|
|
func NewSeed() Seed {
|
|
var b [16]byte
|
|
if _, err := crand.Read(b[:]); err != nil {
|
|
panic("rng: kunde inte läsa slump från OS: " + err.Error())
|
|
}
|
|
return Seed{binary.LittleEndian.Uint64(b[:8]), binary.LittleEndian.Uint64(b[8:])}
|
|
}
|
|
|
|
// FromInt skapar en seed från ett enkelt heltal (praktiskt i tester och för
|
|
// seeds som spelaren skriver in manuellt).
|
|
func FromInt(n uint64) Seed { return Seed{A: n, B: n ^ 0x9E3779B97F4A7C15} }
|
|
|
|
// Derive avleder en deterministisk del-seed för en namngiven kontext, så att
|
|
// t.ex. biljettautomatens minispel på bana 3 alltid får samma slump oavsett
|
|
// vad spelaren gjort innan.
|
|
func (s Seed) Derive(context string) Seed {
|
|
h := rand.New(rand.NewPCG(s.A, s.B))
|
|
a, b := h.Uint64(), h.Uint64()
|
|
for _, c := range context {
|
|
a ^= uint64(c) * 0x100000001B3
|
|
b = b*31 + uint64(c)
|
|
}
|
|
return Seed{A: a, B: b}
|
|
}
|
|
|
|
// New returnerar en generator för seeden. Samma seed ger alltid samma sekvens.
|
|
func (s Seed) New() *rand.Rand { return rand.New(rand.NewPCG(s.A, s.B)) }
|