package rabbitescape.engine.solution; import java.util.ArrayList; import java.util.Arrays; import java.util.Iterator; import java.util.List; import rabbitescape.engine.World.CompletionState; import rabbitescape.engine.solution.SolutionExceptions.UnexpectedState; public class SolutionInterpreter { private static final int maxUntils = 1000; private final Iterator<SolutionCommand> commandIt; private int commandIndex; private final WonAssertCreator wonAssert; private WaitNextable wait; private CompletionState untilState; private SolutionCommand command; private int untilCount; public boolean emptySteps = false; /** * appendWon defaults to true if you omit it. */ public SolutionInterpreter( Solution solution ) { this( solution, true ); } /** * @param solution * @param appendWon add a "WON" assertion at the end, if the last command * is not already a single state assertion. */ public SolutionInterpreter( Solution solution, boolean appendWon ) { this.commandIt = Arrays.asList( solution.commands ).iterator(); this.commandIndex = 0; this.wonAssert = new WonAssertCreator( appendWon ); this.wait = null; this.untilState = null; this.command = null; this.untilCount = -1; } public static SolutionInterpreter getNothingPlaying() { SolutionInterpreter nothingPlaying = new SolutionInterpreter( SolutionParser.parse( "1" ) ); nothingPlaying.emptySteps = true; return nothingPlaying; } public SolutionTimeStep next( CompletionState worldState ) { if ( emptySteps ) { return new SolutionTimeStep( ++commandIndex, new TimeStepAction[] {} ); } if ( wait != null ) { SolutionTimeStep ret = wait.next(); if ( ret != null ) { return ret; } } if ( untilState != null ) { if ( worldState != CompletionState.RUNNING ) { SolutionTimeStep ret = new SolutionTimeStep( commandIndex, new AssertStateAction( untilState ) ); untilState = null; untilCount = -1; wonAssert.done = true; return ret; } else if ( untilCount > maxUntils ) { throw new SolutionExceptions.UntilActionNeverEnded( untilState ); } else { ++untilCount; return new SolutionTimeStep( commandIndex ); } } return nextTimeStep( worldState ); } private SolutionTimeStep nextTimeStep( final CompletionState worldState ) { wait = null; if ( ! commandIt.hasNext() ) { ++commandIndex; return wonAssert.create( commandIndex, command ); } command = commandIt.next(); ++commandIndex; // Work around need for final variable class StepsToWait { int value = 0; }; final StepsToWait stepsToWait = new StepsToWait(); final List<TimeStepAction> tsActions = new ArrayList<TimeStepAction>(); for ( CommandAction action : command.actions ) { action.typeSwitch( new CommandActionTypeSwitch() { @Override public void caseWaitAction( WaitAction waitAction ) { stepsToWait.value += waitAction.steps; } @Override public void caseUntilAction( UntilAction untilAction ) { untilState = untilAction.targetState; untilCount = 0; if ( worldState != CompletionState.RUNNING ) { tsActions.add( new AssertStateAction( untilState ) ); wonAssert.done = true; untilState = null; } } @Override public void caseSelectAction( SelectAction action ) { tsActions.add( action ); } @Override public void casePlaceTokenAction( PlaceTokenAction action ) { tsActions.add( action ); } @Override public void caseAssertStateAction( AssertStateAction action ) throws UnexpectedState { tsActions.add( action ); } // Curse you, Java, for making me this way } ); } if ( stepsToWait.value > 1 ) { wait = new WaitNextable( commandIndex, stepsToWait.value - 1 ); } return new SolutionTimeStep( commandIndex, tsActions.toArray( new TimeStepAction[ tsActions.size() ] ) ); } private static class WaitNextable { private final int commandIndex; private int stepsLeft; public WaitNextable( int commandIndex, int steps ) { this.commandIndex = commandIndex; this.stepsLeft = steps; } public SolutionTimeStep next() { if ( stepsLeft > 0 ) { --stepsLeft; return new SolutionTimeStep( commandIndex ); } return null; } } private static class WonAssertCreator { private final boolean appendWon; public boolean done; public WonAssertCreator( boolean appendWon ) { this.appendWon = appendWon; this.done = false; } public SolutionTimeStep create( int commandIndex, SolutionCommand lastCommand ) { if ( done || !appendWon ) { return null; } if ( lastCommand != null && lastCommand.actions.length == 1 && lastCommand.actions[0] instanceof AssertStateAction ) { return null; } done = true; return new SolutionTimeStep( commandIndex, new AssertStateAction( CompletionState.WON ) ); } } }