aboutsummaryrefslogtreecommitdiff
path: root/go/game/playerControl.go
blob: c472f4f0c423c6bdeaeae01a6db31c32a3a147c3 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
package game

import (
	"fmt"
	"log"
)

type PlayerNotificationType int

const (
	DeclaredActionNotification PlayerNotificationType = iota
	ResolvedActionNotification
	PriorityNotification
	TargetSelectionPrompt
	DeclareTriggeredActionsPrompt
	DraftPickPrompt
)

func (n PlayerNotificationType) String() string {
	switch n {
	case DeclaredActionNotification:
		return "DeclaredActionNotification"
	case ResolvedActionNotification:
		return "ResolvedActionNotification"
	case PriorityNotification:
		return "PriorityNotification"
	case TargetSelectionPrompt:
		return "TargetSelectionPrompt"
	case DeclareTriggeredActionsPrompt:
		return "DeclareTriggeredActionsPrompt"
	case DraftPickPrompt:
		return "DraftPickPrompt"
	default:
		log.Panicf("Unhandled notification %d", n)
		return ""
	}
}

func (n PlayerNotification) IsPriorityNotification() bool {
	return n.Notification == PriorityNotification
}

type PlayerNotification struct {
	Notification PlayerNotificationType
	Context      any
	Error        error
}

func (n *PlayerNotification) String() string {
	if n.Error != nil {
		return fmt.Sprintf("error %v: %v", n.Notification, n.Error)
	}

	return fmt.Sprintf("%v: %v", n.Notification, n.Context)
}

type TargetSelectionCtx struct {
	Action Action
	Prompt string
}

func newPriorityNotification() PlayerNotification {
	return PlayerNotification{PriorityNotification, nil, nil}
}

func newDeclaredActionNotification(a Action, err error) PlayerNotification {
	return PlayerNotification{DeclaredActionNotification, a, err}
}

func newResolvedActionNotification(a Action, err error) PlayerNotification {
	return PlayerNotification{ResolvedActionNotification, a, err}
}

func newTargetSelectionPrompt(a Action, desc string) PlayerNotification {
	return PlayerNotification{TargetSelectionPrompt, TargetSelectionCtx{a, desc}, nil}
}

func newUpkeepPrompt(p *Player) PlayerNotification {
	a := newUpkeepAction(p)
	return newTargetSelectionPrompt(a, "Select units to disband")
}

func newBuyPrompt(p *Player) PlayerNotification {
	a := newBuyAction(p)
	prompt := newTargetSelectionPrompt(a, "Select a card to buy")
	return prompt
}

func newHandCardSelectionPrompt(p *Player, min, max int) PlayerNotification {
	a := newHandCardSelection(p, min, max)
	desc := fmt.Sprintf("Select between %d and %d hand cards", min, max)
	return newTargetSelectionPrompt(a, desc)
}

func newDeclareTriggeredActionsPrompt(triggeredActions []*TriggeredAction) PlayerNotification {
	return PlayerNotification{DeclareTriggeredActionsPrompt, triggeredActions, nil}
}

func newDraftPickPrompt(pack PileOfCards) PlayerNotification {
	return PlayerNotification{DraftPickPrompt, pack, nil}
}

type PlayerControl interface {
	Player() *Player
	RecvAction() Action
	SendNotification(PlayerNotification)
	Close()
}

type ChanPlayerControl struct {
	player        *Player
	actions       chan Action
	notifications chan PlayerNotification
}

func (c *ChanPlayerControl) Player() *Player                       { return c.player }
func (c *ChanPlayerControl) SendAction(a Action)                   { c.actions <- a }
func (c *ChanPlayerControl) RecvAction() Action                    { return <-c.actions }
func (c *ChanPlayerControl) SendNotification(n PlayerNotification) { c.notifications <- n }
func (c *ChanPlayerControl) RecvNotification() *PlayerNotification {
	select {
	case n := <-c.notifications:
		return &n
	default:
		return nil
	}
}
func (c *ChanPlayerControl) Close() {
	close(c.actions)
	close(c.notifications)
}

func NewChanPlayerControl(p *Player) *ChanPlayerControl {
	a := make(chan Action)
	n := make(chan PlayerNotification)
	return &ChanPlayerControl{p, a, n}
}

func prompt(ctrl PlayerControl, notification PlayerNotification) Action {
	ctrl.SendNotification(notification)
	return ctrl.RecvAction()
}

func promptBuy(ctrl PlayerControl) Action {
	return prompt(ctrl, newBuyPrompt(ctrl.Player()))
}

func promptAction(ctrl PlayerControl) Action {
	return prompt(ctrl, newPriorityNotification())
}