Compare commits

..

No commits in common. "93716a7f0f7cd5ff98838ac6bff92918a2d9f8f8" and "f0bdfd94433fef8c81ee44e017a2ed1bd80bbe99" have entirely different histories.

9 changed files with 103 additions and 171 deletions

View File

@ -17,11 +17,6 @@ const (
actBeer // note prev indicates whether the shell was live
actCuff
actKnife
actAdrenaline
actPhone
actInverter
actPillsHeal
actPillsHurt
actDealerConcedes // dealer concedes
actChallengerConcedes // challenger concedes

View File

@ -19,18 +19,13 @@ func _() {
_ = x[actBeer-8]
_ = x[actCuff-9]
_ = x[actKnife-10]
_ = x[actAdrenaline-11]
_ = x[actPhone-12]
_ = x[actInverter-13]
_ = x[actPillsHeal-14]
_ = x[actPillsHurt-15]
_ = x[actDealerConcedes-16]
_ = x[actChallengerConcedes-17]
_ = x[actDealerConcedes-11]
_ = x[actChallengerConcedes-12]
}
const _action_name = "StartShootGameEndBeerGameEndChallengerWinsDealerWinsLensCigBeerCuffKnifeAdrenalinePhoneInverterPillsHealPillsHurtDealerConcedesChallengerConcedes"
const _action_name = "StartShootGameEndBeerGameEndChallengerWinsDealerWinsLensCigBeerCuffKnifeDealerConcedesChallengerConcedes"
var _action_index = [...]uint8{0, 5, 10, 17, 28, 42, 52, 56, 59, 63, 67, 72, 82, 87, 95, 104, 113, 127, 145}
var _action_index = [...]uint8{0, 5, 10, 17, 28, 42, 52, 56, 59, 63, 67, 72, 86, 104}
func (i action) String() string {
if i >= action(len(_action_index)-1) {

View File

@ -5,13 +5,12 @@
// It ends when the challenger wins three rounds or the dealer wins once.
// - A round is an instance of gameplay. Both players start each round with
// the same HP, and it continues until either player reaches zero.
// - A game is a set of 2-8 shells and 2-5 items delivered to each player.
// - A game is a set of 2-8 shells and 1-4 items delivered to each player.
// The challenger always moves first at the start of each game.
package game
import (
"errors"
"math/rand/v2"
"time"
"git.sunturtle.xyz/studio/shotgun/player"
@ -19,6 +18,8 @@ import (
)
type Match struct {
// rng is the PRNG state used for this match.
rng xoshiro
// players are the players in the match. The first element is the dealer
// and the second is the challenger.
players [2]playerState
@ -36,9 +37,6 @@ type Match struct {
// reveal indicates whether the current player has revealed the shell that
// will fire next.
reveal bool
// adrenaline indicates whether the current player has adrenaline in
// effect, requiring them to use an opponent's item.
adrenaline bool
// prev is a pointer to the element of shellArray which was fired last this
// game, or nil if none has been.
prev *bool
@ -52,6 +50,7 @@ type Match struct {
// New creates a new match started at round 1.
func New(dealer, challenger player.ID) *Match {
g := &Match{
rng: newRNG(),
players: [2]playerState{
{id: dealer},
{id: challenger},
@ -63,7 +62,7 @@ func New(dealer, challenger player.ID) *Match {
// NextRound starts the next round of a match.
func (g *Match) NextRound() {
g.hp = int8(rand.IntN(3) + 2)
g.hp = int8(g.rng.Intn(3) + 2)
g.players[0].startRound(g.hp)
g.players[1].startRound(g.hp)
g.round++
@ -72,10 +71,10 @@ func (g *Match) NextRound() {
// NextGame starts the next game of a round.
func (g *Match) NextGame() {
items := rand.IntN(4) + 2
g.players[0].startGame(items)
g.players[1].startGame(items)
shells := rand.IntN(6) + 2
items := g.rng.Intn(4) + 1
g.players[0].startGame(&g.rng, items)
g.players[1].startGame(&g.rng, items)
shells := g.rng.Intn(6) + 2
for i := 0; i < shells/2; i++ {
g.shellArray[i] = true
}
@ -83,7 +82,7 @@ func (g *Match) NextGame() {
g.shellArray[i] = false
}
g.shells = g.shellArray[:shells]
shuffle(g.shells)
shuffle(&g.rng, g.shells)
g.turn = 0
g.prev = nil
g.nextTurn()
@ -120,22 +119,17 @@ func (g *Match) Opponent() *playerState {
// Apply uses an item by index for the current player.
// If this causes the current game to end (a beer discharges the last shell),
// returns ErrGameEnded but does not start the next game.
// Returns ErrWrongTurn if id does not correspond to the current player
// (with appropriate exception for adrenaline).
// Returns ErrWrongTurn if id does not correspond to the current player.
func (g *Match) Apply(id player.ID, item int) error {
p := g.CurrentPlayer()
if g.adrenaline {
p = g.Opponent()
}
if p.id != id {
cur := g.CurrentPlayer()
if cur.id != id {
return ErrWrongTurn
}
if item < 0 || item >= len(p.items) {
if item < 0 || item >= len(cur.items) {
return errors.New("item index out of bounds")
}
if p.items[item].apply(g) {
p.items[item] = itemNone
g.adrenaline = false
if cur.items[item].apply(g) {
cur.items[item] = itemNone
}
if g.Empty() {
return ErrGameEnded
@ -191,11 +185,10 @@ func (g *Match) MatchWinner() *playerState {
// player if self is true. Advances the turn if appropriate.
// Returns ErrRoundEnded if this causes the round to end.
// Returns ErrGameEnded if this causes the game but not the round to end.
// Returns ErrWrongTurn if id does not correspond to the current player
// or if adrenaline is in effect.
// Returns ErrWrongTurn if id does not correspond to the current player.
func (g *Match) Shoot(id player.ID, self bool) error {
cur := g.CurrentPlayer()
if cur.id != id || g.adrenaline {
if cur.id != id {
return ErrWrongTurn
}
target := g.Opponent()

View File

@ -1,7 +1,5 @@
package game
import "math/rand/v2"
type item int8
const (
@ -11,14 +9,10 @@ const (
itemBeer
itemCuff
itemKnife
itemAdrenaline
itemPhone
itemInverter
itemPill
)
func newItem() item {
return item(rand.IntN(9)) + 1
func newItem(rng *xoshiro) item {
return item(rng.Intn(5)) + 1
}
func (i item) apply(g *Match) bool {
@ -61,49 +55,12 @@ func (i item) apply(g *Match) bool {
g.action = actKnife
g.damage = 2
return true
case itemAdrenaline:
if g.adrenaline {
// Adrenaline forbids using adrenaline.
return false
}
g.action = actAdrenaline
g.adrenaline = true
return true
case itemPhone:
g.action = actPhone
// TODO(zeph): implement
return true
case itemInverter:
g.action = actInverter
g.shells[0] = !g.shells[0]
return true
case itemPill:
cur := g.CurrentPlayer()
if rand.Uint64() <= (1<<65)/5 {
g.action = actPillsHeal
cur.hp = min(cur.hp+2, g.hp)
} else {
g.action = actPillsHurt
cur.hp--
}
return true
default:
panic("shotgun: unknown item")
}
}
var itemNames = [...]string{
itemNone: "",
itemLens: "🔍",
itemCig: "🚬",
itemBeer: "🍺",
itemCuff: "👮",
itemKnife: "🔪",
itemAdrenaline: "💉",
itemPhone: "📱",
itemInverter: "🧲",
itemPill: "💊",
}
var itemNames = [...]string{"", "🔍", "🚬", "🍺", "👮", "🔪"}
func (i item) String() string {
return itemNames[i]

View File

@ -13,10 +13,6 @@ func TestItemStrings(t *testing.T) {
{itemBeer, "🍺"},
{itemCuff, "👮"},
{itemKnife, "🔪"},
{itemAdrenaline, "💉"},
{itemPhone, "📱"},
{itemInverter, "🧲"},
{itemPill, "💊"},
}
for _, c := range cases {
got := c.item.String()

View File

@ -19,13 +19,13 @@ func (p *playerState) startRound(hp int8) {
clear(p.items[:])
}
func (p *playerState) startGame(items int) {
func (p *playerState) startGame(rng *xoshiro, items int) {
for i := 0; i < items; i++ {
k := slices.Index(p.items[:], itemNone)
if k < 0 {
break
}
p.items[k] = newItem()
p.items[k] = newItem(rng)
}
p.cuffs = uncuffed
}

View File

@ -1,10 +1,65 @@
package game
import "math/rand/v2"
import (
"crypto/rand"
"encoding/binary"
"math/bits"
)
func shuffle[E any, S ~[]E](s S) {
// xoshiro is a random number generator for shotgun.
//
// Currently xoshiro256**. Subject to change.
type xoshiro struct {
w, x, y, z uint64
}
// newRNG produces a new, uniquely seeded RNG.
func newRNG() xoshiro {
r := xoshiro{}
b := make([]byte, 8*4)
// Loop to ensure the state is never all-zero, which is an invalid state
// for xoshiro.
for r.w == 0 && r.x == 0 && r.y == 0 && r.z == 0 {
rand.Read(b)
r.w = binary.LittleEndian.Uint64(b)
r.x = binary.LittleEndian.Uint64(b[8:])
r.y = binary.LittleEndian.Uint64(b[16:])
r.z = binary.LittleEndian.Uint64(b[24:])
}
return r
}
// Uint64 produces a 64-bit pseudo-random value.
func (rng *xoshiro) Uint64() uint64 {
w, x, y, z := rng.w, rng.x, rng.y, rng.z
r := bits.RotateLeft64(x*5, 7) * 9
t := x << 17
y ^= w
z ^= x
x ^= y
w ^= z
y ^= t
z = bits.RotateLeft64(z, 45)
rng.w, rng.x, rng.y, rng.z = w, x, y, z
return r
}
// Intn produces an int in [0, n). Panics if n <= 0.
func (rng *xoshiro) Intn(n int) int {
if n <= 0 {
panic("shotgun: rng.Intn max below zero")
}
bad := ^uint(0) - ^uint(0)%uint(n)
x := uint(rng.Uint64())
for x > bad {
x = uint(rng.Uint64())
}
return int(x % uint(n))
}
func shuffle[E any, S ~[]E](rng *xoshiro, s S) {
for i := len(s) - 1; i > 0; i-- {
j := rand.IntN(i + 1)
j := rng.Intn(i + 1)
s[i], s[j] = s[j], s[i]
}
}

44
go.mod
View File

@ -1,40 +1,32 @@
module git.sunturtle.xyz/studio/shotgun
go 1.22.2
go 1.21.6
require (
github.com/go-chi/chi/v5 v5.0.12
github.com/google/uuid v1.6.0
github.com/go-chi/chi/v5 v5.0.11
github.com/google/uuid v1.5.0
gitlab.com/zephyrtronium/sq v1.0.1
golang.org/x/crypto v0.22.0
modernc.org/sqlite v1.29.5
nhooyr.io/websocket v1.8.11
golang.org/x/crypto v0.18.0
modernc.org/sqlite v1.28.0
nhooyr.io/websocket v1.8.10
)
require (
github.com/dustin/go-humanize v1.0.1 // indirect
github.com/hashicorp/golang-lru/v2 v2.0.7 // indirect
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 // indirect
github.com/mattn/go-isatty v0.0.20 // indirect
github.com/ncruces/go-strftime v0.1.9 // indirect
github.com/mattn/go-isatty v0.0.16 // indirect
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect
golang.org/x/mod v0.17.0 // indirect
golang.org/x/sync v0.7.0 // indirect
golang.org/x/sys v0.19.0 // indirect
golang.org/x/tools v0.20.0 // indirect
golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028 // indirect
lukechampine.com/uint128 v1.3.0 // indirect
modernc.org/cc/v3 v3.41.0 // indirect
modernc.org/cc/v4 v4.20.0 // indirect
modernc.org/ccgo/v3 v3.17.0 // indirect
modernc.org/ccgo/v4 v4.16.0 // indirect
modernc.org/gc/v2 v2.4.1 // indirect
modernc.org/gc/v3 v3.0.0-20240107210532-573471604cb6 // indirect
modernc.org/libc v1.49.2 // indirect
golang.org/x/mod v0.3.0 // indirect
golang.org/x/sys v0.16.0 // indirect
golang.org/x/tools v0.0.0-20201124115921-2c860bdd6e78 // indirect
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect
lukechampine.com/uint128 v1.2.0 // indirect
modernc.org/cc/v3 v3.40.0 // indirect
modernc.org/ccgo/v3 v3.16.13 // indirect
modernc.org/libc v1.29.0 // indirect
modernc.org/mathutil v1.6.0 // indirect
modernc.org/memory v1.8.0 // indirect
modernc.org/memory v1.7.2 // indirect
modernc.org/opt v0.1.3 // indirect
modernc.org/sortutil v1.2.0 // indirect
modernc.org/strutil v1.2.0 // indirect
modernc.org/token v1.1.0 // indirect
modernc.org/strutil v1.1.3 // indirect
modernc.org/token v1.0.1 // indirect
)

51
go.sum
View File

@ -2,28 +2,18 @@ github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkp
github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto=
github.com/go-chi/chi/v5 v5.0.11 h1:BnpYbFZ3T3S1WMpD79r7R5ThWX40TaFB7L31Y8xqSwA=
github.com/go-chi/chi/v5 v5.0.11/go.mod h1:DslCQbL2OYiznFReuXYUmQ2hGd1aDpCnlMNITLSKoi8=
github.com/go-chi/chi/v5 v5.0.12 h1:9euLV5sTrTNTRUU9POmDUvfxyj6LAABLUcEWO+JJb4s=
github.com/go-chi/chi/v5 v5.0.12/go.mod h1:DslCQbL2OYiznFReuXYUmQ2hGd1aDpCnlMNITLSKoi8=
github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/google/pprof v0.0.0-20221118152302-e6195bd50e26 h1:Xim43kblpZXfIBQsbuBVKCudVG457BR2GZFIz3uw3hQ=
github.com/google/pprof v0.0.0-20221118152302-e6195bd50e26/go.mod h1:dDKJzRmX4S37WGHujM7tX//fmj1uioxKzKxz3lo4HJo=
github.com/google/uuid v1.5.0 h1:1p67kYwdtXjb0gL0BPiP1Av9wiZPo5A8z2cWkTZ+eyU=
github.com/google/uuid v1.5.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/hashicorp/golang-lru/v2 v2.0.7 h1:a+bsQ5rvGLjzHuww6tVxozPZFVghXaHOwFs4luLUK2k=
github.com/hashicorp/golang-lru/v2 v2.0.7/go.mod h1:QeFd9opnmA6QUJc5vARoKUSoFhyfM2/ZepoAG6RGpeM=
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 h1:Z9n2FFNUXsshfwJMBgNA0RU6/i7WVaAegv3PtuIHPMs=
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51/go.mod h1:CzGEWj7cYgsdH8dAjBGEr58BoE7ScuLd+fwFZ44+/x8=
github.com/mattn/go-isatty v0.0.16 h1:bq3VjFmv/sOjHtdEhmkEV4x1AJtvUvOJ2PFAZ5+peKQ=
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
github.com/mattn/go-sqlite3 v1.14.16 h1:yOQRA0RpS5PFz/oikGwBEqvAWhWg5ufRz4ETLjwpU1Y=
github.com/mattn/go-sqlite3 v1.14.16/go.mod h1:2eHXhiwb8IkHr+BDWZGa96P6+rkvnG63S2DGjv9HUNg=
github.com/ncruces/go-strftime v0.1.9 h1:bY0MQC28UADQmHmaF5dgpLmImcShSi2kHU9XLdhx/f4=
github.com/ncruces/go-strftime v0.1.9/go.mod h1:Fwc5htZGVVkseilnfgOVb9mKy6w1naJmn9CehxcKcls=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec h1:W09IVJc94icq4NjY3clb7Lk8O1qJ8BdBEF8z0ibU0rE=
@ -36,97 +26,56 @@ golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8U
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.18.0 h1:PGVlW0xEltQnzFZ55hkuX5+KLyrMYhHld1YHO4AKcdc=
golang.org/x/crypto v0.18.0/go.mod h1:R0j02AL6hcrfOiy9T4ZYp/rcWeMxM3L6QYxlOuEG1mg=
golang.org/x/crypto v0.22.0 h1:g1v0xeRhjcugydODzvb3mEM9SQ0HGp9s/nh3COQ/C30=
golang.org/x/crypto v0.22.0/go.mod h1:vr6Su+7cTlO45qkww3VDJlzDn0ctJvRgYbC2NvXHt+M=
golang.org/x/mod v0.3.0 h1:RM4zey1++hCTbCVQfnWeKs9/IEsaBLA8vTkd0WVtmH4=
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.17.0 h1:zY54UmvipHiNd+pm+m0x9KhZ9hl1/7QNMyxXbc6ICqA=
golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M=
golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.16.0 h1:xWw16ngr6ZMtmxDyKyIgsE93KNKz5HKmMa3b8ALHidU=
golang.org/x/sys v0.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.19.0 h1:q5f1RH2jigJ1MoAWp2KTp3gm5zAGFUTarQZ5U386+4o=
golang.org/x/sys v0.19.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20201124115921-2c860bdd6e78 h1:M8tBwCtWD/cZV9DZpFYRUgaymAYAr+aIUTWzDaM3uPs=
golang.org/x/tools v0.0.0-20201124115921-2c860bdd6e78/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.20.0 h1:hz/CVckiOxybQvFw6h7b/q80NTr9IUQb4s1IIzW7KNY=
golang.org/x/tools v0.20.0/go.mod h1:WvitBU7JJf6A4jOdg4S1tviW9bhUxkgeCui/0JHctQg=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028 h1:+cNy6SZtPcJQH3LJVLOSmiC7MMxXNOb3PU/VUEz+EhU=
golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028/go.mod h1:NDW/Ps6MPRej6fsCIbMTohpP40sJ/P/vI1MoTEGwX90=
lukechampine.com/uint128 v1.2.0 h1:mBi/5l91vocEN8otkC5bDLhi2KdCticRiwbdB0O+rjI=
lukechampine.com/uint128 v1.2.0/go.mod h1:c4eWIwlEGaxC/+H1VguhU4PHXNWDCDMUlWdIWl2j1gk=
lukechampine.com/uint128 v1.3.0 h1:cDdUVfRwDUDovz610ABgFD17nXD4/uDgVHl2sC3+sbo=
lukechampine.com/uint128 v1.3.0/go.mod h1:c4eWIwlEGaxC/+H1VguhU4PHXNWDCDMUlWdIWl2j1gk=
modernc.org/cc/v3 v3.40.0 h1:P3g79IUS/93SYhtoeaHW+kRCIrYaxJ27MFPv+7kaTOw=
modernc.org/cc/v3 v3.40.0/go.mod h1:/bTg4dnWkSXowUO6ssQKnOV0yMVxDYNIsIrzqTFDGH0=
modernc.org/cc/v3 v3.41.0 h1:QoR1Sn3YWlmA1T4vLaKZfawdVtSiGx8H+cEojbC7v1Q=
modernc.org/cc/v3 v3.41.0/go.mod h1:Ni4zjJYJ04CDOhG7dn640WGfwBzfE0ecX8TyMB0Fv0Y=
modernc.org/cc/v4 v4.20.0 h1:45Or8mQfbUqJOG9WaxvlFYOAQO0lQ5RvqBcFCXngjxk=
modernc.org/cc/v4 v4.20.0/go.mod h1:HM7VJTZbUCR3rV8EYBi9wxnJ0ZBRiGE5OeGXNA0IsLQ=
modernc.org/ccgo/v3 v3.16.13 h1:Mkgdzl46i5F/CNR/Kj80Ri59hC8TKAhZrYSaqvkwzUw=
modernc.org/ccgo/v3 v3.16.13/go.mod h1:2Quk+5YgpImhPjv2Qsob1DnZ/4som1lJTodubIcoUkY=
modernc.org/ccgo/v3 v3.17.0 h1:o3OmOqx4/OFnl4Vm3G8Bgmqxnvxnh0nbxeT5p/dWChA=
modernc.org/ccgo/v3 v3.17.0/go.mod h1:Sg3fwVpmLvCUTaqEUjiBDAvshIaKDB0RXaf+zgqFu8I=
modernc.org/ccgo/v4 v4.16.0 h1:ofwORa6vx2FMm0916/CkZjpFPSR70VwTjUCe2Eg5BnA=
modernc.org/ccgo/v4 v4.16.0/go.mod h1:dkNyWIjFrVIZ68DTo36vHK+6/ShBn4ysU61So6PIqCI=
modernc.org/ccorpus v1.11.6 h1:J16RXiiqiCgua6+ZvQot4yUuUy8zxgqbqEEUuGPlISk=
modernc.org/ccorpus v1.11.6/go.mod h1:2gEUTrWqdpH2pXsmTM1ZkjeSrUWDpjMu2T6m29L/ErQ=
modernc.org/gc/v2 v2.4.1 h1:9cNzOqPyMJBvrUipmynX0ZohMhcxPtMccYgGOJdOiBw=
modernc.org/gc/v2 v2.4.1/go.mod h1:wzN5dK1AzVGoH6XOzc3YZ+ey/jPgYHLuVckd62P0GYU=
modernc.org/gc/v3 v3.0.0-20240107210532-573471604cb6 h1:5D53IMaUuA5InSeMu9eJtlQXS2NxAhyWQvkKEgXZhHI=
modernc.org/gc/v3 v3.0.0-20240107210532-573471604cb6/go.mod h1:Qz0X07sNOR1jWYCrJMEnbW/X55x206Q7Vt4mz6/wHp4=
modernc.org/httpfs v1.0.6 h1:AAgIpFZRXuYnkjftxTAZwMIiwEqAfk8aVB2/oA6nAeM=
modernc.org/httpfs v1.0.6/go.mod h1:7dosgurJGp0sPaRanU53W4xZYKh14wfzX420oZADeHM=
modernc.org/libc v1.29.0 h1:tTFRFq69YKCF2QyGNuRUQxKBm1uZZLubf6Cjh/pVHXs=
modernc.org/libc v1.29.0/go.mod h1:DaG/4Q3LRRdqpiLyP0C2m1B8ZMGkQ+cCgOIjEtQlYhQ=
modernc.org/libc v1.49.2 h1:Orwx0/7S7n5GCug2ANrqW0e7ZBu1mteep7xFkZCNydk=
modernc.org/libc v1.49.2/go.mod h1:yMZuGkn7pXbKfoT/M35gFJOAEdSKdxL0q64sF7KqCDo=
modernc.org/mathutil v1.6.0 h1:fRe9+AmYlaej+64JsEEhoWuAYBkOtQiMEU7n/XgfYi4=
modernc.org/mathutil v1.6.0/go.mod h1:Ui5Q9q1TR2gFm0AQRqQUaBWFLAhQpCwNcuhBOSedWPo=
modernc.org/memory v1.7.2 h1:Klh90S215mmH8c9gO98QxQFsY+W451E8AnzjoE2ee1E=
modernc.org/memory v1.7.2/go.mod h1:NO4NVCQy0N7ln+T9ngWqOQfi7ley4vpwvARR+Hjw95E=
modernc.org/memory v1.8.0 h1:IqGTL6eFMaDZZhEWwcREgeMXYwmW83LYW8cROZYkg+E=
modernc.org/memory v1.8.0/go.mod h1:XPZ936zp5OMKGWPqbD3JShgd/ZoQ7899TUuQqxY+peU=
modernc.org/opt v0.1.3 h1:3XOZf2yznlhC+ibLltsDGzABUGVx8J6pnFMS3E4dcq4=
modernc.org/opt v0.1.3/go.mod h1:WdSiB5evDcignE70guQKxYUl14mgWtbClRi5wmkkTX0=
modernc.org/sortutil v1.2.0 h1:jQiD3PfS2REGJNzNCMMaLSp/wdMNieTbKX920Cqdgqc=
modernc.org/sortutil v1.2.0/go.mod h1:TKU2s7kJMf1AE84OoiGppNHJwvB753OYfNl2WRb++Ss=
modernc.org/sqlite v1.28.0 h1:Zx+LyDDmXczNnEQdvPuEfcFVA2ZPyaD7UCZDjef3BHQ=
modernc.org/sqlite v1.28.0/go.mod h1:Qxpazz0zH8Z1xCFyi5GSL3FzbtZ3fvbjmywNogldEW0=
modernc.org/sqlite v1.29.5 h1:8l/SQKAjDtZFo9lkJLdk8g9JEOeYRG4/ghStDCCTiTE=
modernc.org/sqlite v1.29.5/go.mod h1:S02dvcmm7TnTRvGhv8IGYyLnIt7AS2KPaB1F/71p75U=
modernc.org/strutil v1.1.3 h1:fNMm+oJklMGYfU9Ylcywl0CO5O6nTfaowNsh2wpPjzY=
modernc.org/strutil v1.1.3/go.mod h1:MEHNA7PdEnEwLvspRMtWTNnp2nnyvMfkimT1NKNAGbw=
modernc.org/strutil v1.2.0 h1:agBi9dp1I+eOnxXeiZawM8F4LawKv4NzGWSaLfyeNZA=
modernc.org/strutil v1.2.0/go.mod h1:/mdcBmfOibveCTBxUl5B5l6W+TTH1FXPLHZE6bTosX0=
modernc.org/tcl v1.15.2 h1:C4ybAYCGJw968e+Me18oW55kD/FexcHbqH2xak1ROSY=
modernc.org/tcl v1.15.2/go.mod h1:3+k/ZaEbKrC8ePv8zJWPtBSW0V7Gg9g8rkmhI1Kfs3c=
modernc.org/token v1.0.1 h1:A3qvTqOwexpfZZeyI0FeGPDlSWX5pjZu9hF4lU+EKWg=
modernc.org/token v1.0.1/go.mod h1:UGzOrNV1mAFSEB63lOFHIpNRUVMvYTc6yu1SMY/XTDM=
modernc.org/token v1.1.0 h1:Xl7Ap9dKaEs5kLoOQeQmPWevfnk/DM5qcLcYlA8ys6Y=
modernc.org/token v1.1.0/go.mod h1:UGzOrNV1mAFSEB63lOFHIpNRUVMvYTc6yu1SMY/XTDM=
modernc.org/z v1.7.3 h1:zDJf6iHjrnB+WRD88stbXokugjyc0/pB91ri1gO6LZY=
modernc.org/z v1.7.3/go.mod h1:Ipv4tsdxZRbQyLq9Q1M6gdbkxYzdlrciF2Hi/lS7nWE=
nhooyr.io/websocket v1.8.10 h1:mv4p+MnGrLDcPlBoWsvPP7XCzTYMXP9F9eIGoKbgx7Q=
nhooyr.io/websocket v1.8.10/go.mod h1:rN9OFWIUwuxg4fR5tELlYC04bXYowCP9GX47ivo2l+c=
nhooyr.io/websocket v1.8.11 h1:f/qXNc2/3DpoSZkHt1DQu6rj4zGC8JmkkLkWss0MgN0=
nhooyr.io/websocket v1.8.11/go.mod h1:rN9OFWIUwuxg4fR5tELlYC04bXYowCP9GX47ivo2l+c=