package main import ( "fmt" "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"}[g] } type Game struct { GameBoard *Board SentinalPlayer *Player ScourgePlayer *Player SentinalDeck *Deck ScourgeDeck *Deck CurrentTurn int CardBuffer []Card 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: []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 != StatusLobby || g.Status != StatusReady || g.Status != StatusPlaying { return &CommandResult{ PlayerID: cmd.PlayerID, ResultType: cmd.Type, StateResult: NewView(cmd.PlayerID, g), ActionResult: nil, DebugResult: g, } } var state_res *GameView var action_res []Card var debug_res *Game var res_type CmdType if cmd.Type == ActCmd { action_res = g.PlayerAct(cmd.PlayerID, cmd.Cmd) res_type = ActCmd } else if cmd.Type == StateCmd { state_res = g.PlayerStateAct(cmd.PlayerID, cmd.Cmd) res_type = StateCmd } else { 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 { v.Upkeep(g) } } else { for _, v := range g.GameBoard.Scourge { v.Upkeep(g) } } case "e": //end turn and clean up if id != g.CurrentTurn { return nil } g.CardBuffer = []Card{} if id == SentinalID { for _, v := range g.GameBoard.Sentinal { v.Endstep(g) } } else { for _, v := range g.GameBoard.Scourge { v.Endstep(g) } } if g.CurrentTurn == SentinalID { g.CurrentTurn = ScourgeID } else { g.CurrentTurn = SentinalID } } return NewView(id, g) } func (g *Game) PlayerAct(id int, cmd string) []Card { 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 || len(g.CardBuffer) > 0 { return nil } g.CardBuffer = 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[x_i] buf := g.CardBuffer for i, v := range buf { if v == x { buf = append(buf[:i], buf[i+1:]...) } } currD.Bottom(buf) curr.Hand = append(curr.Hand, x) g.CanDraw = false g.HasDrawn = true return 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]) res := g.GameBoard.Move(g.CurrentTurn, x_i, y_i) if res { return g.GameBoard.GetRow(g.CurrentTurn) } else { return []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]) res := g.GameBoard.Attack(g.CurrentTurn, x_i, y_i) if res == 1 { opp.Life = opp.Life - 1 return g.GameBoard.GetRow(g.CurrentTurn) } else if res == 0 { return g.GameBoard.GetRow(g.CurrentTurn) } else { fmt.Println("can't attack") return []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] if g.GameBoard.CanPlay(g.CurrentTurn, &card, y_i) { curr.Hand[x_i].Cast(g) } res := g.GameBoard.Play(g.CurrentTurn, &card, y_i) if res { curr.Hand[x_i].Enters(g) curr.Hand = append(curr.Hand[:x_i], curr.Hand[x_i+1:]...) return g.GameBoard.GetRow(g.CurrentTurn) } else { fmt.Println("couldn't play") return []Card{} } default: fmt.Println("Invalid act command") return nil } return nil }