package game import ( "fmt" "log" "strconv" "strings" ) type GameStatus int const ( StatusLobby = iota StatusReady StatusPlaying StatusStop StatusSentinalWin StatusScourgeWin StatusDraw ) const ( SentinalID = 1 ScourgeID = 2 ) func (g GameStatus) String() string { return []string{"Lobby", "Ready", "Playing", "Stopped", "SentinalWin", "ScougeWin", "Draw"}[g] } type Game struct { GameBoard *Board SentinalPlayer *Player ScourgePlayer *Player SentinalDeck *Deck ScourgeDeck *Deck CurrentTurn int CardBuffer *Deck CanDraw bool HasDrawn bool Status GameStatus } func NewGame() *Game { deckA := NewDeck() deckB := NewDeck() deckA.Shuffle() deckB.Shuffle() return &Game{ GameBoard: NewBoard(), SentinalPlayer: NewPlayer("Sentinal", SentinalID), ScourgePlayer: NewPlayer("Scourge", ScourgeID), SentinalDeck: deckA, ScourgeDeck: deckB, CurrentTurn: 0, //start with no turn CardBuffer: DeckFromCards([]*Card{}), CanDraw: false, HasDrawn: false, Status: StatusLobby, } } func (g *Game) String() string { return fmt.Sprintf("Sen(%v): %v\n\n%v\n\nSco(%v): %v\nStatus:%v Draw:%v Turn:%v\n%v\n", g.SentinalPlayer.Life, g.SentinalPlayer.Hand, g.GameBoard, g.ScourgePlayer.Life, g.ScourgePlayer.Hand, g.Status, g.CanDraw, g.CurrentTurn, g.CardBuffer) } func (g *Game) Parse(cmd *Command) *CommandResult { if g.Status == StatusDraw || g.Status == StatusScourgeWin || g.Status == StatusSentinalWin || g.Status == StatusStop { return &CommandResult{ PlayerID: cmd.PlayerID, ResultType: cmd.Type, StateResult: NewView(cmd.PlayerID, g), ActionResult: nil, DebugResult: g, } } var state_res *GameView var action_res *Deck var debug_res *Game var res_type CmdType if cmd.Type == ActCmd { action_res = g.PlayerAct(cmd.PlayerID, cmd.Cmd) state_res = nil debug_res = nil res_type = ActCmd } else if cmd.Type == StateCmd { state_res = g.PlayerStateAct(cmd.PlayerID, cmd.Cmd) action_res = nil debug_res = nil res_type = StateCmd } else { state_res = nil action_res = nil debug_res = g res_type = DebugCmd } g.StateChanges() return &CommandResult{ PlayerID: cmd.PlayerID, ResultType: res_type, StateResult: state_res, ActionResult: action_res, DebugResult: debug_res, } } func (g *Game) StateChanges() { //check for no actions first if len(g.SentinalPlayer.Hand) == 0 && g.SentinalDeck.Size() == 0 { if g.GameBoard.Empty(SentinalID) { g.Status = StatusScourgeWin } } if len(g.ScourgePlayer.Hand) == 0 && g.ScourgeDeck.Size() == 0 { if g.GameBoard.Empty(ScourgeID) { g.Status = StatusSentinalWin } } //check life //this is second on purpose so that it shadows deck out win conditions //if you use your last action to win the game, you should actually win if g.SentinalPlayer.Life < 0 { g.Status = StatusScourgeWin } if g.ScourgePlayer.Life < 0 { g.Status = StatusSentinalWin } if g.ScourgePlayer.Life < 0 && g.SentinalPlayer.Life < 0 { g.Status = StatusDraw } } func (g *Game) PlayerStateAct(id int, cmd string) *GameView { switch cmd { case "g": //game state return NewView(id, g) case "b": //begin game g.Status = StatusReady //TODO check for ready on both accounts first g.SentinalPlayer.Hand = g.SentinalDeck.Cards[len(g.SentinalDeck.Cards)-5 : len(g.SentinalDeck.Cards)] g.SentinalDeck.Cards = g.SentinalDeck.Cards[0 : len(g.SentinalDeck.Cards)-5] g.ScourgePlayer.Hand = g.ScourgeDeck.Cards[len(g.ScourgeDeck.Cards)-5 : len(g.ScourgeDeck.Cards)] g.SentinalDeck.Cards = g.ScourgeDeck.Cards[0 : len(g.ScourgeDeck.Cards)-5] case "s": //start turn if g.Status == StatusReady { //first turn g.Status = StatusPlaying g.CurrentTurn = id g.CanDraw = false g.HasDrawn = true } else { g.CanDraw = true g.HasDrawn = false } if id != g.CurrentTurn { return nil } if id == SentinalID { for _, v := range g.GameBoard.Sentinal { OracleUpkeep(v, g) } } else { for _, v := range g.GameBoard.Scourge { OracleUpkeep(v, g) } } case "e": //end turn and clean up if id != g.CurrentTurn { return nil } g.CardBuffer = DeckFromCards([]*Card{}) if id == SentinalID { for _, v := range g.GameBoard.Sentinal { OracleEndstep(v, g) } } else { for _, v := range g.GameBoard.Scourge { OracleEndstep(v, g) } } if g.CurrentTurn == SentinalID { g.CurrentTurn = ScourgeID } else { g.CurrentTurn = SentinalID } } return NewView(id, g) } func (g *Game) PlayerAct(id int, cmd string) *Deck { if id != g.CurrentTurn { return nil } var curr *Player var opp *Player var currD *Deck if id == g.SentinalPlayer.Id { curr = g.SentinalPlayer opp = g.ScourgePlayer currD = g.SentinalDeck } else { curr = g.ScourgePlayer opp = g.SentinalPlayer currD = g.ScourgeDeck } cmd_s := strings.Split(cmd, " ") if len(cmd_s) < 1 { return nil } switch cmd_s[0] { case "s": //scry: return scry options off top of deck if !g.CanDraw || g.CardBuffer.Size() > 0 { return nil } g.CardBuffer = DeckFromCards(currD.Scry(curr.Life)) return g.CardBuffer case "d": //draw: return player hand if !g.CanDraw { return nil } if len(cmd_s) != 2 || !g.CanDraw { return nil } x_i, err := strconv.Atoi(cmd_s[1]) if err != nil { panic(err) } x := g.CardBuffer.Cards[x_i] buf := g.CardBuffer for i, v := range buf.Cards { if v == x { buf.Cards = append(buf.Cards[:i], buf.Cards[i+1:]...) } } currD.Bottom(buf.Cards) curr.Hand = append(curr.Hand, x) g.CanDraw = false g.HasDrawn = true return DeckFromCards(curr.Hand) case "m": //move: return player board or [] if invalid if len(cmd_s) != 3 { return nil } if !g.HasDrawn { return nil } x_i, _ := strconv.Atoi(cmd_s[1]) y_i, _ := strconv.Atoi(cmd_s[2]) if g.GameBoard.CanMove(g.CurrentTurn, x_i, y_i) { OracleMove(g.GameBoard.GetCard(g.CurrentTurn, x_i), g) g.GameBoard.Move(g.CurrentTurn, x_i, y_i) return DeckFromCards(g.GameBoard.GetRow(g.CurrentTurn)) } else { return DeckFromCards([]*Card{}) } case "a": //attack if len(cmd_s) != 3 { return nil } if !g.HasDrawn { return nil } x_i, _ := strconv.Atoi(cmd_s[1]) y_i, _ := strconv.Atoi(cmd_s[2]) if g.GameBoard.CanAttack(g.CurrentTurn, x_i, y_i) { OracleAttack(g.GameBoard.GetCard(g.CurrentTurn, x_i), g) res := g.GameBoard.Attack(g.CurrentTurn, x_i, y_i) if res == 1 { opp.Life = opp.Life - 1 return DeckFromCards(g.GameBoard.GetRow(g.CurrentTurn)) } else { return DeckFromCards(g.GameBoard.GetRow(g.CurrentTurn)) } } else { log.Println("can't attack") return DeckFromCards([]*Card{}) } case "p": //play: return player boad or [] if invalid if len(cmd_s) != 3 { fmt.Println("not enough arguments") return nil } if !g.HasDrawn { return nil } x_i, _ := strconv.Atoi(cmd_s[1]) y_i, _ := strconv.Atoi(cmd_s[2]) card := curr.Hand[x_i] shouldPlace := true if g.GameBoard.CanPlay(g.CurrentTurn, card, y_i) { shouldPlace = OracleCast(curr.Hand[x_i], g) _ = g.GameBoard.Play(g.CurrentTurn, card, y_i, shouldPlace) OracleEnters(curr.Hand[x_i], g) curr.Hand = append(curr.Hand[:x_i], curr.Hand[x_i+1:]...) return DeckFromCards(g.GameBoard.GetRow(g.CurrentTurn)) } else { fmt.Println("couldn't play") return DeckFromCards([]*Card{}) } default: fmt.Println("Invalid act command") return nil } return nil }