aboutsummaryrefslogtreecommitdiff
path: root/go/game/map.go
diff options
context:
space:
mode:
authorFlorian Fischer <florian.fischer@muhq.space>2025-07-03 21:48:58 -0400
committerFlorian Fischer <florian.fischer@muhq.space>2025-07-06 11:49:19 -0400
commitd4e6d843dc71b68a34f1aa2eed84e5fe20af3589 (patch)
treeee25b7ef22ee4408325642c65d26784646f5ff37 /go/game/map.go
parentfa5c66a13d7c182f44c9fa52c216e4d0f455ea29 (diff)
downloadmuhqs-game-d4e6d843dc71b68a34f1aa2eed84e5fe20af3589.tar.gz
muhqs-game-d4e6d843dc71b68a34f1aa2eed84e5fe20af3589.zip
support king games
Diffstat (limited to 'go/game/map.go')
-rw-r--r--go/game/map.go69
1 files changed, 44 insertions, 25 deletions
diff --git a/go/game/map.go b/go/game/map.go
index fb67ebbb..b3203bd4 100644
--- a/go/game/map.go
+++ b/go/game/map.go
@@ -1,7 +1,6 @@
package game
import (
- "errors"
"fmt"
"io"
"log"
@@ -11,6 +10,8 @@ import (
"path"
"strings"
+ "golang.org/x/exp/slices"
+
"gopkg.in/yaml.v3"
)
@@ -27,10 +28,7 @@ type MapYml struct {
Map string `yaml:"map"`
Symbols map[string]string `yaml:"symbols"`
StartDeckList string `yaml:"start_deck_list"`
-}
-
-func DummyWinCondition(*LocalState) []*Player {
- return []*Player{}
+ Kings [][]int `yaml:"omitemptt"`
}
type Map struct {
@@ -38,8 +36,9 @@ type Map struct {
symbols map[string]string
ResourceGain int
StartDeckList string
- WinCondition func(*LocalState) []*Player
+ WinCondition WinCondition
Stores map[Position]*Store
+ Prepare func(*LocalState)
}
func readMap(r io.Reader) (*Map, error) {
@@ -51,6 +50,7 @@ func readMap(r io.Reader) (*Map, error) {
return ParseMap(data)
}
+// ParseMap constructs a Map from a yaml definition.
func ParseMap(data []byte) (*Map, error) {
mapYml := MapYml{}
err := yaml.Unmarshal(data, &mapYml)
@@ -74,10 +74,10 @@ func ParseMap(data []byte) (*Map, error) {
}
rows := strings.Split(mapYml.Map, "\n")
- for y := 0; y < len(rows); y++ {
+ for y := range len(rows) {
row := rows[y]
m.Tiles = append(m.Tiles, []Tile{})
- for x := 0; x < len(rows[y]); x++ {
+ for x := range len(rows[y]) {
pos := Position{x, y}
s := string(row[x])
tile, err := NewTileFromString(mapYml.Symbols[s], pos)
@@ -95,12 +95,23 @@ func ParseMap(data []byte) (*Map, error) {
m.selectStreets()
+ if len(mapYml.Kings) == 0 {
+ m.WinCondition = KingGame
+ m.Prepare = func(s *LocalState) {
+ k := NewCard("misc/king")
+ for i, kingPos := range mapYml.Kings {
+ p := s.PlayerById(i + 1)
+ s.addNewUnit(k, Position{kingPos[0], kingPos[1]}, p)
+ }
+ }
+ }
+
return m, nil
}
func (m *Map) selectStreets() {
- for y := 0; y < len(m.Tiles); y++ {
- for x := 0; x < len(m.Tiles[y]); x++ {
+ for y := range len(m.Tiles) {
+ for x := range len(m.Tiles[y]) {
tile := &m.Tiles[y][x]
if tile.Type != TileTypes.Street {
continue
@@ -175,6 +186,7 @@ func (m *Map) FindFortificationConnections(x int, y int) (connections int, left,
return m.FindConnections(x, y, func(t TileType) bool { return t.IsFortification() })
}
+// GetMap creates a new map from the definition retrieved for the map's name.
func GetMap(name string) (*Map, error) {
url := path.Join(BASE_URL, MAP_URL_PART, name+".yml")
log.Printf("loading map from %s\n", url)
@@ -186,33 +198,35 @@ func GetMap(name string) (*Map, error) {
return readMap(resp.Body)
}
-func LoadMap(file string) (*Map, error) {
- f, err := os.Open(file)
+// LoadMap creates a new map from a definition stored in path.
+func LoadMap(path string) (*Map, error) {
+ f, err := os.Open(path)
if err != nil {
- log.Fatal("Opening map ", file, " failed: ", err)
+ log.Fatal("Opening map ", path, " failed: ", err)
}
defer f.Close()
return readMap(f)
}
+// TileAt returns the tile at a certain position.
+// Id p is an invalid position, nil is returned.
func (m *Map) TileAt(p Position) *Tile {
- if p.Y >= len(m.Tiles) || p.X >= len(m.Tiles[p.Y]) {
+ if p.Y < 0 || p.Y >= len(m.Tiles) || p.X < 0 || p.X >= len(m.Tiles[p.Y]) {
return nil
}
return &m.Tiles[p.Y][p.X]
}
+// RandomTile returns the position of a randomly selected tile.
+// The selected tile's type is included in the types input slice.
func (m *Map) RandomTile(r *rand.Rand, types []TileType) Position {
candidates := []Position{}
- for y := 0; y < len(m.Tiles); y++ {
- for x := 0; x < len(m.Tiles[y]); x++ {
+ for y := range len(m.Tiles) {
+ for x := range len(m.Tiles[y]) {
candidate := m.Tiles[y][x]
- for _, t := range types {
- if candidate.Type == t {
- candidates = append(candidates, candidate.Position)
- break
- }
+ for slices.Contains(types, candidate.Type) {
+ candidates = append(candidates, candidate.Position)
}
}
}
@@ -221,6 +235,8 @@ func (m *Map) RandomTile(r *rand.Rand, types []TileType) Position {
return candidates[randIdx]
}
+// RandomTileFromSymbols returns the position of a randomly selected tile.
+// The selected tile's type is represented in the symbols input slice.
func (m *Map) RandomTileFromSymbols(r *rand.Rand, symbols []string) (Position, error) {
types := make([]TileType, 0, len(symbols))
for _, symbol := range symbols {
@@ -231,7 +247,7 @@ func (m *Map) RandomTileFromSymbols(r *rand.Rand, symbols []string) (Position, e
tileType, ok := TileNames[tileString]
if !ok {
- return INVALID_POSITION(), errors.New("tile type unknown")
+ return INVALID_POSITION(), ErrInvalidTileName
}
types = append(types, tileType)
@@ -239,10 +255,12 @@ func (m *Map) RandomTileFromSymbols(r *rand.Rand, symbols []string) (Position, e
return m.RandomTile(r, types), nil
}
+// FilterTiles returns a slice of tiles matching the filter.
+// A tile is included in the result if the filter functions returns true for the given tile.
func (m *Map) FilterTiles(filter func(t *Tile) bool) []*Tile {
tiles := []*Tile{}
- for y := 0; y < len(m.Tiles); y++ {
- for x := 0; x < len(m.Tiles[y]); x++ {
+ for y := range len(m.Tiles) {
+ for x := range len(m.Tiles[y]) {
tile := &m.Tiles[y][x]
if filter(tile) {
tiles = append(tiles, tile)
@@ -252,6 +270,7 @@ func (m *Map) FilterTiles(filter func(t *Tile) bool) []*Tile {
return tiles
}
+// AllTiles returns all map tiles as flattened slice.
func (m *Map) AllTiles() []*Tile {
return m.FilterTiles(func(*Tile) bool { return true })
}
@@ -271,7 +290,7 @@ func (m *Map) distributeStoreCards(cards PileOfCards, rand *rand.Rand) {
d.Shuffle(rand)
nCards := d.Size()
- for i := 0; i < nCards; i++ {
+ for i := range nCards {
c := d.DrawOne()
stores[i%nStores].AddCard(c)
}