diff options
Diffstat (limited to 'go/game/kraken.go')
| -rw-r--r-- | go/game/kraken.go | 179 |
1 files changed, 179 insertions, 0 deletions
diff --git a/go/game/kraken.go b/go/game/kraken.go new file mode 100644 index 00000000..19adfd3c --- /dev/null +++ b/go/game/kraken.go @@ -0,0 +1,179 @@ +package game + +import ( + "log" + "strings" + "sync" +) + +const ( + KRAKEN_NAME = "Kraken" +) + +var KrakenDecklist = `2 kraken/angry_squid +2 kraken/chachalot +2 kraken/clownfish +2 kraken/deja_vu! +2 kraken/devour_the_poor! +2 kraken/dolphin +2 kraken/flying_dutchmen +2 kraken/frost_pylon +2 kraken/gigantic_hail +2 kraken/sailfish +2 kraken/sold_out! +2 kraken/suprise! +2 kraken/tentacle_slap +2 kraken/tides_change! +2 kraken/unholy_cannonball` + +func NewKraken(id int, s *State) *Player { + kraken := NewPlayer(id, KRAKEN_NAME, NewDeck(), s) + d := NewDeckFromDeckList(KrakenDecklist) + d.Shuffle(s.Rand) + kraken.Deck = d + + kraken.DrawPerTurn = 0 + + kraken_tile := s.Map.FilterTiles(func(t *Tile) bool { return t.Raw == "the kraken" }) + if len(kraken_tile) != 1 { + log.Fatal("No kraken tile found in Map") + } + + s.AddPermanent(NewUnitFromPath("kraken/the_kraken", kraken_tile[0], kraken)) + + addKrakenControl(kraken) + + return kraken +} + +func (s *State) AddKraken() { + kraken := NewKraken(len(s.Players)+1, s) + s.Players = append(s.Players, kraken) +} + +type KrakenControl struct { + kraken *Player + actions chan Action + syncGameState *sync.WaitGroup + turn int +} + +func addKrakenControl(kraken *Player) { + ctrl := &KrakenControl{kraken, make(chan Action), new(sync.WaitGroup), 0} + kraken.Ctrl = ctrl + + ctrl.syncGameState.Add(1) + go func() { + s := kraken.gameState + for len(s.Map.WinCondition(s)) == 0 { + ctrl.krakenTurn() + } + }() +} + +func (ctrl *KrakenControl) awaitGameStateSync() { + ctrl.syncGameState.Wait() + ctrl.syncGameState.Add(1) +} + +func (ctrl *KrakenControl) krakenTurn() { + s := ctrl.kraken.gameState + kraken := ctrl.kraken + + ctrl.awaitGameStateSync() + ctrl.turn++ + if ctrl.turn != kraken.Turn { + log.Fatalf("Ai turn out of sync %d != %d", ctrl.turn, kraken.Turn) + } + +turn: + for { + drawn := kraken.Deck.Draw(1) + if len(drawn) == 0 { + break + } + c := drawn[0] + + if c.BuyCost > kraken.Resource { + log.Println("Kraken discards", c.Name, "because resource to low", kraken.Resource) + kraken.DiscardPile.AddCard(c) + break + } + kraken.Hand.AddCard(c) + + costFunc := func(s *State) bool { + kraken.Resource -= c.BuyCost + return true + } + + a := NewPlayAction(kraken, c, costFunc) + for a.Targets().RequireTargets() { + options := a.Targets().NextOptions() + if len(options) == 0 { + log.Println("No target available for", c.Name) + kraken.DiscardPile.AddCard(c) + continue turn + } + + idx := 0 + if len(options) > 1 { + idx = s.Rand.Intn(len(options) - 1) + } + a.Targets().AddTarget(options[idx]) + } + + ctrl.actions <- a + ctrl.awaitGameStateSync() + } + + for _, u := range s.OwnUnits(kraken) { + unitAI := NewUnitAI(s, u) + if unitAI == nil { + continue + } + + unitAI.promptAction() + for a := range unitAI.actions { + ctrl.actions <- a + ctrl.awaitGameStateSync() + unitAI.promptAction() + } + } + + ctrl.actions <- NewPassPriority(ctrl.kraken) +} + +func (ctrl *KrakenControl) RecvAction() Action { + s := ctrl.kraken.gameState + kraken := ctrl.kraken + if !s.IsActivePlayer(kraken) || + s.ActivePhase != Phases.ActionPhase || !s.Stack.IsEmpty() { + + return NewPassPriority(ctrl.kraken) + } + + ctrl.syncGameState.Done() + return <-ctrl.actions +} + +func (ctrl *KrakenControl) SendNotification(n PlayerNotification) { +} + +func (p *Player) IsKraken() bool { + return p.Name == KRAKEN_NAME +} + +func (s *State) FindKraken() *Player { + for _, p := range s.Players { + if p.IsKraken() { + return p + } + } + return nil +} + +func (s *State) KrakenSpawnTiles() []*Tile { + return s.Map.FilterTiles(func(t *Tile) bool { + return strings.Contains(t.Raw, "deep water spawn") + }) +} |
