aboutsummaryrefslogtreecommitdiff
path: root/go/game/kraken.go
diff options
context:
space:
mode:
Diffstat (limited to 'go/game/kraken.go')
-rw-r--r--go/game/kraken.go179
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")
+ })
+}