~nromdotcom/gemif

ref: 9f912f91eaf180b228bfec21da16186faf33c8c4 gemif/cmd/gemifc/roomparser.go -rw-r--r-- 3.0 KiB
9f912f91Norm MacLennan Render index banner properly on clients not using monospace font 1 year, 1 month ago
                                                                                
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
package main

import (
	"errors"
	"fmt"
	"gemif/pkg/gamemanager"
	"regexp"
	"strings"
)

// ErrInvalidRoomHeader happens when the header of a room is malformed or missing.
var ErrInvalidRoomHeader = errors.New("invalid or missing room header")

// ErrInvalidExitDescription happens when an exit is malformed.
var ErrInvalidExitDescription = errors.New("invalid exit description")

type roomParser struct {
	roomInfoRexp  *regexp.Regexp
	exitRexp      *regexp.Regexp
	ifCondRexp    *regexp.Regexp
	nifCondRexp   *regexp.Regexp
	setCondRexp   *regexp.Regexp
	unsetCondRexp *regexp.Regexp
}

func newRoomParser() roomParser {
	roomInfoRexp := regexp.MustCompile(`(?m)^# ([A-Za-z0-9_-]+) ([\w .,!/]+)$`)
	exitRexp := regexp.MustCompile("(?m)^=> ([\\w]+) ({([\\+-~!\\w ]+)} )?([^\n{}]+)$")
	setCondRexp := regexp.MustCompile(`\+([\w]+)`)
	unsetCondRexp := regexp.MustCompile(`-([\w]+)`)
	ifCondRexp := regexp.MustCompile(`~([\w]+)`)
	nifCondRexp := regexp.MustCompile(`!([\w]+)`)

	return roomParser{
		roomInfoRexp:  roomInfoRexp,
		exitRexp:      exitRexp,
		ifCondRexp:    ifCondRexp,
		setCondRexp:   setCondRexp,
		unsetCondRexp: unsetCondRexp,
		nifCondRexp:   nifCondRexp,
	}
}

func (rp *roomParser) findRoomInfo(room string) (gamemanager.Room, error) {
	infoMatch := rp.roomInfoRexp.FindStringSubmatch(room)
	if infoMatch == nil || len(infoMatch) != 3 {
		return gamemanager.Room{}, fmt.Errorf("%w: %v", ErrInvalidRoomHeader, infoMatch)
	}

	return gamemanager.Room{
		ID:          infoMatch[1],
		Name:        infoMatch[2],
		Exits:       []gamemanager.Exit{},
		Description: "",
	}, nil
}

func (rp *roomParser) removeInfoFromDesc(room string) string {
	return rp.roomInfoRexp.ReplaceAllString(room, "")
}

func (rp *roomParser) processExits(room string) ([]gamemanager.Exit, error) {
	roomExits := []gamemanager.Exit{}

	exitMatch := rp.exitRexp.FindAllStringSubmatch(room, -1)
	for _, exitStr := range exitMatch {
		if exitStr[1] == "" || exitStr[4] == "" {
			return roomExits, fmt.Errorf("%w: %s", ErrInvalidExitDescription, exitStr)
		}

		thisExit := gamemanager.Exit{
			Destination:    exitStr[1],
			Description:    exitStr[4],
			SetCondition:   "",
			UnsetCondition: "",
			IfCondition:    "",
			NotCondition:   "",
		}

		if exitStr[3] != "" {
			thisExit.SetCondition = getMatchOrDefault(rp.setCondRexp, exitStr[3])
			thisExit.UnsetCondition = getMatchOrDefault(rp.unsetCondRexp, exitStr[3])
			thisExit.IfCondition = getMatchOrDefault(rp.ifCondRexp, exitStr[3])
			thisExit.NotCondition = getMatchOrDefault(rp.nifCondRexp, exitStr[3])
		}

		roomExits = append(roomExits, thisExit)
	}

	return roomExits, nil
}

func (rp *roomParser) removeExitsFromDesc(room string) string {
	return rp.exitRexp.ReplaceAllString(room, "")
}

func (rp *roomParser) getRoomDescription(room string) string {
	room = rp.removeInfoFromDesc(room)
	room = rp.removeExitsFromDesc(room)
	room = strings.TrimSpace(room)

	return room
}

func getMatchOrDefault(rexp *regexp.Regexp, input string) string {
	setOpt := rexp.FindStringSubmatch(input)
	if len(setOpt) > 1 {
		return setOpt[1]
	}

	return ""
}