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 "" }