86 lines
1.7 KiB
Go
86 lines
1.7 KiB
Go
package soko
|
|
|
|
import (
|
|
"errors"
|
|
"fmt"
|
|
"io"
|
|
|
|
"opslag.de/schobers/krampus19/gut"
|
|
)
|
|
|
|
func ParseLevel(r io.Reader) (Level, error) {
|
|
var l Level
|
|
ctx := levelContext{&l}
|
|
err := gut.ParseLines(r, ctx.parse)
|
|
if err != nil {
|
|
return Level{}, err
|
|
}
|
|
return l, nil
|
|
}
|
|
|
|
type levelContext struct {
|
|
level *Level
|
|
}
|
|
|
|
func (c *levelContext) parse(p *gut.LineParser) gut.ParseLineFn {
|
|
if p.EOF() {
|
|
return nil
|
|
}
|
|
switch p.Peek() {
|
|
case "level:":
|
|
return c.parseContent
|
|
case "":
|
|
p.Next() // skip
|
|
return c.parse
|
|
default:
|
|
return nil
|
|
}
|
|
}
|
|
|
|
func (c *levelContext) parseContent(p *gut.LineParser) gut.ParseLineFn {
|
|
if p.Next() != "level:" {
|
|
return p.EmitErr(errors.New("expected level start"))
|
|
}
|
|
return c.parseRow
|
|
}
|
|
|
|
func (c *levelContext) parseRow(p *gut.LineParser) gut.ParseLineFn {
|
|
if p.EOF() {
|
|
return p.EmitErr(errors.New("unexpected end of file"))
|
|
}
|
|
line := p.Next()
|
|
if line == ":level" {
|
|
return c.parse
|
|
}
|
|
if c.level.Height == 0 {
|
|
c.level.Width = len(line) / 2
|
|
}
|
|
return c.addRow(p, line)
|
|
}
|
|
|
|
func (c *levelContext) addRow(p *gut.LineParser, line string) gut.ParseLineFn {
|
|
var tiles []TileType
|
|
var entities []EntityType
|
|
for i := 0; i < len(line); i += 2 {
|
|
tiles = append(tiles, TileType(line[i]))
|
|
entities = append(entities, EntityType(line[i+1]))
|
|
}
|
|
|
|
for i, t := range tiles {
|
|
if !t.IsValid() {
|
|
return p.EmitErr(fmt.Errorf("level contains invalid TileType at (%d, %d)", i, c.level.Height))
|
|
}
|
|
}
|
|
for i, e := range entities {
|
|
if !e.IsValid() {
|
|
return p.EmitErr(fmt.Errorf("level contains invalid entity type at (%d, %d)", i, c.level.Height))
|
|
}
|
|
}
|
|
|
|
c.level.Height++
|
|
c.level.Tiles = append(c.level.Tiles, tiles...)
|
|
c.level.Entities = append(c.level.Entities, entities...)
|
|
|
|
return c.parseRow
|
|
}
|