Skip to content Search Apps Documentation Source Content File Folder Download Copy Actions State String Boolean Number Struct Map Slice Pointer Function Closure Reference Nil Package Type Interface Unknown

Community realm. Read the code first. Community realm, deployed by its author. Read the code before you interact or send coins.

seed.gno

3.57 Kb · 134 lines
  1package penalty
  2
  3// Seed is the 32 bytes of entropy that complete a kick.
  4//
  5// When the player shoots, the seed supplies the computer's keeper and the
  6// player's mishit:
  7//
  8//	bytes 0-7    keeper plan: four big-endian uint16 (direction, speed, jump, reaction)
  9//	bytes 8-31   mishit seed (24 bytes)
 10//
 11// When the player keeps, the seed supplies the computer's whole kick:
 12//
 13//	bytes 0-1    aim x       uint16 -> ±(GoalWidth/2 - ChainAimInset) mm
 14//	bytes 2-3    aim y       uint16 -> ChainAimMinY .. GoalHeight + ChainAimOverY mm
 15//	bytes 4-5    power       uint16 -> ChainPowerMin .. 1000 per-mille
 16//	byte  6      contact x   int8   -> ±ChainContact milli-radii
 17//	byte  7      contact y   int8   -> ±ChainContact milli-radii
 18//	bytes 8-31   mishit seed (24 bytes)
 19//
 20// So the layout is the same either way: the first eight bytes are "the
 21// computer's move", the last twenty-four are the mishit.
 22type Seed [32]byte
 23
 24// How the computer takes its kicks: inside the frame, aimed a little high to
 25// allow for the drop, struck with at least ChainPowerMin.
 26const (
 27	ChainAimInset = 250 // mm inside each post
 28	ChainAimMinY  = 300 // mm
 29	ChainAimOverY = 200 // mm above the bar at most
 30	ChainPowerMin = 450 // per-mille
 31	ChainContact  = 350 // milli-radii
 32)
 33
 34func u16(b []byte) uint16 { return uint16(b[0])<<8 | uint16(b[1]) }
 35
 36// span maps a uint16 linearly onto lo..hi.
 37func span(u uint16, lo, hi int64) int64 { return lo + (hi-lo)*int64(u)/65535 }
 38
 39// KeeperPlan reads the computer's keeper plan from bytes 0-7.
 40func (s Seed) KeeperPlan() KeeperPlan {
 41	return KeeperPlan{
 42		Direction: u16(s[0:2]),
 43		Speed:     u16(s[2:4]),
 44		Jump:      u16(s[4:6]),
 45		Reaction:  u16(s[6:8]),
 46	}
 47}
 48
 49// Mishit returns bytes 8-31.
 50func (s Seed) Mishit() [24]byte {
 51	var m [24]byte
 52	copy(m[:], s[8:32])
 53	return m
 54}
 55
 56// ChainShot reads the computer's kick from bytes 0-7 (see Seed).
 57func (s Seed) ChainShot(c Config) ShotInput {
 58	halfW := c.GoalWidth/2 - ChainAimInset
 59	in := ShotInput{
 60		AimX:     span(u16(s[0:2]), -halfW, halfW),
 61		AimY:     span(u16(s[2:4]), ChainAimMinY, c.GoalHeight+ChainAimOverY),
 62		Power:    span(u16(s[4:6]), ChainPowerMin, 1000),
 63		ContactX: (int64(s[6]) - 128) * ChainContact / 128,
 64		ContactY: (int64(s[7]) - 128) * ChainContact / 128,
 65	}
 66	// Keep the contact inside this game's selectable disc.
 67	r2 := in.ContactX*in.ContactX + in.ContactY*in.ContactY
 68	if m := c.MaxContact; r2 > m*m {
 69		r := isqrt(r2)
 70		in.ContactX = in.ContactX * m / r
 71		in.ContactY = in.ContactY * m / r
 72	}
 73	return in
 74}
 75
 76const hexDigits = "0123456789abcdef"
 77
 78// Hex prints the seed as 64 hex characters.
 79func (s Seed) Hex() string { return toHex(s[:]) }
 80
 81func toHex(b []byte) string {
 82	out := make([]byte, len(b)*2)
 83	for i, v := range b {
 84		out[2*i] = hexDigits[v>>4]
 85		out[2*i+1] = hexDigits[v&15]
 86	}
 87	return string(out)
 88}
 89
 90// MishitHex prints a mishit seed as 48 hex characters.
 91func MishitHex(m [24]byte) string { return toHex(m[:]) }
 92
 93// ParseMishitHex reads 48 hex characters.
 94func ParseMishitHex(s string) ([24]byte, bool) {
 95	var m [24]byte
 96	if len(s) != 48 {
 97		return m, false
 98	}
 99	for i := 0; i < 24; i++ {
100		hi, ok1 := hexVal(s[2*i])
101		lo, ok2 := hexVal(s[2*i+1])
102		if !ok1 || !ok2 {
103			return m, false
104		}
105		m[i] = hi<<4 | lo
106	}
107	return m, true
108}
109
110func hexVal(c byte) (byte, bool) {
111	switch {
112	case c >= '0' && c <= '9':
113		return c - '0', true
114	case c >= 'a' && c <= 'f':
115		return c - 'a' + 10, true
116	case c >= 'A' && c <= 'F':
117		return c - 'A' + 10, true
118	}
119	return 0, false
120}
121
122// isqrt is the integer square root (floor).
123func isqrt(n int64) int64 {
124	if n <= 0 {
125		return 0
126	}
127	x := n
128	y := (x + 1) / 2
129	for y < x {
130		x = y
131		y = (x + n/x) / 2
132	}
133	return x
134}