package rabbitescape.ui.text; import java.io.IOException; import static rabbitescape.engine.i18n.Translation.*; import rabbitescape.engine.err.ExceptionTranslation; import rabbitescape.engine.err.RabbitEscapeException; import rabbitescape.engine.solution.AssertStateAction; import rabbitescape.engine.solution.SandboxGame; import rabbitescape.engine.solution.Solution; import rabbitescape.engine.solution.SolutionExceptions; import rabbitescape.engine.solution.SolutionParser; import rabbitescape.engine.solution.SolutionRecorder; import rabbitescape.engine.solution.SolutionRunner; import rabbitescape.engine.solution.UntilAction; import rabbitescape.engine.solution.SolutionCommand; import rabbitescape.engine.util.Util; public class InputHandler { private final SandboxGame sandboxGame; private final Terminal terminal; private final SolutionRecorder recorder; public InputHandler( SandboxGame sandboxGame, Terminal terminal ) { this.sandboxGame = sandboxGame; this.terminal = terminal; this.recorder = new SolutionRecorder(); } public boolean handle( int commandIndex ) { String input = input(); input = expandAbbreviations( input ); if ( input.equals( "help" ) ) { return help(); } else if ( input.equals( "exit" ) ) { sandboxGame.getWorld().changes.explodeAllRabbits(); sandboxGame.getWorld().step(); return true; } try { Solution partialSolution = SolutionParser.parse( input ); SolutionRunner.runPartialSolution( partialSolution, sandboxGame ); if ( partialSolution.commands.length == 0 ) { return fail( t( "Unexpected problem: no SolutionCommand" ) ); } SolutionCommand command = partialSolution.commands[ partialSolution.commands.length - 1 ]; // TODO: until commands step past the last time step, so we // avoid stepping here. if ( ! ( ( command.actions.length == 1 && ( command.actions[0] instanceof UntilAction || command.actions[0] instanceof AssertStateAction ) ) ) ) { // TODO: it's weird we have to do the last time step // outside of runSingleCommand sandboxGame.getWorld().step(); } appendAll( partialSolution ); } catch ( SolutionExceptions.ProblemRunningSolution e ) { e.commandIndex = commandIndex; e.solutionId = 1; return fail( ExceptionTranslation.translate( e, terminal.locale ) ); } catch ( RabbitEscapeException e ) { return fail( ExceptionTranslation.translate( e, terminal.locale ) ); } return true; } /** * Note: changes the argument. */ static String expandAbbreviations( String input ) { if ( input.equals( "" ) ) { return "1"; } // Surround coordinates with brackets input = Util.regexReplace( input, "\\(?+([0-9]+,[0-9]+)\\)?+", "($1)" ); // Expand token selection shortcuts for ( InputExpansion e : InputExpansion.expansions ) { input = Util.regexReplace( input, "\\b" + e.character + "\\b", e.expansion ); } return input; } private void appendAll( Solution solution ) { recorder.append( solution ); } private boolean help() { String msg = "\n" + "Press return to move forward a time step.\n" + "Type 'exit' to stop.\n" + "Type an ability name (e.g. 'bash') to switch to that ability.\n" + "Type '(x,y)' (e.g '(2,3)') to place a token.\n" + "Type a number (e.g. '5') to skip that many steps.\n" + "\n" + "The following abbreviations are available:\n" ; for ( InputExpansion e : InputExpansion.expansions ) { msg = msg + e + "\n"; } msg += "Brackets may be omitted when placing tokens: '2,3'.\n" + "Multiple commands may be joined by ';'.\n"; terminal.out.println( t( msg ) ); return false; } private boolean fail( String message ) { terminal.out.println( message ); return false; } private String input() { terminal.out.println( t( "Type 'help' then press return for help." ) ); try { terminal.out.print( "> " ); return terminal.in.readLine(); } catch ( IOException e ) { return ""; } } public String solution() { return recorder.getRecord(); } }