import eprog.*; /** * state machine * @author Peter Schueller mail:e0125596@student.tuwien.ac.at */ class StateMachine { /** * generic state of state machine */ public abstract class State { /** * get input oInput at status oData from this state and return next state index * @param oInput the input which triggers the transition * @param oData the data which stores additional information of the state machine * @return int: index of new state */ public abstract int doTransition( Object oInput, Object oData ); /** * code to be executed at entering this state * @param oInput input which triggered the transition which triggered entering this state * @param oData additional information of the state machine */ public void enterState( Object oInput, Object oData ) { } /** * code to be executed at leaving his state * @param oInput input which triggered the transition which triggered exiting this state * @param oData additional information of the state machine */ public void exitState( Object oInput, Object oData ) { } /** * true if this state is a stop-state, else false */ public final boolean bIsStopState = false; } /** * states of this state machine (static to enable multiple state machines of this type while saving memory) */ protected static State[] sStates = null; /** * index of current state of state machine, always starts at index 0 */ protected int iActiveState; /** * additional information stored in the state machine and passed to the state transition functions */ protected Object oData; /** * constructor */ public StateMachine() { iActiveState = 0; if( sStates != null ) sStates[0].enterState( null, null ); } /** * process input to state-machine: * *) calculate transition * *) execute transition functions if needed * @param oInput input object of this state machine which has to processed * @return int: index of state which was entered after processing the input */ public int processInput( Object oInput ) { //check if the machine has stopped if( sStates[iActiveState].bIsStopState ) return -1; //process input with current state int iNextState = sStates[iActiveState].doTransition( oInput, oData ); //if state has changed, do enter and exit procedures if( iActiveState != iNextState ) { sStates[iActiveState].exitState( oInput, oData ); sStates[iNextState].enterState( oInput, oData ); iActiveState = iNextState; } return iActiveState; } /** * stop-detection * @return true if machine has entered a stop-state, else false */ public boolean hasStopped() { return sStates[iActiveState].bIsStopState; } /** * get status data * @return Object: additional information of state machine */ public Object getData() { return oData; } } /** * main class * @author Peter Schueller mail: e0125596@student.tuwien.ac.at */ public class dekomp extends EprogIO { /** * special state machine for decoding run-length-compressed strings */ protected static class dekompStateMachine extends StateMachine { /** * initial state */ public static final byte START = 0; /** * state in single mode */ public static final byte SINGLE = 1; /** * state after occurence of ' in single mode */ public static final byte MULTI_START = 2; /** * multi mode, waiting for multiplication digit */ public static final byte MULTI_WAITDIGIT = 3; /** * multi mode, waiting for next character to multiply */ public static final byte MULTI_WAITCHAR = 4; /** * multi mode, ' was received, waiting for '(multiply ') or for character (exit multi mode, print char) */ public static final byte MULTI_LEAVE = 5; /** * error state (final state) */ public static final byte ERROR = 6; /** * storage class for state-machine input storage */ protected static class smInput { /** * input was ' */ public static final byte HYPHEN = 0; /** * input was a digit, number is stored in iInfo */ public static final byte DIGIT = 1; /** * input was a character which is stored in cInfo */ public static final byte CHAR = 2; /** * type of input: hyphen / digit / character */ public byte iType; /** * character which was entered */ public char cInfo; /** * number information which was entered */ public int iInfo; /** * constructor: decodes input and calculates type * @param cInput input character which has to be represented by this class */ public smInput( char cInput ) { //digit if( "0123456789".indexOf( cInput ) != -1 ) { iInfo = (int)( cInput - '0' ); iType = DIGIT; //' } else if( cInput == '\'' ) { iType = HYPHEN; //everything else } else { cInfo = cInput; iType = CHAR; } } } /** * storage class for state-machine status storage */ protected static class smData { /** * active decoded string */ public String s; /** * last character which was entered */ public char lastChar; /** * constructor */ public smData() { s = ""; lastChar = (char)-1; } } /** * constructor for this state machine * builds states */ public dekompStateMachine() { super(); oData = new smData(); //initialise the states of this special state machine //but only if sStates was not initialised before (static) if( sStates == null ) { sStates = new State[] { //state 0: start //' -> goto multi mode start, character -> print, goto single mode new State() { public int doTransition( Object oInput, Object oData ) { smInput i = (smInput)oInput; smData d = (smData)oData; switch( i.iType ) { case smInput.HYPHEN: return MULTI_START; case smInput.CHAR: d.s += i.cInfo; return SINGLE; default: return ERROR; } } }, //state 1: single (same as state 0, but cleaner if start state is visited only once) //' -> goto multi mode start, character -> print, goto single mode new State() { public int doTransition( Object oInput, Object oData ) { smInput i = (smInput)oInput; smData d = (smData)oData; switch( i.iType ) { case smInput.HYPHEN: return MULTI_START; case smInput.CHAR: d.s += i.cInfo; return SINGLE; default: return ERROR; } } }, //state 2: multi_start //' -> print ', stay in single mode, character -> save char in data, goto multi mode wait for digit new State() { public int doTransition( Object oInput, Object oData ) { smInput i = (smInput)oInput; smData d = (smData)oData; switch( i.iType ) { case smInput.HYPHEN: d.s += '\''; return SINGLE; case smInput.CHAR: d.lastChar = i.cInfo; return MULTI_WAITDIGIT; default: return ERROR; } } }, //state 3: multi_waitdigit //digit -> add digit times saved character to string and goto multi mode wait char mode new State() { public int doTransition( Object oInput, Object oData ) { smInput i = (smInput)oInput; smData d = (smData)oData; switch( i.iType ) { case smInput.DIGIT: for( int j = 0; j < i.iInfo; j++ ) d.s += d.lastChar; return MULTI_WAITCHAR; default: return ERROR; } } }, //state 4: multi_waitchar //' -> goto multi mode leave state, character -> store character, goto multi mode wait digit state new State() { public int doTransition( Object oInput, Object oData ) { smInput i = (smInput)oInput; smData d = (smData)oData; switch( i.iType ) { case smInput.HYPHEN: return MULTI_LEAVE; case smInput.CHAR: d.lastChar = i.cInfo; return MULTI_WAITDIGIT; default: return ERROR; } } }, //state 5: multi_leave //' -> save ' as last char and goto multi mode wait digit state (-> allows ' to be printed multliply), character -> leave multi mode, goto single mode, print input character new State() { public int doTransition( Object oInput, Object oData ) { smInput i = (smInput)oInput; smData d = (smData)oData; switch( i.iType ) { case smInput.HYPHEN: d.lastChar = '\''; return MULTI_WAITDIGIT; case smInput.CHAR: d.s += i.cInfo; return SINGLE; default: return ERROR; } } }, //state 6: error //stay there new State() { public final boolean bIsStopState = true; public int doTransition( Object oInput, Object oData ) { return ERROR; } } }; // sStates[] = } //if } //constructor StateMachine } //class state machine /** * decompression function * state-machine for decoding * * @param sInput String: input string * @return String with decoded sInput-string or null if error */ public static String decodeString( String sInput ) { dekompStateMachine SM = new dekompStateMachine(); int i; int iLastState = dekompStateMachine.ERROR; //process input in state machine for( i = 0; i < sInput.length(); i++ ) iLastState = SM.processInput( new dekompStateMachine.smInput( sInput.charAt(i) ) ); //only return sucess if end state was not waiting for something special or was an error switch( iLastState ) { case dekompStateMachine.SINGLE: case dekompStateMachine.MULTI_START: case dekompStateMachine.MULTI_WAITCHAR: case dekompStateMachine.MULTI_LEAVE: return ((dekompStateMachine.smData)SM.getData()).s; default: return null; } } /** * main program function * *) reads input * *) checks input for simple errors * *) if errors return error * *) else * *) calculates output and returns output * *) or returns error if calculation returned error * * @param args String[]: command line parameters */ public static void main( String[] args ) { String sInput = readWord(); String sOutput = null; boolean bError = false; //simple error: length error if( sInput.length() > 30 || sInput.length() < 1 ) bError = true; else { //no length error -> try calculation sOutput = decodeString( sInput ); if( sOutput == null ) bError = true; } if( bError ) println( "FALSCHE EINGABE" ); else println( sOutput ); } }