package rabbitescape.engine.solution; import java.util.ArrayList; import java.util.List; import java.util.regex.Matcher; import java.util.regex.Pattern; import static rabbitescape.engine.util.Util.*; import rabbitescape.engine.Token.Type; import rabbitescape.engine.World.CompletionState; import rabbitescape.engine.util.Util.Function; public class SolutionParser { public static final String COMMAND_DELIMITER = ";"; public static final String ACTION_DELIMITER = "&"; private static final Pattern WAIT_REGEX = Pattern.compile( "\\d+" ); private static final Pattern UNTIL_REGEX = Pattern.compile( "until:([A-Z]+)" ); private static final Pattern PLACE_TOKEN_REGEX = Pattern.compile( "\\((\\d+),(\\d+)\\)" ); private static final List<String> COMPLETION_STATES = toStringList( CompletionState.values() ); private static final List<String> TOKEN_TYPES = toStringList( Type.values() ); public static Solution parse( String solution ) { String[] stringCommands = split( solution, COMMAND_DELIMITER ); List<SolutionCommand> commands = new ArrayList<>(); for ( int i = 0; i < stringCommands.length; i++ ) { commands.add( parseCommand( stringCommands[i] ) ); } return new Solution( commands.toArray( new SolutionCommand[ commands.size() ] ) ); } public static SolutionCommand parseCommand( String commandString ) { ArrayList<CommandAction> actions = new ArrayList<CommandAction>(); String[] actionStrings = split( commandString, ACTION_DELIMITER ); for ( int j = 0; j < actionStrings.length; j++ ) { if ( !actionStrings[j].equals( "" ) ) { actions.add( makeAction( actionStrings[j] ) ); } } return new SolutionCommand( actions.toArray( new CommandAction[ actions.size() ] ) ); } public static String serialise( Solution solution ) { return join( ";", map( serialiseCommand(), solution.commands ) ); } // --- private static CommandAction makeAction( String actionString ) { try { return doMakeAction( actionString ); } catch ( NumberFormatException e ) { throw new InvalidAction( e, actionString ); } } private static CommandAction doMakeAction( String actionString ) throws NumberFormatException, InvalidAction { Matcher untilMatcher = UNTIL_REGEX.matcher( actionString ); if ( COMPLETION_STATES.contains( actionString ) ) { return new AssertStateAction( CompletionState.valueOf( actionString ) ); } else if ( untilMatcher.matches() ) { CompletionState state = CompletionState.valueOf( untilMatcher.group( 1 ) ); return new UntilAction( state ); } else if ( WAIT_REGEX.matcher( actionString ).matches() ) { return new WaitAction( Integer.valueOf( actionString ) ); } else if ( TOKEN_TYPES.contains( actionString ) ) { return new SelectAction( Type.valueOf( actionString ) ); } else { Matcher m = PLACE_TOKEN_REGEX.matcher( actionString ); if ( m.matches() ) { return new PlaceTokenAction( Integer.valueOf( m.group( 1 ) ), Integer.valueOf( m.group( 2 ) ) ); } } throw new InvalidAction( actionString ); } private static Function<SolutionCommand, String> serialiseCommand() { return new Function<SolutionCommand, String>() { @Override public String apply( SolutionCommand command ) { return join( "&", map( serialiseAction(), command.actions ) ); } }; } private static Function<CommandAction, String> serialiseAction() { return new Function<CommandAction, String>() { @Override public String apply( CommandAction action ) { ActionSerialiser s = new ActionSerialiser(); action.typeSwitch( s ); return s.ret; } }; } private static class ActionSerialiser implements CommandActionTypeSwitch { public String ret = null; @Override public void caseWaitAction( WaitAction waitAction ) { if ( waitAction.steps == 1 ) { ret = ""; } else { ret = String.valueOf( waitAction.steps ); } } @Override public void caseSelectAction( SelectAction selectAction ) { ret = selectAction.type.name(); } @Override public void caseAssertStateAction( AssertStateAction targetStateAction ) { ret = targetStateAction.targetState.name(); } @Override public void casePlaceTokenAction( PlaceTokenAction placeTokenAction ) { ret = "(" + placeTokenAction.x + "," + placeTokenAction.y + ")"; } @Override public void caseUntilAction( UntilAction untilAction ) { ret = "until:" + untilAction.targetState.name(); } } }