Skip to content

Commit

Permalink
feat: Many bet types
Browse files Browse the repository at this point in the history
  • Loading branch information
lcox74 committed Apr 27, 2024
1 parent 4e09457 commit df77db1
Show file tree
Hide file tree
Showing 11 changed files with 523 additions and 62 deletions.
192 changes: 191 additions & 1 deletion applications/snailrace/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,16 @@ func RegisterSnailraceApp(bot *framework.Bot) framework.Route {
&Snailrace{}, // [NOP]

framework.NewRoute(bot, "host", &SnailraceHostSubCommand{}),
framework.NewRoute(bot, "bet", &SnailraceBetSubCommand{}),
framework.NewRoute(bot, "bet",
&SnailraceBetSubCommand{}, // Handle Bet Events

framework.NewRoute(bot, "win", &SnailraceBetSubCommand{}),
framework.NewRoute(bot, "place", &SnailraceBetSubCommand{}),
framework.NewRoute(bot, "eachway", &SnailraceBetSubCommand{}),
framework.NewRoute(bot, "quinella", &SnailraceBetSubCommand{}),
framework.NewRoute(bot, "exacta", &SnailraceBetSubCommand{}),
framework.NewRoute(bot, "trifecta", &SnailraceBetSubCommand{}),
),
)
}

Expand All @@ -41,6 +50,187 @@ func (s Snailrace) GetDefinition() *discordgo.ApplicationCommand {
Name: "host",
Description: "Host a snailrace",
},
{
Type: discordgo.ApplicationCommandOptionSubCommandGroup,
Name: "bet",
Description: "Bet on a race",
Options: []*discordgo.ApplicationCommandOption{
{
Type: discordgo.ApplicationCommandOptionSubCommand,
Name: "win",
Description: "Bet on a snail to win",
Options: []*discordgo.ApplicationCommandOption{
{
Type: discordgo.ApplicationCommandOptionString,
Name: "race_id",
Description: "The ID of the race to place a bet on",
Required: true,
},
{
Type: discordgo.ApplicationCommandOptionInteger,
Name: "bet_amount",
Description: "The amount to bet",
Required: true,
},
{
Type: discordgo.ApplicationCommandOptionInteger,
Name: "snail_index_1",
Description: "The index of the snail to win",
Required: true,
},
},
},
{
Type: discordgo.ApplicationCommandOptionSubCommand,
Name: "place",
Description: "Bet on a snail to place in the top 3",
Options: []*discordgo.ApplicationCommandOption{
{
Type: discordgo.ApplicationCommandOptionString,
Name: "race_id",
Description: "The ID of the race to place a bet on",
Required: true,
},
{
Type: discordgo.ApplicationCommandOptionInteger,
Name: "bet_amount",
Description: "The amount to bet",
Required: true,
},
{
Type: discordgo.ApplicationCommandOptionInteger,
Name: "snail_index_1",
Description: "The index of the snail to place",
Required: true,
},
},
},
{
Type: discordgo.ApplicationCommandOptionSubCommand,
Name: "eachway",
Description: "Bet on a snail to place in the top 3 and/or win",
Options: []*discordgo.ApplicationCommandOption{
{
Type: discordgo.ApplicationCommandOptionString,
Name: "race_id",
Description: "The ID of the race to place a bet on",
Required: true,
},
{
Type: discordgo.ApplicationCommandOptionInteger,
Name: "bet_amount",
Description: "The amount to bet",
Required: true,
},
{
Type: discordgo.ApplicationCommandOptionInteger,
Name: "snail_index_1",
Description: "The index of the snail to win/place",
Required: true,
},
},
},
{
Type: discordgo.ApplicationCommandOptionSubCommand,
Name: "quinella",
Description: "Bet on two snails to win and place 2nd in any order",
Options: []*discordgo.ApplicationCommandOption{
{
Type: discordgo.ApplicationCommandOptionString,
Name: "race_id",
Description: "The ID of the race to place a bet on",
Required: true,
},
{
Type: discordgo.ApplicationCommandOptionInteger,
Name: "bet_amount",
Description: "The amount to bet",
Required: true,
},
{
Type: discordgo.ApplicationCommandOptionInteger,
Name: "snail_index_1",
Description: "The index of the snail to win or place 2nd",
Required: true,
},
{
Type: discordgo.ApplicationCommandOptionInteger,
Name: "snail_index_2",
Description: "The index of the snail to win or place 2nd",
Required: true,
},
},
},
{
Type: discordgo.ApplicationCommandOptionSubCommand,
Name: "exacta",
Description: "Bet on two snails to win and place 2nd in order",
Options: []*discordgo.ApplicationCommandOption{
{
Type: discordgo.ApplicationCommandOptionString,
Name: "race_id",
Description: "The ID of the race to place a bet on",
Required: true,
},
{
Type: discordgo.ApplicationCommandOptionInteger,
Name: "bet_amount",
Description: "The amount to bet",
Required: true,
},
{
Type: discordgo.ApplicationCommandOptionInteger,
Name: "snail_index_1",
Description: "The index of the snail to win",
Required: true,
},
{
Type: discordgo.ApplicationCommandOptionInteger,
Name: "snail_index_2",
Description: "The index of the snail to place 2nd",
Required: true,
},
},
},
{
Type: discordgo.ApplicationCommandOptionSubCommand,
Name: "trifecta",
Description: "Bet on three snails to come in the top 3 in order",
Options: []*discordgo.ApplicationCommandOption{
{
Type: discordgo.ApplicationCommandOptionString,
Name: "race_id",
Description: "The ID of the race to place a bet on",
Required: true,
},
{
Type: discordgo.ApplicationCommandOptionInteger,
Name: "bet_amount",
Description: "The amount to bet",
Required: true,
},
{
Type: discordgo.ApplicationCommandOptionInteger,
Name: "snail_index_1",
Description: "The index of the snail to win",
Required: true,
},
{
Type: discordgo.ApplicationCommandOptionInteger,
Name: "snail_index_2",
Description: "The index of the snail to place 2nd",
Required: true,
},
{
Type: discordgo.ApplicationCommandOptionInteger,
Name: "snail_index_3",
Description: "The index of the snail to place 3rd",
Required: true,
},
},
},
},
},
},
}
}
Expand Down
98 changes: 92 additions & 6 deletions applications/snailrace/render/finish_render.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,15 @@ import (
"github.com/bwmarrin/discordgo"
)

var betPayout = map[int]func(snailrace.RaceState, snailrace.UserBet, map[int]int, func(string, int64)){
snailrace.BetTypeWin: payWinBet,
snailrace.BetTypePlace: payPlaceBet,
snailrace.BetTypeEachWay: payEachWayBet,
snailrace.BetTypeQuinella: payQuinellaBet,
snailrace.BetTypeExacta: payExactaBet,
snailrace.BetTypeTrifecta: payTrifectaBet,
}

func finishedMessage(state snailrace.RaceState, creditUser func(string, int64)) (string, []discordgo.MessageComponent) {

description := fmt.Sprintf("```\nRace ID: %s\n\n%s\n", state.Race.Id, buildTrack(state))
Expand All @@ -31,12 +40,8 @@ func finishedMessage(state snailrace.RaceState, creditUser func(string, int64))

// Payout the winners
for _, userBet := range state.Race.UserBets {
if place, ok := state.Place[userBet.SnailIndex]; ok {
if place == 1 {
odds := snailrace.CalculateOdds(state.Race.Pool, state.Race.Snails[userBet.SnailIndex].Pool)
win := int64(float64(userBet.Amount) * odds)
creditUser(userBet.UserId, win)
}
if payout, ok := betPayout[userBet.Type]; ok {
payout(state, userBet, state.Place, creditUser)
}
}

Expand All @@ -49,3 +54,84 @@ func finishedMessage(state snailrace.RaceState, creditUser func(string, int64))
},
}
}

func payWinBet(state snailrace.RaceState, bet snailrace.UserBet, place map[int]int, creditUser func(string, int64)) {
if place, ok := place[bet.Snail1Index]; ok {
if place == 1 {
odds := snailrace.CalculateOdds(state.Race.Pool, state.Race.Snails[bet.Snail1Index].Pool)
returns := int64(float64(bet.Amount) * odds)
creditUser(bet.UserId, returns)
}
}
}
func payPlaceBet(state snailrace.RaceState, bet snailrace.UserBet, place map[int]int, creditUser func(string, int64)) {
if place, ok := place[bet.Snail1Index]; ok {
if place <= 3 {
odds := snailrace.CalculatePlaceOdds(state.Race.Pool, state.Race.Snails[bet.Snail1Index].Pool)
returns := int64(float64(bet.Amount) * odds)
creditUser(bet.UserId, returns)
}
}
}
func payEachWayBet(state snailrace.RaceState, bet snailrace.UserBet, place map[int]int, creditUser func(string, int64)) {
if place, ok := place[bet.Snail1Index]; ok {

if place <= 3 {
// Calculate the place amount as half the bet amount is placed on
// the win and the other half is on a place
amount := float64(bet.Amount) / 2.0

// Check if the snail placed
placeOdds := snailrace.CalculatePlaceOdds(state.Race.Pool, state.Race.Snails[bet.Snail1Index].Pool)
returns := int64(amount * placeOdds)

// Check if the snail won
if place == 1 {
winOdds := snailrace.CalculateOdds(state.Race.Pool, state.Race.Snails[bet.Snail1Index].Pool)
win := int64(amount * winOdds)
returns += win
}

creditUser(bet.UserId, returns)
}
}
}
func payQuinellaBet(state snailrace.RaceState, bet snailrace.UserBet, place map[int]int, creditUser func(string, int64)) {
snail1Place, ok1 := place[bet.Snail1Index]
snail2Place, ok2 := place[bet.Snail2Index]
if ok1 && ok2 {
if (snail1Place == 1 && snail2Place == 2) || (snail1Place == 2 && snail2Place == 1) {
odds := snailrace.CalculatePlaceOdds(state.Race.Pool, state.Race.Snails[bet.Snail1Index].Pool)
odds *= snailrace.CalculatePlaceOdds(state.Race.Pool, state.Race.Snails[bet.Snail2Index].Pool)
returns := int64(float64(bet.Amount) * odds)
creditUser(bet.UserId, returns)
}
}
}
func payExactaBet(state snailrace.RaceState, bet snailrace.UserBet, place map[int]int, creditUser func(string, int64)) {
snail1Place, ok1 := place[bet.Snail1Index]
snail2Place, ok2 := place[bet.Snail2Index]
if ok1 && ok2 {
if snail1Place == 1 && snail2Place == 2 {
odds := snailrace.CalculateOdds(state.Race.Pool, state.Race.Snails[bet.Snail1Index].Pool)
odds *= snailrace.CalculatePlaceOdds(state.Race.Pool, state.Race.Snails[bet.Snail2Index].Pool)
returns := int64(float64(bet.Amount) * odds)
creditUser(bet.UserId, returns)
}
}
}
func payTrifectaBet(state snailrace.RaceState, bet snailrace.UserBet, place map[int]int, creditUser func(string, int64)) {
snail1Place, ok1 := place[bet.Snail1Index]
snail2Place, ok2 := place[bet.Snail2Index]
snail3Place, ok3 := place[bet.Snail3Index]

if ok1 && ok2 && ok3 {
if snail1Place == 1 && snail2Place == 2 && snail3Place == 3 {
odds := snailrace.CalculateOdds(state.Race.Pool, state.Race.Snails[bet.Snail1Index].Pool)
odds *= snailrace.CalculatePlaceOdds(state.Race.Pool, state.Race.Snails[bet.Snail2Index].Pool)
odds *= snailrace.CalculatePlaceOdds(state.Race.Pool, state.Race.Snails[bet.Snail3Index].Pool)
returns := int64(float64(bet.Amount) * odds)
creditUser(bet.UserId, returns)
}
}
}
Loading

0 comments on commit df77db1

Please sign in to comment.