Parser refactor complete
This commit is contained in:
parent
9564a205dc
commit
d0d2db70a4
41 changed files with 656 additions and 534 deletions
|
@ -5,7 +5,7 @@
|
|||
|
||||
package com.github.dtschust.zork;
|
||||
|
||||
import com.github.dtschust.zork.parser.ZorkReader;
|
||||
import com.github.dtschust.zork.parser.ParserIOC;
|
||||
import com.github.dtschust.zork.repl.ActionDispatcher;
|
||||
import com.github.dtschust.zork.types.ZorkContainer;
|
||||
import com.github.dtschust.zork.types.ZorkObject;
|
||||
|
@ -13,16 +13,15 @@ import com.github.dtschust.zork.types.ZorkObject;
|
|||
import java.util.Iterator;
|
||||
import java.util.Scanner;
|
||||
|
||||
import static com.github.dtschust.zork.Zork.Type.*;
|
||||
import static com.github.dtschust.zork.types.ZorkGameStatusType.*;
|
||||
|
||||
/* And away we go*/
|
||||
public class Zork {
|
||||
ZorkGame game;
|
||||
Scanner source = new Scanner(System.in);
|
||||
|
||||
public Zork(String filename) {
|
||||
|
||||
game = new ZorkReader(filename).build();
|
||||
public Zork(final String filename) {
|
||||
game = ParserIOC.xmlParser().parse(filename);
|
||||
|
||||
game.changeRoom("Entrance");
|
||||
/* Print out the first entrance description, starting the game!*/
|
||||
|
@ -147,8 +146,4 @@ public class Zork {
|
|||
}
|
||||
return skip;
|
||||
}
|
||||
|
||||
|
||||
public enum Type {ROOM, ITEM, CONTAINER, CREATURE}
|
||||
|
||||
}
|
||||
|
|
|
@ -3,8 +3,8 @@ package com.github.dtschust.zork;
|
|||
import com.github.dtschust.zork.types.ZorkContainer;
|
||||
import com.github.dtschust.zork.types.ZorkRoom;
|
||||
|
||||
import static com.github.dtschust.zork.Zork.Type.CONTAINER;
|
||||
import static com.github.dtschust.zork.Zork.Type.ROOM;
|
||||
import static com.github.dtschust.zork.types.ZorkGameStatusType.CONTAINER;
|
||||
import static com.github.dtschust.zork.types.ZorkGameStatusType.ROOM;
|
||||
|
||||
|
||||
/* Has conditions*/
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
package com.github.dtschust.zork;
|
||||
|
||||
import com.github.dtschust.zork.Zork.Type;
|
||||
import com.github.dtschust.zork.types.*;
|
||||
|
||||
import java.util.HashMap;
|
||||
|
@ -14,7 +13,7 @@ public class ZorkGame {
|
|||
private final ZorkMap<ZorkItem> items = new ZorkMap<>();
|
||||
private final ZorkMap<ZorkContainer> containers = new ZorkMap<>();
|
||||
private final ZorkMap<ZorkCreature> creatures = new ZorkMap<>();
|
||||
private final HashMap<String, Type> objectLookup = new HashMap<>();
|
||||
private final HashMap<String, ZorkGameStatusType> objectLookup = new HashMap<>();
|
||||
private boolean running = false;
|
||||
private String currentRoom;
|
||||
|
||||
|
@ -39,11 +38,11 @@ public class ZorkGame {
|
|||
running = false;
|
||||
}
|
||||
|
||||
public Type getTypeFromLookup(String object) {
|
||||
public ZorkGameStatusType getTypeFromLookup(String object) {
|
||||
return objectLookup.get(object);
|
||||
}
|
||||
|
||||
public void addObjectThroughLookup(Type type, ZorkObject object) {
|
||||
public void addObjectThroughLookup(ZorkGameStatusType type, ZorkObject object) {
|
||||
putInMapGivenType(type, object);
|
||||
objectLookup.put(object.getName(), type);
|
||||
}
|
||||
|
@ -52,20 +51,20 @@ public class ZorkGame {
|
|||
return values(cast, objectLookup.get(name));
|
||||
}
|
||||
|
||||
public <T extends ZorkObject> ZorkMap<T> values(Class<T> cast, Type type) {
|
||||
public <T extends ZorkObject> ZorkMap<T> values(Class<T> cast, ZorkGameStatusType type) {
|
||||
return (ZorkMap<T>) getMapFromType(type);
|
||||
}
|
||||
|
||||
public ZorkObject get(Type type, String key) {
|
||||
public ZorkObject get(ZorkGameStatusType type, String key) {
|
||||
return getMapFromType(type).get(key);
|
||||
}
|
||||
|
||||
public void put(Type type, ZorkObject object) {
|
||||
public void put(ZorkGameStatusType type, ZorkObject object) {
|
||||
putInMapGivenType(type, object);
|
||||
}
|
||||
|
||||
|
||||
private ZorkMap<? extends ZorkObject> getMapFromType(Type type) {
|
||||
private ZorkMap<? extends ZorkObject> getMapFromType(ZorkGameStatusType type) {
|
||||
switch (type) {
|
||||
case ROOM:
|
||||
return rooms;
|
||||
|
@ -80,7 +79,7 @@ public class ZorkGame {
|
|||
}
|
||||
}
|
||||
|
||||
private void putInMapGivenType(Type type, ZorkObject object) {
|
||||
private void putInMapGivenType(ZorkGameStatusType type, ZorkObject object) {
|
||||
switch (type) {
|
||||
case ROOM:
|
||||
rooms.put((ZorkRoom) object);
|
||||
|
|
|
@ -1,70 +0,0 @@
|
|||
package com.github.dtschust.zork.parser;
|
||||
|
||||
import org.w3c.dom.CharacterData;
|
||||
import org.w3c.dom.Element;
|
||||
import org.w3c.dom.Node;
|
||||
import org.w3c.dom.NodeList;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
public final class DOMUtils {
|
||||
private DOMUtils() {
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Given a DOM element with one and only one child of text node type, returns the text as a string. If there is no
|
||||
* such node, '?' is returned
|
||||
* Get a string from an element (XML parsing stuff)
|
||||
*
|
||||
* @param e the element
|
||||
* @return the text as string, or '?'
|
||||
*/
|
||||
public static String getInnerText(final Element e) {
|
||||
final Node child = e.getFirstChild();
|
||||
return child instanceof CharacterData ? ((CharacterData) child).getData() : "?";
|
||||
}
|
||||
|
||||
public static String getInnerTextByTagName(final Element element, final String elementName) {
|
||||
return getInnerTextByTagName(element, elementName, Optional.empty());
|
||||
}
|
||||
|
||||
public static String getInnerTextByTagName(final Element element,
|
||||
final String name,
|
||||
final String defaultValue) {
|
||||
return getInnerTextByTagName(element, name, Optional.of(defaultValue));
|
||||
}
|
||||
|
||||
public static String getInnerTextByTagName(final Element element,
|
||||
final String elementName,
|
||||
final Optional<String> defaultValue) {
|
||||
final NodeList field = element.getElementsByTagName(elementName);
|
||||
|
||||
if (field.getLength() == 0) {
|
||||
return defaultValue.orElseThrow(() ->
|
||||
new IllegalArgumentException(elementName + " element count in container is not 1"));
|
||||
}
|
||||
|
||||
final Node first = field.item(0);
|
||||
if (!(first instanceof Element)) {
|
||||
// the contract of getElementsByTagName states that it returns a list of Element objects
|
||||
throw new IllegalStateException("unreachable");
|
||||
}
|
||||
|
||||
return getInnerText((Element) first);
|
||||
}
|
||||
|
||||
public static List<Element> childrenElements(final Element parent) {
|
||||
final List<Element> elements = new ArrayList<>();
|
||||
final NodeList children = parent.getChildNodes();
|
||||
for (int i = 0; i < children.getLength(); i++) {
|
||||
final Node item = children.item(i);
|
||||
if (item instanceof Element) {
|
||||
elements.add((Element) item);
|
||||
}
|
||||
}
|
||||
return elements;
|
||||
}
|
||||
}
|
28
src/main/java/com/github/dtschust/zork/parser/ParserIOC.java
Normal file
28
src/main/java/com/github/dtschust/zork/parser/ParserIOC.java
Normal file
|
@ -0,0 +1,28 @@
|
|||
package com.github.dtschust.zork.parser;
|
||||
|
||||
import com.github.dtschust.zork.ZorkCondition;
|
||||
import com.github.dtschust.zork.parser.strategies.*;
|
||||
import com.github.dtschust.zork.types.ZorkContainer;
|
||||
import com.github.dtschust.zork.types.ZorkCreature;
|
||||
import com.github.dtschust.zork.types.ZorkItem;
|
||||
import com.github.dtschust.zork.types.ZorkRoom;
|
||||
|
||||
/**
|
||||
* Inversion of control for Zork parse strategies
|
||||
*/
|
||||
public final class ParserIOC {
|
||||
private static final PropertyParseStrategy<ZorkCondition> condition = new ZorkConditionParseStrategy();
|
||||
private static final TriggerPropertyParseStrategy trigger = new ZorkTriggerParseStrategy(condition);
|
||||
private static final PropertyParseStrategy<ZorkContainer> container = new ZorkContainerParseStrategy(trigger);
|
||||
private static final PropertyParseStrategy<ZorkItem> item = new ZorkItemParseStrategy(trigger);
|
||||
private static final PropertyParseStrategy<ZorkRoom> room = new ZorkRoomParseStrategy(trigger);
|
||||
private static final PropertyParseStrategy<ZorkCreature> creature = new ZorkCreatureParseStrategy(condition, trigger);
|
||||
private static final ZorkParser xmlParser = new ZorkXMLParser(creature, container, item, room);
|
||||
|
||||
private ParserIOC() {
|
||||
}
|
||||
|
||||
public static ZorkParser xmlParser() {
|
||||
return xmlParser;
|
||||
}
|
||||
}
|
91
src/main/java/com/github/dtschust/zork/parser/Property.java
Normal file
91
src/main/java/com/github/dtschust/zork/parser/Property.java
Normal file
|
@ -0,0 +1,91 @@
|
|||
package com.github.dtschust.zork.parser;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* A property is an encoding-agnostic representation of a 3-tuple made of:
|
||||
* - A property name (string);
|
||||
* - A property value (string);
|
||||
* - An (optional) list of sub-properties.
|
||||
*/
|
||||
public interface Property {
|
||||
|
||||
/**
|
||||
* Returns the property name
|
||||
*
|
||||
* @return the property name
|
||||
*/
|
||||
String name();
|
||||
|
||||
/**
|
||||
* Returns the property value
|
||||
*
|
||||
* @return the property value
|
||||
*/
|
||||
String value();
|
||||
|
||||
/**
|
||||
* Returns a list of all sub-properties
|
||||
*
|
||||
* @return a list af all sub-properties
|
||||
*/
|
||||
List<? extends Property> subProperties();
|
||||
|
||||
/**
|
||||
* Returns a list of the sub-properties matching the given name
|
||||
*
|
||||
* @param name the name of the sub-properties
|
||||
* @return a list of sub-properties
|
||||
*/
|
||||
List<? extends Property> subPropertiesByName(String name);
|
||||
|
||||
/**
|
||||
* Given a sub-property name and an optional default value, returns:
|
||||
* - The sub-property value for the first sub-property with the given name, or;
|
||||
* - If no such sub-properties are found and if the default value is given, the default value, or;
|
||||
* - nothing, throwing an exception, if no default value is given
|
||||
*
|
||||
* @param elementName the sub-property name
|
||||
* @param defaultValue the default value or Optional.empty()
|
||||
* @return the sub-property value
|
||||
* @throws IllegalStateException when the default value is not given and no sub-property is found
|
||||
*/
|
||||
String subPropertyValue(String elementName, Optional<String> defaultValue);
|
||||
|
||||
/**
|
||||
* Returns whether at least one sub-property with the given name is found
|
||||
*
|
||||
* @param name the sub-property name
|
||||
* @return whether at least one sub-property with the given name is found
|
||||
*/
|
||||
boolean hasSubProperty(String name);
|
||||
|
||||
/**
|
||||
* Overload of {@link #subPropertyValue(String, Optional)} with empty default value
|
||||
*/
|
||||
default String subPropertyValue(String name) {
|
||||
return subPropertyValue(name, Optional.empty());
|
||||
}
|
||||
|
||||
/**
|
||||
* Overload of {@link #subPropertyValue(String, Optional)} with the given default value
|
||||
* boxed as an {@link Optional}
|
||||
*/
|
||||
default String subPropertyValue(String name, String defaultValue) {
|
||||
return subPropertyValue(name, Optional.of(defaultValue));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a list of property values for the sub-properties matching the given name
|
||||
*
|
||||
* @param propertyName the name of the sub-properties
|
||||
* @return a list of sub-property values
|
||||
*/
|
||||
default List<String> subPropertyValues(final String propertyName) {
|
||||
return subPropertiesByName(propertyName).stream()
|
||||
.map(Property::value)
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
}
|
|
@ -0,0 +1,5 @@
|
|||
package com.github.dtschust.zork.parser;
|
||||
|
||||
public interface PropertyParseStrategy<T> {
|
||||
T parse(final Property source);
|
||||
}
|
|
@ -0,0 +1,19 @@
|
|||
package com.github.dtschust.zork.parser;
|
||||
|
||||
import com.github.dtschust.zork.ZorkTrigger;
|
||||
|
||||
import java.util.function.Function;
|
||||
|
||||
public interface TriggerPropertyParseStrategy {
|
||||
ZorkTrigger parseTrigger(final Property source, final Property parent);
|
||||
|
||||
/**
|
||||
* Partial function application for the parseTrigger method able to define the parent element first
|
||||
*
|
||||
* @param parent the parent element
|
||||
* @return a lambda mapping a source, a child element of `parent`, to ZorkTrigger objects
|
||||
*/
|
||||
default Function<Property, ZorkTrigger> parse(final Property parent) {
|
||||
return (source) -> this.parseTrigger(source, parent);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,43 @@
|
|||
package com.github.dtschust.zork.parser;
|
||||
|
||||
import com.github.dtschust.zork.ZorkGame;
|
||||
import com.github.dtschust.zork.types.*;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import static com.github.dtschust.zork.types.ZorkGameStatusType.*;
|
||||
|
||||
public abstract class ZorkParser {
|
||||
private final Map<ZorkGameStatusType, PropertyParseStrategy<? extends ZorkObject>> strategies;
|
||||
|
||||
public ZorkParser(final PropertyParseStrategy<ZorkCreature> creatureStrategy,
|
||||
final PropertyParseStrategy<ZorkContainer> containerStrategy,
|
||||
final PropertyParseStrategy<ZorkItem> itemStrategy,
|
||||
final PropertyParseStrategy<ZorkRoom> roomStrategy) {
|
||||
this.strategies = Map.ofEntries(
|
||||
Map.entry(CREATURE, creatureStrategy),
|
||||
Map.entry(CONTAINER, containerStrategy),
|
||||
Map.entry(ITEM, itemStrategy),
|
||||
Map.entry(ROOM, roomStrategy)
|
||||
);
|
||||
}
|
||||
|
||||
protected abstract Property getRootProperty(final String filename);
|
||||
|
||||
public ZorkGame parse(final String filename) {
|
||||
ZorkGame data = new ZorkGame();
|
||||
|
||||
final Property rootElement = getRootProperty(filename);
|
||||
|
||||
// Every single first generation child is a room, container, creature, or item. So load them in
|
||||
for (final Property element : rootElement.subProperties()) {
|
||||
final String name = element.name();
|
||||
final ZorkGameStatusType t = ZorkGameStatusType.fromPropertyName(name)
|
||||
.orElseThrow(() -> new IllegalStateException("Unexpected value: " + name));
|
||||
final ZorkObject built = strategies.get(t).parse(element);
|
||||
data.addObjectThroughLookup(t, built);
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
||||
}
|
|
@ -1,103 +0,0 @@
|
|||
package com.github.dtschust.zork.parser;
|
||||
|
||||
import com.github.dtschust.zork.ZorkGame;
|
||||
import com.github.dtschust.zork.parser.builders.Parsers;
|
||||
import com.github.dtschust.zork.types.ZorkContainer;
|
||||
import com.github.dtschust.zork.types.ZorkCreature;
|
||||
import com.github.dtschust.zork.types.ZorkItem;
|
||||
import com.github.dtschust.zork.types.ZorkRoom;
|
||||
import org.w3c.dom.Element;
|
||||
|
||||
import javax.xml.parsers.DocumentBuilderFactory;
|
||||
import java.io.File;
|
||||
import java.nio.channels.NonReadableChannelException;
|
||||
|
||||
import static com.github.dtschust.zork.Zork.Type.*;
|
||||
|
||||
public class ZorkReader {
|
||||
|
||||
private final String filename;
|
||||
|
||||
public ZorkReader(String filename) {
|
||||
this.filename = filename;
|
||||
}
|
||||
|
||||
private static void addCreature(ZorkGame data, Element element) {
|
||||
final ZorkCreature tempCreature = Parsers.creature.parse(element);
|
||||
|
||||
/* Put each creature in the creatures hashmap, the generic object hashmap, and the object lookup hashmap*/
|
||||
data.addObjectThroughLookup(CREATURE, tempCreature);
|
||||
}
|
||||
|
||||
private static void addContainer(ZorkGame data, Element element) {
|
||||
final ZorkContainer tempCont = Parsers.container.parse(element);
|
||||
|
||||
/* Put each container in the containers hashmap, the generic object hashmap, and the objectlookup hashmap*/
|
||||
data.addObjectThroughLookup(CONTAINER, tempCont);
|
||||
}
|
||||
|
||||
private static void addItem(ZorkGame data, Element element) {
|
||||
final ZorkItem tempItem = Parsers.item.parse(element);
|
||||
|
||||
/* Put each item in the items hashmap, the generic objects hashmap, and store its type in object lookup */
|
||||
data.addObjectThroughLookup(ITEM, tempItem);
|
||||
}
|
||||
|
||||
private static void addRoom(ZorkGame data, Element element) {
|
||||
final ZorkRoom tempRoom = Parsers.room.parse(element);
|
||||
|
||||
/*Add this room to the rooms hashmap, put it in the generic objects hashmap, and store it's type in the objectlookup hashmap*/
|
||||
data.addObjectThroughLookup(ROOM, tempRoom);
|
||||
}
|
||||
|
||||
public ZorkGame build() {
|
||||
ZorkGame data = new ZorkGame();
|
||||
|
||||
File file = new File(filename);
|
||||
if (!file.canRead()) {
|
||||
System.out.println("Error opening file. Exiting...");
|
||||
throw new NonReadableChannelException();
|
||||
}
|
||||
|
||||
try {
|
||||
/* Open the xml file*/
|
||||
DocumentBuilderFactory builder = DocumentBuilderFactory.newInstance();
|
||||
// Limit XML features to mitigate vulnerabilities
|
||||
builder.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);
|
||||
builder.setFeature("http://xml.org/sax/features/external-general-entities", false);
|
||||
builder.setFeature("http://xml.org/sax/features/external-parameter-entities", false);
|
||||
|
||||
Element rootElement = builder.newDocumentBuilder().parse(file).getDocumentElement();
|
||||
|
||||
/* Every single first generation child is a room, container, creature, or item. So load them in*/
|
||||
for (Element element : DOMUtils.childrenElements(rootElement)) {
|
||||
switch (element.getTagName()) {
|
||||
/* If it's a room ... */
|
||||
case "room":
|
||||
addRoom(data, element);
|
||||
break;
|
||||
/* If it's an item... */
|
||||
case "item":
|
||||
addItem(data, element);
|
||||
break;
|
||||
/* If it's a container... */
|
||||
case "container":
|
||||
addContainer(data, element);
|
||||
break;
|
||||
/* And finally, if it's a creature...*/
|
||||
case "creature":
|
||||
addCreature(data, element);
|
||||
break;
|
||||
default:
|
||||
throw new IllegalStateException("Unexpected value: " + element.getTagName());
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
// e.printStackTrace();
|
||||
System.out.println("Invalid XML file, exiting");
|
||||
System.exit(-1);
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,47 @@
|
|||
package com.github.dtschust.zork.parser;
|
||||
|
||||
import com.github.dtschust.zork.parser.dom.DOMElement;
|
||||
import com.github.dtschust.zork.types.ZorkContainer;
|
||||
import com.github.dtschust.zork.types.ZorkCreature;
|
||||
import com.github.dtschust.zork.types.ZorkItem;
|
||||
import com.github.dtschust.zork.types.ZorkRoom;
|
||||
import org.w3c.dom.Element;
|
||||
|
||||
import javax.xml.parsers.DocumentBuilderFactory;
|
||||
import java.io.File;
|
||||
import java.nio.channels.NonReadableChannelException;
|
||||
|
||||
public class ZorkXMLParser extends ZorkParser {
|
||||
public ZorkXMLParser(final PropertyParseStrategy<ZorkCreature> creatureStrategy,
|
||||
final PropertyParseStrategy<ZorkContainer> containerStrategy,
|
||||
final PropertyParseStrategy<ZorkItem> itemStrategy,
|
||||
final PropertyParseStrategy<ZorkRoom> roomStrategy) {
|
||||
super(creatureStrategy, containerStrategy, itemStrategy, roomStrategy);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Property getRootProperty(String filename) {
|
||||
File file = new File(filename);
|
||||
if (!file.canRead()) {
|
||||
System.out.println("Error opening file. Exiting...");
|
||||
throw new NonReadableChannelException();
|
||||
}
|
||||
|
||||
try {
|
||||
// Open the xml file
|
||||
final DocumentBuilderFactory builder = DocumentBuilderFactory.newInstance();
|
||||
// Limit XML features to mitigate vulnerabilities
|
||||
builder.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);
|
||||
builder.setFeature("http://xml.org/sax/features/external-general-entities", false);
|
||||
builder.setFeature("http://xml.org/sax/features/external-parameter-entities", false);
|
||||
|
||||
final Element rootElement = builder.newDocumentBuilder().parse(file).getDocumentElement();
|
||||
return DOMElement.of(rootElement);
|
||||
} catch (final Exception e) {
|
||||
System.out.println("Invalid XML file, exiting");
|
||||
e.printStackTrace();
|
||||
System.exit(-1);
|
||||
return null; // never reached
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,23 +0,0 @@
|
|||
package com.github.dtschust.zork.parser.builders;
|
||||
|
||||
import com.github.dtschust.zork.ZorkCondition;
|
||||
import com.github.dtschust.zork.ZorkTrigger;
|
||||
import com.github.dtschust.zork.types.ZorkContainer;
|
||||
import com.github.dtschust.zork.types.ZorkCreature;
|
||||
import com.github.dtschust.zork.types.ZorkItem;
|
||||
import com.github.dtschust.zork.types.ZorkRoom;
|
||||
|
||||
/**
|
||||
* Inversion of control for Zork parse strategies
|
||||
*/
|
||||
public final class Parsers {
|
||||
private static final ZorkParseStrategy<ZorkCondition> condition = new ZorkConditionParseStrategy();
|
||||
private static final ZorkParseStrategy<ZorkTrigger> trigger = new ZorkTriggerListParseStrategy(condition);
|
||||
public static final ZorkParseStrategy<ZorkContainer> container = new ZorkContainerParseStrategy(trigger);
|
||||
public static final ZorkParseStrategy<ZorkItem> item = new ZorkItemParseStrategy(trigger);
|
||||
public static final ZorkParseStrategy<ZorkRoom> room = new ZorkRoomParseStrategy(trigger);
|
||||
public static final ZorkParseStrategy<ZorkCreature> creature = new ZorkCreatureParseStrategy(condition, trigger);
|
||||
|
||||
private Parsers() {
|
||||
}
|
||||
}
|
|
@ -1,25 +0,0 @@
|
|||
package com.github.dtschust.zork.parser.builders;
|
||||
|
||||
import com.github.dtschust.zork.ZorkCondition;
|
||||
import com.github.dtschust.zork.ZorkConditionHas;
|
||||
import com.github.dtschust.zork.ZorkConditionStatus;
|
||||
import com.github.dtschust.zork.parser.DOMUtils;
|
||||
import org.w3c.dom.Element;
|
||||
|
||||
public class ZorkConditionParseStrategy implements ZorkParseStrategy<ZorkCondition> {
|
||||
@Override
|
||||
public ZorkCondition parse(final Element conditionElement) {
|
||||
if (conditionElement.getElementsByTagName("has").getLength() > 0) {
|
||||
return new ZorkConditionHas(
|
||||
DOMUtils.getInnerTextByTagName(conditionElement, "has"),
|
||||
DOMUtils.getInnerTextByTagName(conditionElement, "object"),
|
||||
DOMUtils.getInnerTextByTagName(conditionElement, "owner")
|
||||
);
|
||||
} else {
|
||||
return new ZorkConditionStatus(
|
||||
DOMUtils.getInnerTextByTagName(conditionElement, "status"),
|
||||
DOMUtils.getInnerTextByTagName(conditionElement, "object")
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,37 +0,0 @@
|
|||
package com.github.dtschust.zork.parser.builders;
|
||||
|
||||
import com.github.dtschust.zork.ZorkTrigger;
|
||||
import com.github.dtschust.zork.parser.DOMUtils;
|
||||
import com.github.dtschust.zork.parser.dom.Elements;
|
||||
import com.github.dtschust.zork.types.ZorkContainer;
|
||||
import org.w3c.dom.Element;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public class ZorkContainerParseStrategy implements ZorkParseStrategy<ZorkContainer> {
|
||||
private final ZorkParseStrategy<ZorkTrigger> triggerStrategy;
|
||||
|
||||
public ZorkContainerParseStrategy(ZorkParseStrategy<ZorkTrigger> triggerStrategy) {
|
||||
this.triggerStrategy = triggerStrategy;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ZorkContainer parse(final Element element) {
|
||||
final String name = DOMUtils.getInnerTextByTagName(element, "name", "");
|
||||
|
||||
final String description = DOMUtils.getInnerTextByTagName(element, "description", "");
|
||||
|
||||
final List<ZorkTrigger> triggers = Elements.byTagName(element, "trigger").stream()
|
||||
.map(triggerStrategy::parse)
|
||||
.collect(Collectors.toList());
|
||||
|
||||
final String status = DOMUtils.getInnerTextByTagName(element, "status", "");
|
||||
|
||||
final List<String> accepts = Elements.innerTextByTagName(element, "accept");
|
||||
|
||||
final List<String> items = Elements.innerTextByTagName(element, "item");
|
||||
|
||||
return new ZorkContainer(name, description, status, items, accepts, triggers);
|
||||
}
|
||||
}
|
|
@ -1,52 +0,0 @@
|
|||
package com.github.dtschust.zork.parser.builders;
|
||||
|
||||
import com.github.dtschust.zork.ZorkCondition;
|
||||
import com.github.dtschust.zork.ZorkTrigger;
|
||||
import com.github.dtschust.zork.parser.DOMUtils;
|
||||
import com.github.dtschust.zork.parser.dom.Elements;
|
||||
import com.github.dtschust.zork.types.ZorkCreature;
|
||||
import org.w3c.dom.Element;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public class ZorkCreatureParseStrategy implements ZorkParseStrategy<ZorkCreature> {
|
||||
|
||||
private final ZorkParseStrategy<ZorkCondition> conditionStrategy;
|
||||
private final ZorkParseStrategy<ZorkTrigger> triggerStrategy;
|
||||
|
||||
public ZorkCreatureParseStrategy(final ZorkParseStrategy<ZorkCondition> conditionStrategy,
|
||||
final ZorkParseStrategy<ZorkTrigger> triggerStrategy) {
|
||||
this.conditionStrategy = conditionStrategy;
|
||||
this.triggerStrategy = triggerStrategy;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ZorkCreature parse(final Element source) {
|
||||
// Get all possible creature attributes
|
||||
final List<ZorkCondition> conditions = Elements.byTagName(source, "attack").stream()
|
||||
.flatMap(e -> Elements.byTagName(e, "condition").stream())
|
||||
.map(conditionStrategy::parse)
|
||||
.collect(Collectors.toList());
|
||||
|
||||
final List<String> prints = Elements.byTagName(source, "attack").stream()
|
||||
.flatMap(e -> Elements.innerTextByTagName(e, "print").stream())
|
||||
.collect(Collectors.toList());
|
||||
|
||||
final List<String> actions = Elements.byTagName(source, "attack").stream()
|
||||
.flatMap(e -> Elements.innerTextByTagName(e, "action").stream())
|
||||
.collect(Collectors.toList());
|
||||
|
||||
final List<String> vulnerabilities = Elements.innerTextByTagName(source, "vulnerability");
|
||||
|
||||
final List<ZorkTrigger> triggers = Elements.byTagName(source, "trigger").stream()
|
||||
.map(triggerStrategy::parse)
|
||||
.collect(Collectors.toList());
|
||||
|
||||
final String name = DOMUtils.getInnerTextByTagName(source, "name", "");
|
||||
final String description = DOMUtils.getInnerTextByTagName(source, "description", "");
|
||||
final String status = DOMUtils.getInnerTextByTagName(source, "status", "");
|
||||
|
||||
return new ZorkCreature(name, description, status, triggers, vulnerabilities, conditions, prints, actions);
|
||||
}
|
||||
}
|
|
@ -1,45 +0,0 @@
|
|||
package com.github.dtschust.zork.parser.builders;
|
||||
|
||||
import com.github.dtschust.zork.ZorkTrigger;
|
||||
import com.github.dtschust.zork.parser.DOMUtils;
|
||||
import com.github.dtschust.zork.parser.dom.Elements;
|
||||
import com.github.dtschust.zork.types.ZorkItem;
|
||||
import org.w3c.dom.Element;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public class ZorkItemParseStrategy implements ZorkParseStrategy<ZorkItem> {
|
||||
|
||||
private final ZorkParseStrategy<ZorkTrigger> triggerStrategy;
|
||||
|
||||
public ZorkItemParseStrategy(final ZorkParseStrategy<ZorkTrigger> triggerStrategy) {
|
||||
this.triggerStrategy = triggerStrategy;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ZorkItem parse(final Element source) {
|
||||
final List<String> prints = Elements.byTagName(source, "turnon").stream()
|
||||
.flatMap(e -> Elements.innerTextByTagName(e, "print").stream())
|
||||
.collect(Collectors.toList());
|
||||
|
||||
final List<String> actions = Elements.byTagName(source, "turnon").stream()
|
||||
.flatMap(e -> Elements.innerTextByTagName(e, "action").stream())
|
||||
.collect(Collectors.toList());
|
||||
|
||||
final List<ZorkTrigger> triggers = Elements.byTagName(source, "trigger").stream()
|
||||
.map(triggerStrategy::parse)
|
||||
.collect(Collectors.toList());
|
||||
|
||||
/* Get all possible item attributes*/
|
||||
return new ZorkItem(
|
||||
DOMUtils.getInnerTextByTagName(source, "name", ""),
|
||||
DOMUtils.getInnerTextByTagName(source, "description", ""),
|
||||
DOMUtils.getInnerTextByTagName(source, "status", ""),
|
||||
DOMUtils.getInnerTextByTagName(source, "writing", ""),
|
||||
triggers,
|
||||
prints,
|
||||
actions
|
||||
);
|
||||
}
|
||||
}
|
|
@ -1,7 +0,0 @@
|
|||
package com.github.dtschust.zork.parser.builders;
|
||||
|
||||
import org.w3c.dom.Element;
|
||||
|
||||
public interface ZorkParseStrategy<T> {
|
||||
T parse(Element source);
|
||||
}
|
|
@ -1,47 +0,0 @@
|
|||
package com.github.dtschust.zork.parser.builders;
|
||||
|
||||
import com.github.dtschust.zork.ZorkTrigger;
|
||||
import com.github.dtschust.zork.parser.DOMUtils;
|
||||
import com.github.dtschust.zork.parser.dom.Elements;
|
||||
import com.github.dtschust.zork.types.ZorkDirection;
|
||||
import com.github.dtschust.zork.types.ZorkRoom;
|
||||
import org.w3c.dom.Element;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public class ZorkRoomParseStrategy implements ZorkParseStrategy<ZorkRoom> {
|
||||
|
||||
private final ZorkParseStrategy<ZorkTrigger> triggerStrategy;
|
||||
|
||||
public ZorkRoomParseStrategy(final ZorkParseStrategy<ZorkTrigger> triggerStrategy) {
|
||||
this.triggerStrategy = triggerStrategy;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ZorkRoom parse(final Element source) {
|
||||
// Get all possible Room attributes
|
||||
final String name = DOMUtils.getInnerTextByTagName(source, "name", "");
|
||||
final String description = DOMUtils.getInnerTextByTagName(source, "description", "");
|
||||
final String type = DOMUtils.getInnerTextByTagName(source, "type", "regular");
|
||||
|
||||
final List<ZorkTrigger> triggers = Elements.byTagName(source, "trigger").stream()
|
||||
.map(triggerStrategy::parse)
|
||||
.collect(Collectors.toList());
|
||||
|
||||
final String status = DOMUtils.getInnerTextByTagName(source, "status", "");
|
||||
|
||||
final List<String> items = Elements.innerTextByTagName(source, "item");
|
||||
final List<String> creatures = Elements.innerTextByTagName(source, "creature");
|
||||
final List<String> containers = Elements.innerTextByTagName(source, "container");
|
||||
|
||||
final Map<ZorkDirection, String> borders = Elements.byTagName(source, "border").stream()
|
||||
.collect(Collectors.toMap(
|
||||
e -> ZorkDirection.fromLong(DOMUtils.getInnerTextByTagName(e, "direction")),
|
||||
e -> DOMUtils.getInnerTextByTagName(e, "name")
|
||||
));
|
||||
|
||||
return new ZorkRoom(name, description, type, status, triggers, borders, containers, items, creatures);
|
||||
}
|
||||
}
|
|
@ -1,39 +0,0 @@
|
|||
package com.github.dtschust.zork.parser.builders;
|
||||
|
||||
import com.github.dtschust.zork.ZorkCommand;
|
||||
import com.github.dtschust.zork.ZorkCondition;
|
||||
import com.github.dtschust.zork.ZorkTrigger;
|
||||
import com.github.dtschust.zork.parser.DOMUtils;
|
||||
import com.github.dtschust.zork.parser.dom.Elements;
|
||||
import org.w3c.dom.Element;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public class ZorkTriggerListParseStrategy implements ZorkParseStrategy<ZorkTrigger> {
|
||||
|
||||
private final ZorkParseStrategy<ZorkCondition> conditionStrategy;
|
||||
|
||||
public ZorkTriggerListParseStrategy(final ZorkParseStrategy<ZorkCondition> conditionStrategy) {
|
||||
this.conditionStrategy = conditionStrategy;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ZorkTrigger parse(final Element trigger) {
|
||||
final String type = DOMUtils.getInnerTextByTagName((Element) trigger.getParentNode(), "type", "single");
|
||||
|
||||
final List<ZorkCommand> commands = Elements.byTagName(trigger, "command").stream()
|
||||
.map(DOMUtils::getInnerText)
|
||||
.map(ZorkCommand::new)
|
||||
.collect(Collectors.toList());
|
||||
|
||||
final List<ZorkCondition> conditions = Elements.byTagName(trigger, "condition").stream()
|
||||
.map(conditionStrategy::parse)
|
||||
.collect(Collectors.toList());
|
||||
|
||||
final List<String> prints = Elements.innerTextByTagName(trigger, "print");
|
||||
final List<String> actions = Elements.innerTextByTagName(trigger, "action");
|
||||
|
||||
return new ZorkTrigger(type, conditions, commands, prints, actions);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,83 @@
|
|||
package com.github.dtschust.zork.parser.dom;
|
||||
|
||||
import com.github.dtschust.zork.parser.Property;
|
||||
import org.w3c.dom.CharacterData;
|
||||
import org.w3c.dom.Element;
|
||||
import org.w3c.dom.Node;
|
||||
import org.w3c.dom.NodeList;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
public class DOMElement implements Property {
|
||||
private final Element backing;
|
||||
|
||||
public DOMElement(final Element backing) {
|
||||
this.backing = backing;
|
||||
}
|
||||
|
||||
public static DOMElement of(final Element backing) {
|
||||
return new DOMElement(backing);
|
||||
}
|
||||
|
||||
/**
|
||||
* Given a DOM element with one and only one child of text node type, returns the text as a string. If there is no
|
||||
* such node, '?' is returned
|
||||
* Get a string from an element (XML parsing stuff)
|
||||
*
|
||||
* @return the text as string, or '?'
|
||||
*/
|
||||
@Override
|
||||
public String value() {
|
||||
final Node child = backing.getFirstChild();
|
||||
return child instanceof CharacterData ? ((CharacterData) child).getData() : "?";
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<? extends Property> subPropertiesByName(final String name) {
|
||||
return DOMElementList.byTagName(backing, name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String subPropertyValue(final String elementName,
|
||||
final Optional<String> defaultValue) {
|
||||
final NodeList field = backing.getElementsByTagName(elementName);
|
||||
|
||||
if (field.getLength() == 0) {
|
||||
return defaultValue.orElseThrow(() ->
|
||||
new IllegalArgumentException(elementName + " element count in container is not 1"));
|
||||
}
|
||||
|
||||
final Node first = field.item(0);
|
||||
if (!(first instanceof Element)) {
|
||||
// the contract of getElementsByTagName states that it returns a list of Element objects
|
||||
throw new IllegalStateException("unreachable");
|
||||
}
|
||||
|
||||
return DOMElement.of((Element) first).value();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String name() {
|
||||
return backing.getTagName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasSubProperty(final String name) {
|
||||
return backing.getElementsByTagName(name).getLength() > 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Property> subProperties() {
|
||||
final List<Property> elements = new ArrayList<>();
|
||||
final NodeList children = backing.getChildNodes();
|
||||
for (int i = 0; i < children.getLength(); i++) {
|
||||
final Node item = children.item(i);
|
||||
if (item instanceof Element) {
|
||||
elements.add(DOMElement.of((Element) item));
|
||||
}
|
||||
}
|
||||
return elements;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,35 @@
|
|||
package com.github.dtschust.zork.parser.dom;
|
||||
|
||||
import org.w3c.dom.Element;
|
||||
import org.w3c.dom.Node;
|
||||
import org.w3c.dom.NodeList;
|
||||
|
||||
import java.util.AbstractList;
|
||||
import java.util.RandomAccess;
|
||||
|
||||
public class DOMElementList extends AbstractList<DOMElement> implements RandomAccess {
|
||||
private final NodeList list;
|
||||
|
||||
private DOMElementList(final NodeList l) {
|
||||
list = l;
|
||||
}
|
||||
|
||||
static DOMElementList byTagName(final Element parent, final String name) {
|
||||
return new DOMElementList(parent.getElementsByTagName(name));
|
||||
}
|
||||
|
||||
@Override
|
||||
public DOMElement get(int index) {
|
||||
final Node e = list.item(index);
|
||||
if (!(e instanceof Element)) {
|
||||
// the contract of getElementsByTagName states that it returns a list of Element objects
|
||||
throw new IllegalStateException("unreachable");
|
||||
}
|
||||
return DOMElement.of((Element) e);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int size() {
|
||||
return list.getLength();
|
||||
}
|
||||
}
|
|
@ -1,44 +0,0 @@
|
|||
package com.github.dtschust.zork.parser.dom;
|
||||
|
||||
import com.github.dtschust.zork.parser.DOMUtils;
|
||||
import org.w3c.dom.Element;
|
||||
import org.w3c.dom.Node;
|
||||
import org.w3c.dom.NodeList;
|
||||
|
||||
import java.util.AbstractList;
|
||||
import java.util.List;
|
||||
import java.util.RandomAccess;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public class Elements extends AbstractList<Element> implements RandomAccess {
|
||||
private final NodeList list;
|
||||
|
||||
private Elements(final NodeList l) {
|
||||
list = l;
|
||||
}
|
||||
|
||||
public static Elements byTagName(final Element parent, final String name) {
|
||||
return new Elements(parent.getElementsByTagName(name));
|
||||
}
|
||||
|
||||
public static List<String> innerTextByTagName(final Element parent, final String name) {
|
||||
return Elements.byTagName(parent, name).stream()
|
||||
.map(DOMUtils::getInnerText)
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Element get(int index) {
|
||||
final Node e = list.item(index);
|
||||
if (!(e instanceof Element)) {
|
||||
// the contract of getElementsByTagName states that it returns a list of Element objects
|
||||
throw new IllegalStateException("unreachable");
|
||||
}
|
||||
return (Element) e;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int size() {
|
||||
return list.getLength();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,25 @@
|
|||
package com.github.dtschust.zork.parser.strategies;
|
||||
|
||||
import com.github.dtschust.zork.ZorkCondition;
|
||||
import com.github.dtschust.zork.ZorkConditionHas;
|
||||
import com.github.dtschust.zork.ZorkConditionStatus;
|
||||
import com.github.dtschust.zork.parser.Property;
|
||||
import com.github.dtschust.zork.parser.PropertyParseStrategy;
|
||||
|
||||
public class ZorkConditionParseStrategy implements PropertyParseStrategy<ZorkCondition> {
|
||||
@Override
|
||||
public ZorkCondition parse(final Property source) {
|
||||
if (source.hasSubProperty("has")) {
|
||||
return new ZorkConditionHas(
|
||||
source.subPropertyValue("has"),
|
||||
source.subPropertyValue("object"),
|
||||
source.subPropertyValue("owner")
|
||||
);
|
||||
} else {
|
||||
return new ZorkConditionStatus(
|
||||
source.subPropertyValue("status"),
|
||||
source.subPropertyValue("object")
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,38 @@
|
|||
package com.github.dtschust.zork.parser.strategies;
|
||||
|
||||
import com.github.dtschust.zork.ZorkTrigger;
|
||||
import com.github.dtschust.zork.parser.Property;
|
||||
import com.github.dtschust.zork.parser.PropertyParseStrategy;
|
||||
import com.github.dtschust.zork.parser.TriggerPropertyParseStrategy;
|
||||
import com.github.dtschust.zork.types.ZorkContainer;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public class ZorkContainerParseStrategy implements PropertyParseStrategy<ZorkContainer> {
|
||||
private final TriggerPropertyParseStrategy triggerStrategy;
|
||||
|
||||
public ZorkContainerParseStrategy(TriggerPropertyParseStrategy triggerStrategy) {
|
||||
this.triggerStrategy = triggerStrategy;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ZorkContainer parse(final Property element) {
|
||||
|
||||
final String name = element.subPropertyValue("name", "");
|
||||
|
||||
final String description = element.subPropertyValue("description", "");
|
||||
|
||||
final List<ZorkTrigger> triggers = element.subPropertiesByName("trigger").stream()
|
||||
.map(triggerStrategy.parse(element))
|
||||
.collect(Collectors.toList());
|
||||
|
||||
final String status = element.subPropertyValue("status", "");
|
||||
|
||||
final List<String> accepts = element.subPropertyValues("accept");
|
||||
|
||||
final List<String> items = element.subPropertyValues("item");
|
||||
|
||||
return new ZorkContainer(name, description, status, items, accepts, triggers);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,54 @@
|
|||
package com.github.dtschust.zork.parser.strategies;
|
||||
|
||||
import com.github.dtschust.zork.ZorkCondition;
|
||||
import com.github.dtschust.zork.ZorkTrigger;
|
||||
import com.github.dtschust.zork.parser.Property;
|
||||
import com.github.dtschust.zork.parser.PropertyParseStrategy;
|
||||
import com.github.dtschust.zork.parser.TriggerPropertyParseStrategy;
|
||||
import com.github.dtschust.zork.types.ZorkCreature;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public class ZorkCreatureParseStrategy implements PropertyParseStrategy<ZorkCreature> {
|
||||
|
||||
private final PropertyParseStrategy<ZorkCondition> conditionStrategy;
|
||||
private final TriggerPropertyParseStrategy triggerStrategy;
|
||||
|
||||
public ZorkCreatureParseStrategy(final PropertyParseStrategy<ZorkCondition> conditionStrategy,
|
||||
final TriggerPropertyParseStrategy triggerStrategy) {
|
||||
this.conditionStrategy = conditionStrategy;
|
||||
this.triggerStrategy = triggerStrategy;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ZorkCreature parse(final Property source) {
|
||||
// Get all possible creature attributes
|
||||
final List<ZorkCondition> conditions = source.subPropertiesByName("attack").stream()
|
||||
.flatMap(e -> e.subPropertiesByName("condition").stream())
|
||||
.map(conditionStrategy::parse)
|
||||
.collect(Collectors.toList());
|
||||
|
||||
final List<String> prints = source.subPropertiesByName("attack").stream()
|
||||
.flatMap(e -> e.subPropertyValues("print").stream())
|
||||
.collect(Collectors.toList());
|
||||
|
||||
final List<String> actions = source.subPropertiesByName("attack").stream()
|
||||
.flatMap(e -> e.subPropertyValues("action").stream())
|
||||
.collect(Collectors.toList());
|
||||
|
||||
final List<String> vulnerabilities = source.subPropertyValues("vulnerability");
|
||||
|
||||
final List<ZorkTrigger> triggers = source.subPropertiesByName("trigger").stream()
|
||||
.map(triggerStrategy.parse(source))
|
||||
.collect(Collectors.toList());
|
||||
|
||||
final String name = source.subPropertyValue("name", "");
|
||||
|
||||
final String description = source.subPropertyValue("description", "");
|
||||
|
||||
final String status = source.subPropertyValue("status", "");
|
||||
|
||||
return new ZorkCreature(name, description, status, triggers, vulnerabilities, conditions, prints, actions);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,46 @@
|
|||
package com.github.dtschust.zork.parser.strategies;
|
||||
|
||||
import com.github.dtschust.zork.ZorkTrigger;
|
||||
import com.github.dtschust.zork.parser.Property;
|
||||
import com.github.dtschust.zork.parser.PropertyParseStrategy;
|
||||
import com.github.dtschust.zork.parser.TriggerPropertyParseStrategy;
|
||||
import com.github.dtschust.zork.types.ZorkItem;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public class ZorkItemParseStrategy implements PropertyParseStrategy<ZorkItem> {
|
||||
|
||||
private final TriggerPropertyParseStrategy triggerStrategy;
|
||||
|
||||
public ZorkItemParseStrategy(final TriggerPropertyParseStrategy triggerStrategy) {
|
||||
this.triggerStrategy = triggerStrategy;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ZorkItem parse(final Property source) {
|
||||
final List<String> prints = source.subPropertiesByName("turnon").stream()
|
||||
.flatMap(e -> e.subPropertyValues("print").stream())
|
||||
.collect(Collectors.toList());
|
||||
|
||||
final List<String> actions = source.subPropertiesByName("turnon").stream()
|
||||
.flatMap(e -> e.subPropertyValues("action").stream())
|
||||
.collect(Collectors.toList());
|
||||
|
||||
final List<ZorkTrigger> triggers = source.subPropertiesByName("trigger").stream()
|
||||
.map(triggerStrategy.parse(source))
|
||||
.collect(Collectors.toList());
|
||||
|
||||
/* Get all possible item attributes*/
|
||||
|
||||
return new ZorkItem(
|
||||
source.subPropertyValue("name", ""),
|
||||
source.subPropertyValue("description", ""),
|
||||
source.subPropertyValue("status", ""),
|
||||
source.subPropertyValue("writing", ""),
|
||||
triggers,
|
||||
prints,
|
||||
actions
|
||||
);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,50 @@
|
|||
package com.github.dtschust.zork.parser.strategies;
|
||||
|
||||
import com.github.dtschust.zork.ZorkTrigger;
|
||||
import com.github.dtschust.zork.parser.Property;
|
||||
import com.github.dtschust.zork.parser.PropertyParseStrategy;
|
||||
import com.github.dtschust.zork.parser.TriggerPropertyParseStrategy;
|
||||
import com.github.dtschust.zork.types.ZorkDirection;
|
||||
import com.github.dtschust.zork.types.ZorkRoom;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public class ZorkRoomParseStrategy implements PropertyParseStrategy<ZorkRoom> {
|
||||
|
||||
private final TriggerPropertyParseStrategy triggerStrategy;
|
||||
|
||||
public ZorkRoomParseStrategy(final TriggerPropertyParseStrategy triggerStrategy) {
|
||||
this.triggerStrategy = triggerStrategy;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ZorkRoom parse(final Property source) {
|
||||
// Get all possible Room attributes
|
||||
|
||||
final String name = source.subPropertyValue("name", "");
|
||||
|
||||
final String description = source.subPropertyValue("description", "");
|
||||
|
||||
final String type = source.subPropertyValue("type", "regular");
|
||||
|
||||
final List<ZorkTrigger> triggers = source.subPropertiesByName("trigger").stream()
|
||||
.map(triggerStrategy.parse(source))
|
||||
.collect(Collectors.toList());
|
||||
|
||||
final String status = source.subPropertyValue("status", "");
|
||||
|
||||
final List<String> items = source.subPropertyValues("item");
|
||||
final List<String> creatures = source.subPropertyValues("creature");
|
||||
final List<String> containers = source.subPropertyValues("container");
|
||||
|
||||
final Map<ZorkDirection, String> borders = source.subPropertiesByName("border").stream()
|
||||
.collect(Collectors.toMap(
|
||||
e -> ZorkDirection.fromLong(e.subPropertyValue("direction")),
|
||||
e -> e.subPropertyValue("name")
|
||||
));
|
||||
|
||||
return new ZorkRoom(name, description, type, status, triggers, borders, containers, items, creatures);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,39 @@
|
|||
package com.github.dtschust.zork.parser.strategies;
|
||||
|
||||
import com.github.dtschust.zork.ZorkCommand;
|
||||
import com.github.dtschust.zork.ZorkCondition;
|
||||
import com.github.dtschust.zork.ZorkTrigger;
|
||||
import com.github.dtschust.zork.parser.Property;
|
||||
import com.github.dtschust.zork.parser.PropertyParseStrategy;
|
||||
import com.github.dtschust.zork.parser.TriggerPropertyParseStrategy;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public class ZorkTriggerParseStrategy implements TriggerPropertyParseStrategy {
|
||||
|
||||
private final PropertyParseStrategy<ZorkCondition> conditionStrategy;
|
||||
|
||||
public ZorkTriggerParseStrategy(final PropertyParseStrategy<ZorkCondition> conditionStrategy) {
|
||||
this.conditionStrategy = conditionStrategy;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ZorkTrigger parseTrigger(final Property source, final Property parent) {
|
||||
final String type = parent.subPropertyValue("type", "single");
|
||||
|
||||
final List<ZorkCommand> commands = source.subPropertiesByName("command").stream()
|
||||
.map(Property::value)
|
||||
.map(ZorkCommand::new)
|
||||
.collect(Collectors.toList());
|
||||
|
||||
final List<ZorkCondition> conditions = source.subPropertiesByName("condition").stream()
|
||||
.map(conditionStrategy::parse)
|
||||
.collect(Collectors.toList());
|
||||
|
||||
final List<String> prints = source.subPropertyValues("print");
|
||||
final List<String> actions = source.subPropertyValues("action");
|
||||
|
||||
return new ZorkTrigger(type, conditions, commands, prints, actions);
|
||||
}
|
||||
}
|
|
@ -1,9 +1,9 @@
|
|||
package com.github.dtschust.zork.repl.actions;
|
||||
|
||||
import com.github.dtschust.zork.Zork.Type;
|
||||
import com.github.dtschust.zork.ZorkGame;
|
||||
import com.github.dtschust.zork.repl.Action;
|
||||
import com.github.dtschust.zork.types.HasSetOfCollectable;
|
||||
import com.github.dtschust.zork.types.ZorkGameStatusType;
|
||||
import com.github.dtschust.zork.types.ZorkObject;
|
||||
|
||||
import java.util.List;
|
||||
|
@ -29,8 +29,8 @@ public class AddAction implements Action {
|
|||
final String destination = arguments.get(3);
|
||||
|
||||
try {
|
||||
Type destType = game.getTypeFromLookup(destination);
|
||||
Type objType = game.getTypeFromLookup(object);
|
||||
ZorkGameStatusType destType = game.getTypeFromLookup(destination);
|
||||
ZorkGameStatusType objType = game.getTypeFromLookup(object);
|
||||
ZorkObject tempObject = game.get(destType, destination);
|
||||
((HasSetOfCollectable) tempObject).getSetFromType(objType).add(object);
|
||||
game.put(destType, tempObject);
|
||||
|
|
|
@ -6,7 +6,7 @@ import com.github.dtschust.zork.types.ZorkCreature;
|
|||
|
||||
import java.util.List;
|
||||
|
||||
import static com.github.dtschust.zork.Zork.Type.CREATURE;
|
||||
import static com.github.dtschust.zork.types.ZorkGameStatusType.CREATURE;
|
||||
|
||||
/**
|
||||
* Attempt an attack, do you feel lucky?
|
||||
|
|
|
@ -1,22 +1,22 @@
|
|||
package com.github.dtschust.zork.repl.actions;
|
||||
|
||||
import com.github.dtschust.zork.Zork.Type;
|
||||
import com.github.dtschust.zork.ZorkGame;
|
||||
import com.github.dtschust.zork.repl.Action;
|
||||
import com.github.dtschust.zork.types.HasSetOfCollectable;
|
||||
import com.github.dtschust.zork.types.ZorkGameStatusType;
|
||||
import com.github.dtschust.zork.types.ZorkObject;
|
||||
import com.github.dtschust.zork.types.ZorkRoom;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import static com.github.dtschust.zork.Zork.Type.*;
|
||||
import static com.github.dtschust.zork.types.ZorkGameStatusType.*;
|
||||
|
||||
/**
|
||||
* Delete: figure out what object it is and delete it accordingly. Rooms are especially tricky
|
||||
*/
|
||||
public class DeleteAction implements Action {
|
||||
private static void deleteElementFromSpace(ZorkGame game, Type space, Type element, String object) {
|
||||
private static void deleteElementFromSpace(ZorkGame game, ZorkGameStatusType space, ZorkGameStatusType element, String object) {
|
||||
for (ZorkObject tempObject : game.values(ZorkObject.class, space)) {
|
||||
Set<String> set = ((HasSetOfCollectable) tempObject).getSetFromType(element);
|
||||
if (set.contains(object)) {
|
||||
|
|
|
@ -6,7 +6,7 @@ import com.github.dtschust.zork.types.ZorkRoom;
|
|||
|
||||
import java.util.List;
|
||||
|
||||
import static com.github.dtschust.zork.Zork.Type.ROOM;
|
||||
import static com.github.dtschust.zork.types.ZorkGameStatusType.ROOM;
|
||||
|
||||
public class DropItemAction implements Action {
|
||||
@Override
|
||||
|
|
|
@ -6,7 +6,7 @@ import com.github.dtschust.zork.types.ZorkContainer;
|
|||
|
||||
import java.util.List;
|
||||
|
||||
import static com.github.dtschust.zork.Zork.Type.CONTAINER;
|
||||
import static com.github.dtschust.zork.types.ZorkGameStatusType.CONTAINER;
|
||||
|
||||
public class OpenAction implements Action {
|
||||
@Override
|
||||
|
|
|
@ -6,7 +6,7 @@ import com.github.dtschust.zork.types.ZorkContainer;
|
|||
|
||||
import java.util.List;
|
||||
|
||||
import static com.github.dtschust.zork.Zork.Type.CONTAINER;
|
||||
import static com.github.dtschust.zork.types.ZorkGameStatusType.CONTAINER;
|
||||
|
||||
public class PutAction implements Action {
|
||||
@Override
|
||||
|
|
|
@ -6,7 +6,7 @@ import com.github.dtschust.zork.types.ZorkItem;
|
|||
|
||||
import java.util.List;
|
||||
|
||||
import static com.github.dtschust.zork.Zork.Type.ITEM;
|
||||
import static com.github.dtschust.zork.types.ZorkGameStatusType.ITEM;
|
||||
|
||||
public class ReadAction implements Action {
|
||||
@Override
|
||||
|
|
|
@ -7,8 +7,8 @@ import com.github.dtschust.zork.types.ZorkRoom;
|
|||
|
||||
import java.util.List;
|
||||
|
||||
import static com.github.dtschust.zork.Zork.Type.CONTAINER;
|
||||
import static com.github.dtschust.zork.Zork.Type.ROOM;
|
||||
import static com.github.dtschust.zork.types.ZorkGameStatusType.CONTAINER;
|
||||
import static com.github.dtschust.zork.types.ZorkGameStatusType.ROOM;
|
||||
|
||||
public class TakeAction implements Action {
|
||||
@Override
|
||||
|
|
|
@ -6,7 +6,7 @@ import com.github.dtschust.zork.types.ZorkItem;
|
|||
|
||||
import java.util.List;
|
||||
|
||||
import static com.github.dtschust.zork.Zork.Type.ITEM;
|
||||
import static com.github.dtschust.zork.types.ZorkGameStatusType.ITEM;
|
||||
|
||||
/**
|
||||
* Turn on an item
|
||||
|
|
|
@ -1,12 +1,10 @@
|
|||
package com.github.dtschust.zork.types;
|
||||
|
||||
import com.github.dtschust.zork.Zork;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
public interface HasSetOfCollectable {
|
||||
|
||||
default Set<String> getSetFromType(Zork.Type type) {
|
||||
default Set<String> getSetFromType(ZorkGameStatusType type) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,11 +1,10 @@
|
|||
package com.github.dtschust.zork.types;
|
||||
|
||||
import com.github.dtschust.zork.Zork;
|
||||
import com.github.dtschust.zork.ZorkTrigger;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
import static com.github.dtschust.zork.Zork.Type.ITEM;
|
||||
import static com.github.dtschust.zork.types.ZorkGameStatusType.ITEM;
|
||||
|
||||
/* Container*/
|
||||
public class ZorkContainer extends ZorkObject implements HasSetOfCollectable {
|
||||
|
@ -59,7 +58,7 @@ public class ZorkContainer extends ZorkObject implements HasSetOfCollectable {
|
|||
}
|
||||
|
||||
@Override
|
||||
public Set<String> getSetFromType(Zork.Type type) {
|
||||
public Set<String> getSetFromType(ZorkGameStatusType type) {
|
||||
if (type.equals(ITEM))
|
||||
return items;
|
||||
throw new IllegalStateException("Unexpected value: " + type);
|
||||
|
|
|
@ -0,0 +1,21 @@
|
|||
package com.github.dtschust.zork.types;
|
||||
|
||||
import java.util.EnumSet;
|
||||
import java.util.Optional;
|
||||
|
||||
public enum ZorkGameStatusType {
|
||||
ROOM("room"),
|
||||
ITEM("item"),
|
||||
CONTAINER("container"),
|
||||
CREATURE("creature");
|
||||
|
||||
private final String propertyName;
|
||||
|
||||
ZorkGameStatusType(final String propertyName) {
|
||||
this.propertyName = propertyName;
|
||||
}
|
||||
|
||||
public static Optional<ZorkGameStatusType> fromPropertyName(final String propertyName) {
|
||||
return EnumSet.allOf(ZorkGameStatusType.class).stream().filter(e -> e.propertyName.equals(propertyName)).findFirst();
|
||||
}
|
||||
}
|
|
@ -1,7 +1,6 @@
|
|||
package com.github.dtschust.zork.types;
|
||||
|
||||
|
||||
import com.github.dtschust.zork.Zork;
|
||||
import com.github.dtschust.zork.ZorkTrigger;
|
||||
|
||||
import java.util.*;
|
||||
|
@ -32,7 +31,7 @@ public class ZorkRoom extends ZorkObject implements HasSetOfCollectable {
|
|||
}
|
||||
|
||||
@Override
|
||||
public Set<String> getSetFromType(Zork.Type type) {
|
||||
public Set<String> getSetFromType(ZorkGameStatusType type) {
|
||||
switch (type) {
|
||||
case CONTAINER:
|
||||
return getContainer();
|
||||
|
|
Reference in a new issue