This commit is contained in:
a 2022-04-13 19:20:00 -05:00
parent a5f78f4d9d
commit 95e6383f94
8 changed files with 187 additions and 35 deletions

View File

@ -9,6 +9,7 @@ import (
"git.tuxpa.in/a/card_id/common/game" "git.tuxpa.in/a/card_id/common/game"
"git.tuxpa.in/a/card_id/common/game/card" "git.tuxpa.in/a/card_id/common/game/card"
"git.tuxpa.in/a/card_id/common/game/score"
) )
func main() { func main() {
@ -16,15 +17,27 @@ func main() {
if err != nil { if err != nil {
log.Panicln(err) log.Panicln(err)
} }
g := game.Game{Dealer: deal, Lives: 3} g := game.Game{Dealer: deal, Lives: 3}
trial := g.CreateTrial(3, 1) trial := g.CreateTrial(3, 1)
g.CurrentTrial = 1
fmt.Println("type c[n] to select a card, e.g. c1")
fmt.Println("exit to exit")
for { for {
if trial != nil { if trial != nil {
if trial.CheckSelection() { sc, lives := trial.CheckSelection()
fmt.Print("\n match found!!!") if sc != 0 {
fmt.Println(" match found!!!")
g.Combo = g.Combo + 1
g.Score = g.Score + sc*score.DefaultTable.Ratio(g.Combo)*g.CurrentTrial
} else {
g.Combo = 0
} }
g.Lives = g.Lives + lives
msg := fmt.Sprintf(`
lives: %0.4v | score: %d | combo: %d
`, g.Lives, g.Score, g.Combo)
fmt.Printf(msg)
} }
fmt.Printf("\ncardid > ") fmt.Printf("\ncardid > ")
var args [4]string var args [4]string
@ -45,20 +58,15 @@ func main() {
case "select", "sel", "c": case "select", "sel", "c":
if alen > 1 { if alen > 1 {
num, _ := strconv.Atoi(args[1]) num, _ := strconv.Atoi(args[1])
cd, err := trial.SelectCard(num) _, err := trial.SelectCard(num)
if err != nil { if err != nil {
log.Println(err) log.Println(err)
} }
if cd.Id > 0 {
msg := fmt.Sprintf(`
card %d was %s | lives: %d
current hand:
%s`, num, cd.Name, trial.Lives, trial.ShowString())
fmt.Printf(msg)
}
} else { } else {
trial.SelectCard(0) trial.SelectCard(0)
} }
fmt.Printf("hand: %s\n", trial.ShowString())
case "debug": case "debug":
fmt.Println(trial) fmt.Println(trial)
case "exit", "quit", "q": case "exit", "quit", "q":

1
common/data/combo.go Normal file
View File

@ -0,0 +1 @@
package data

View File

@ -1,16 +1,47 @@
package card package card
import "git.tuxpa.in/a/card_id/common/data" import (
"strings"
"git.tuxpa.in/a/card_id/common/data"
"lukechampine.com/frand"
)
type Card struct { type Card struct {
Id int `json:"id"` Id int `json:"id"`
Name string `json:"name"` Name string `json:"name"`
CleanName string `json:"clean_name"`
Rate float64 `json:"rate"` Rate float64 `json:"rate"`
BonusLife bool `json:"bonus_life"`
} }
func (c *Card) FromResult(d data.Result) Card { func (c *Card) FromResult(d data.Result) Card {
c.Id = d.Id c.Id = d.Id
c.Name = d.Name c.Name = d.Name
c.Rate = d.Rate c.Rate = d.Rate
c.CleanName = strings.ReplaceAll(strings.TrimSpace(stripNum(c.Name)), " ", " ")
return *c return *c
} }
func (c *Card) CopyWithBonus(chance float64) Card {
return Card{
Id: c.Id,
Rate: c.Rate,
Name: c.Name,
CleanName: c.CleanName,
BonusLife: (frand.Float64() <= chance),
}
}
func stripNum(s string) string {
var result strings.Builder
for i := 0; i < len(s); i++ {
b := s[i]
if !('0' <= b && b <= '9') {
result.WriteByte(b)
}
}
return result.String()
}

View File

@ -21,6 +21,25 @@ func NewDealer() *Dealer {
} }
} }
func (g *Dealer) CardNames() []string {
out := map[string]struct{}{}
for _, br := range g.Brands {
for _, c := range br.RewardDeck.Cards {
out[c.CleanName] = struct{}{}
}
if br.SpecialDeck != nil {
for _, c := range br.SpecialDeck.Cards {
out[c.CleanName] = struct{}{}
}
}
}
keys := make([]string, 0, len(out))
for k := range out {
keys = append(keys, k)
}
return keys
}
func (g *Dealer) ReadFromRoot(datadir string) (*Dealer, error) { func (g *Dealer) ReadFromRoot(datadir string) (*Dealer, error) {
if datadir == "" { if datadir == "" {
datadir = "./data" datadir = "./data"

View File

@ -13,10 +13,13 @@ type Deck struct {
Cards []Card Cards []Card
TotalProbability float64 TotalProbability float64
BonusLifeProbability float64
} }
func NewDeck(r data.Results) *Deck { func NewDeck(r data.Results) *Deck {
out := &Deck{} out := &Deck{}
out.BonusLifeProbability = 0.005
out.Cards = make([]Card, 0, len(r)) out.Cards = make([]Card, 0, len(r))
for _, v := range r { for _, v := range r {
out.Cards = append(out.Cards, new(Card).FromResult(v)) out.Cards = append(out.Cards, new(Card).FromResult(v))
@ -31,7 +34,7 @@ func (t *Deck) Draw() Card {
for _, v := range t.Cards { for _, v := range t.Cards {
sofar = sofar + v.Rate sofar = sofar + v.Rate
if sofar >= selector-0.000000001 { if sofar >= selector-0.000000001 {
return v return v.CopyWithBonus(t.BonusLifeProbability)
} }
} }
return Card{ return Card{

View File

@ -6,8 +6,31 @@ import (
) )
type Game struct { type Game struct {
Lives int Lives float64
Dealer *card.Dealer Score int
Combo int
BestCombo int
CurrentTrial int
Trial *Trial
Trials []Trial
Player string
PlayerId string
Dealer *card.Dealer `json:"-"`
}
func (g *Game) New(user string, dealer *card.Dealer) *Game {
return &Game{
Dealer: dealer,
Player: user,
}
}
func (g *Game) Resolve(action string, args []string) {
} }
func (g *Game) CreateTrial(pairs int, extra int) *Trial { func (g *Game) CreateTrial(pairs int, extra int) *Trial {
@ -37,7 +60,7 @@ func (g *Game) CreateTrial(pairs int, extra int) *Trial {
} }
frand.Shuffle(len(cards), func(i, j int) { cards[i], cards[j] = cards[j], cards[i] }) frand.Shuffle(len(cards), func(i, j int) { cards[i], cards[j] = cards[j], cards[i] })
trial := NewTrial(g.Lives) trial := NewTrial()
for k, v := range cards { for k, v := range cards {
trial.Cards[k+1] = v trial.Cards[k+1] = v
} }

View File

@ -0,0 +1,71 @@
package score
type ComboTable interface {
Ratio(int) int
}
type MapTable struct {
m map[int]int
}
func (t *MapTable) Ratio(i int) int {
if v, ok := t.m[i]; ok {
return v
}
return 1
}
var DefaultTable ComboTable = &MapTable{
m: map[int]int{
0: 1,
1: 2,
2: 4,
3: 7,
4: 12,
5: 19,
6: 28,
7: 39,
8: 52,
9: 67,
10: 84,
11: 103,
12: 124,
13: 147,
14: 172,
15: 199,
16: 228,
17: 259,
18: 292,
19: 327,
20: 364,
21: 364,
22: 364,
23: 364,
24: 364,
25: 364,
26: 364,
27: 364,
28: 364,
29: 364,
30: 364,
31: 364,
32: 364,
33: 364,
34: 364,
35: 364,
36: 364,
37: 364,
38: 364,
39: 364,
40: 364,
41: 364,
42: 364,
43: 364,
44: 364,
45: 364,
46: 364,
47: 364,
48: 364,
49: 364,
50: 364,
}}

View File

@ -12,7 +12,6 @@ import (
type Trial struct { type Trial struct {
Cards map[int]card.Card Cards map[int]card.Card
Lives int
SelectionState int SelectionState int
PendingSelection [2]int PendingSelection [2]int
@ -21,9 +20,8 @@ type Trial struct {
History [][2]int History [][2]int
} }
func NewTrial(lives int) *Trial { func NewTrial() *Trial {
return &Trial{ return &Trial{
Lives: lives,
Cards: make(map[int]card.Card, 7), Cards: make(map[int]card.Card, 7),
Shown: make(map[int]card.Card, 7), Shown: make(map[int]card.Card, 7),
PendingSelection: [2]int{-1, -1}, PendingSelection: [2]int{-1, -1},
@ -34,9 +32,6 @@ func (t *Trial) SelectCard(id int) (card.Card, error) {
if id > len(t.Cards) { if id > len(t.Cards) {
return card.Card{}, errs.Invalid("index out of bounds") return card.Card{}, errs.Invalid("index out of bounds")
} }
if t.Lives == 0 {
return card.Card{}, errs.Logic("game over")
}
switch t.SelectionState { switch t.SelectionState {
case 0: // start selection case 0: // start selection
t.SelectionState = 1 t.SelectionState = 1
@ -51,36 +46,37 @@ func (t *Trial) SelectCard(id int) (card.Card, error) {
} }
} }
func (t *Trial) CheckSelection() bool { func (t *Trial) CheckSelection() (points int, lifechange float64) {
switch t.SelectionState { switch t.SelectionState {
case 0, 1: case 0, 1:
return false return
default: default:
} }
defer func() { defer func() {
t.SelectionState = 0 t.SelectionState = 0
}() }()
lifechange = -1
c1, ok := t.Cards[t.PendingSelection[0]] c1, ok := t.Cards[t.PendingSelection[0]]
if !ok { if !ok {
return false return
} }
c2, ok := t.Cards[t.PendingSelection[1]] c2, ok := t.Cards[t.PendingSelection[1]]
if !ok { if !ok {
return false return
} }
if c1.Id == c2.Id { if c1.Id == c2.Id {
if c1.Name == c2.Name { if c1.Name == c2.Name {
t.Shown[t.PendingSelection[0]] = c1 t.Shown[t.PendingSelection[0]] = c1
t.Shown[t.PendingSelection[1]] = c2 t.Shown[t.PendingSelection[1]] = c2
return true if c1.BonusLife || c2.BonusLife {
return 10, 1
}
return 10, 0.35
} }
} }
t.History = append(t.History, t.PendingSelection) t.History = append(t.History, t.PendingSelection)
t.PendingSelection = [2]int{-1, -1} t.PendingSelection = [2]int{-1, -1}
t.Lives = t.Lives - 1 return 0, -1
return false
} }
func (t *Trial) Show() map[int]card.Card { func (t *Trial) Show() map[int]card.Card {
@ -102,8 +98,8 @@ func (t *Trial) ShowString() string {
} }
outs := "" outs := ""
for _, k := range t.CardKeys() { for n, k := range t.CardKeys() {
piece := "[???]" piece := fmt.Sprintf("[??%d??]", n+1)
if v, ok := out[k]; ok { if v, ok := out[k]; ok {
piece = fmt.Sprintf("[%s]", v.Name) piece = fmt.Sprintf("[%s]", v.Name)
} }