Added !poker and auth entry point
This commit is contained in:
@@ -4,9 +4,10 @@ import (
|
||||
"log"
|
||||
"os"
|
||||
|
||||
"streambot_twitch/internal/auth"
|
||||
auth "streambot_twitch/internal/auth"
|
||||
"streambot_twitch/internal/chat"
|
||||
"streambot_twitch/internal/commands"
|
||||
"streambot_twitch/internal/points"
|
||||
twitchapi "streambot_twitch/internal/twitchapi"
|
||||
tests "streambot_twitch/internal/tests"
|
||||
twitch "github.com/gempir/go-twitch-irc/v4"
|
||||
@@ -14,7 +15,7 @@ import (
|
||||
|
||||
func main() {
|
||||
go func() {
|
||||
if err := oauth.StartOAuthServer(":8080"); err != nil {
|
||||
if err := auth.StartOAuthServer(":8080"); err != nil {
|
||||
log.Fatalf("OAuth server error: %v", err)
|
||||
}
|
||||
}()
|
||||
@@ -22,9 +23,9 @@ func main() {
|
||||
log.Println("OAuth server started on port 8080")
|
||||
|
||||
botUsername := os.Getenv("nz_chatterbot")
|
||||
botOAuth :+ os.Getenv("BOT_OAUTH")
|
||||
botOAuth := os.Getenv("BOT_OAUTH")
|
||||
channel := os Getenv("brycefromnz101")
|
||||
clientID := os.Getenv("TWITCH_CLIENTID")
|
||||
clientID := os.Getenv("TWITCH_CLIENT_ID")
|
||||
clientSecret := os.Getenv("TWITCH_CLIENT_SECRET")
|
||||
botChannel := botUsername
|
||||
|
||||
@@ -52,6 +53,14 @@ log.Println("OAuth server started on port 8080")
|
||||
log.Println("All startup tests passed. Starting bot. . .")
|
||||
// END of TESTS
|
||||
|
||||
// load chat points
|
||||
if err := points.LoadPoints(); err != nil {
|
||||
log.Fatalf("Failed to load points: %v", err)
|
||||
}
|
||||
|
||||
// make sure points are saved on exit
|
||||
defer points.SavePoints()
|
||||
|
||||
// load custom commands
|
||||
if err := commands.LoadCommands(); err != nil {
|
||||
log.Fatalf("Failed to Load Custom Commands: %v", err)
|
||||
|
13
cmd/oauth/main.go
Normal file
13
cmd/oauth/main.go
Normal file
@@ -0,0 +1,13 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"log"
|
||||
|
||||
auth "streambot_twitch/internal/auth"
|
||||
)
|
||||
|
||||
func main() {
|
||||
if err := auth.StartOAuthServer(":8080"); err != nil {
|
||||
log.Fatalf("OAuth server error: %v", err)
|
||||
}
|
||||
}
|
@@ -1,4 +1,4 @@
|
||||
package oauth
|
||||
package auth
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
|
@@ -91,6 +91,12 @@ func HandleMessage(client *twitch.Client, apiClient interface{}, message twitch.
|
||||
return
|
||||
}
|
||||
|
||||
// dispatch poker/table commands
|
||||
if strings.HasPrefix(strings.ToLower(msg), "!poker") || strings.HasPrefix(strings.ToLower(msg), "!table") {
|
||||
HandlePokerCommand(client, message, user, channel, msg)
|
||||
return
|
||||
}
|
||||
|
||||
// Dispatch custom/default commands
|
||||
HandleCustomCommands(client, message, user, channel, botUsername)
|
||||
}
|
||||
|
154
internal/chat/poker.go
Normal file
154
internal/chat/poker.go
Normal file
@@ -0,0 +1,154 @@
|
||||
package chat
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math/rand"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
twitch "github.com/gempir/go-twitch-irc/v4"
|
||||
"streambot_twitch/internal/points"
|
||||
)
|
||||
|
||||
// card
|
||||
type Card struct {
|
||||
Rank, Suit string
|
||||
}
|
||||
|
||||
var (
|
||||
suits = []string{" of Hearts", " of Diamnods", " of Clubs", " of Spades"}
|
||||
ranks = []string{"2", "3", "4", "5", "6", "7", "8", "9", "10", "J", "Q", "K", "A"}
|
||||
baseDeck []Card
|
||||
)
|
||||
|
||||
func init() {
|
||||
// build 2 decks (no Jokers) 104 cards
|
||||
for d := 0; d < 2; d++ {
|
||||
for _, s := range suits {
|
||||
for _, r := range ranks {
|
||||
baseDeck = append(baseDeck, Card{Rank: r, Suit: s})
|
||||
}
|
||||
}
|
||||
}
|
||||
rand.Seed(time.Now().UnixNano())
|
||||
}
|
||||
|
||||
// impliment !poker or !table <bet>
|
||||
func HandlePokerCommand(
|
||||
client *twitch.Client,
|
||||
message twitch.PrivateMessage,
|
||||
user twitch.User,
|
||||
channel, msg string,
|
||||
) {
|
||||
parts := strings.Fields(msg)
|
||||
if len(parts) < 2 {
|
||||
client.Say(channel, fmt.Sprintf("@%s Usage: !poker <bet>", user.DisplayName))
|
||||
return
|
||||
}
|
||||
bet, err := strconv.Atoi(parts[1])
|
||||
if err != nil || bet <= 0 {
|
||||
client.Say(channel, fmt.Sprintf("@%s Invalid bet amount", user.DisplayName))
|
||||
return
|
||||
}
|
||||
|
||||
login := strings.ToLower(user.Name)
|
||||
// load or init user points
|
||||
balance := points.GetPoints(login)
|
||||
if bet > ballance {
|
||||
client.Say(channel, fmt.Sprintf("@%s You have %d points, bet lower", user.DisplayName, balance))
|
||||
return
|
||||
}
|
||||
// Deduct the bet
|
||||
balance, err = points.AddPoints(login, -bet)
|
||||
if err != nil {
|
||||
client.Say(channel, fmt.Sprintf("@%s Error updating points: %v", user.DisplayName, err))
|
||||
return
|
||||
}
|
||||
|
||||
// shuffle deck
|
||||
deck := make([]Card, len(baseDeck))
|
||||
copy(deck, baseDeck)
|
||||
rand.Shuffle(len(deck), func(i, j int) {deck[i], deck[j] = deck[j], deck[i]})
|
||||
|
||||
// deal 2 cards each
|
||||
player := []Card{deck[0], deck[1]}
|
||||
dealer := []Card{deck[2], deck[3]}
|
||||
|
||||
// compute hand values
|
||||
pv := handValue(player)
|
||||
dv := handValue(dealer)
|
||||
|
||||
// Determine outcome and payout multiplier
|
||||
var net int
|
||||
var outcome string
|
||||
switch {
|
||||
case pv > 21:
|
||||
outcome = "FBPenalty Bust! You lose"
|
||||
net = 0
|
||||
case pv == 21:
|
||||
outcome = "BLACKJACK! GoatEmotey"
|
||||
net = bet * 2
|
||||
case dv > 21:
|
||||
outcome = "GoldPLZ Dealer bust! You win"
|
||||
net = int(float64(bet) * 1.5)
|
||||
case pv > dv:
|
||||
outcome = "OhMyDog You Win"
|
||||
net int(float64(bet) * 1.3)
|
||||
case pv < dv:
|
||||
outcome = "cmonBruh You lose"
|
||||
net = 0
|
||||
default:
|
||||
outcome = "PunchTrees Push"
|
||||
net = bet
|
||||
}
|
||||
|
||||
// Add winnings
|
||||
balance, err = points.AddPoints(login, net)
|
||||
if err != nil {
|
||||
client.Say(channel, fmt.Sprintf("@%s Error updating Points: %v", user.DisplayName, err))
|
||||
return
|
||||
}
|
||||
|
||||
// format a hand for display
|
||||
fmtHand := func(h []Card) string {
|
||||
var parts []string
|
||||
for _, c := range h {
|
||||
parts = append(parts, c.Rank+c.Suit)
|
||||
}
|
||||
return strings.Join(parts, ",")
|
||||
}
|
||||
|
||||
// post result
|
||||
client.Say(channel, fmt.Sprintf("@%s You: [%s]=%d Dealer: [%s]=%d => %s | Bet: %d Net: %d Ballance: %d", user.DisplayName,
|
||||
fmtHand(player), pv,
|
||||
fmtHand(dealer), dv,
|
||||
outcome,
|
||||
bet, net, balance,
|
||||
))
|
||||
}
|
||||
|
||||
// compute BlackJack style value (A = 11 or 1)
|
||||
func handValue(hand []Card) int {
|
||||
total := 0
|
||||
aces := 0
|
||||
for _, c := range hand {
|
||||
switch c.Rank {
|
||||
case "J", "Q", "K":
|
||||
total += 10
|
||||
case "A":
|
||||
total += 11
|
||||
aces++
|
||||
default:
|
||||
v, _ := strconv.Atoi(c.Rank)
|
||||
total += v
|
||||
}
|
||||
}
|
||||
|
||||
// convert A from 11 to 1 while busting
|
||||
for total > 21 && aces > 0 {
|
||||
total -= 10
|
||||
aces--
|
||||
}
|
||||
return total
|
||||
}
|
84
internal/points/points.go
Normal file
84
internal/points/points.go
Normal file
@@ -0,0 +1,84 @@
|
||||
package points
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"sync"
|
||||
)
|
||||
|
||||
const (
|
||||
dataDir = "internal/storage"
|
||||
pointsFile = "points.json"
|
||||
)
|
||||
|
||||
var (
|
||||
mu sync.Mutex
|
||||
pts map[string]int
|
||||
)
|
||||
|
||||
const DefaultPoints = 100000
|
||||
|
||||
// init or load points from disk
|
||||
func LoadPoints() error {
|
||||
mu.Lock()
|
||||
defer mu.Unlock()
|
||||
pts = make(map[string]int)
|
||||
path := filepath.Join(dataDir, pointsFile)
|
||||
|
||||
data, err := ioutil.ReadFile(path)
|
||||
if err != nil {
|
||||
if os.IsNotExist(err) {
|
||||
return nil
|
||||
}
|
||||
return err
|
||||
}
|
||||
return json.Unmarshal(data, &pts)
|
||||
}
|
||||
|
||||
// save balances to disk
|
||||
func SavePoints() error {
|
||||
mu.Lock()
|
||||
data, err := json.MarshalIndent(pts, "", " ")
|
||||
mu.Unlock()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err := os.MkdirAll(dataDir, 0755); err != nil {
|
||||
return err
|
||||
}
|
||||
return ioutil.WriteFile(filepath.Join(dataDir, pointsFile), data, 0644)
|
||||
}
|
||||
|
||||
// return point balance for user, init if needed
|
||||
func GetPoints(user string) int {
|
||||
mu.Lock()
|
||||
defer mu.Unlock()
|
||||
key := strings.ToLower(user)
|
||||
bal, ok := pts[key]
|
||||
if !ok {
|
||||
pts[key] = DefaultPoints
|
||||
bal = DefaultPoints
|
||||
}
|
||||
return bal
|
||||
}
|
||||
|
||||
// add points to user's bal, save & return new bal
|
||||
func AddPoints(user string, delta int) (int error) {
|
||||
mu.Lock()
|
||||
key := strings.ToLower(user)
|
||||
bal, ok := pts[key]
|
||||
if !ok {
|
||||
bal = DefaultPoints
|
||||
}
|
||||
bal += delta
|
||||
pts[key] = bal
|
||||
mu.Unlock()
|
||||
|
||||
if err := SavePoints(); err != nil {
|
||||
return bal, err
|
||||
}
|
||||
return bal, nil
|
||||
}
|
Reference in New Issue
Block a user