/* Import the Java I/O package */
import java.io.*;
import AppletConsoleApp;

/**
 * Solution to the 1999 British Informatics Olympiad exam
 * question 2: Black Box (Atom)
 *
 * This application that can be run either from the console
 * as a stand-alone application or from an in-applet
 * console created with the AppletConsole applet.
 *
 * Solution copyright (c) 1999 The British Informatics Olympiad (BIO).
 *
 * This program may be freely copied by persons or organisations
 * involved in the British Informatics Olympiad or the International
 * Olympiad in Informatics, on condition that no changes are made and
 * this notice is not altered. Distribution for profit is forbidden
 * unless permission is first obtained in writing from the BIO.
 *
 * This program is for educational purposes only and comes with no
 * warranty, implied or otherwise, as to its fitness for any purpose.
 *
 * Author:     Antony Rix
 * Internet:   http://www.christs.cam.ac.uk/bio/
 * E-mail:     a.rix@lineone.net
 * S-mail:     The British Informatics Olympiad
 *             Christ's College
 *             Cambridge CB2 3BU
 *             United Kingdom
 *
 * @author    Antony Rix
 * @version 0.1
 * @see         AppletConsoleApp
 * @see         AppletConsole
 */
class BIO99R1Q2App extends AppletConsoleApp {
    /**
     * Start the application from the command line.
     */
    public static void main(String[] args) {
        BIO99R1Q2App thisApp = new BIO99R1Q2App();
        thisApp.redirectStreams(System.in, System.out);
        thisApp.run();
    }

    /**
     * Key constants.
     */
    static int Blank = 0;
    static int Atom = 1;
    static int Ray = 2;
    static int Hit = 3;

    /**
     * Array holding board.
     */
    int[][] Board = new int[12][12];

    /**
     * Result of injecting the atom
     */
    String result = "";

    /**
     * The implementation of this application.
     */
    public void run() {
        int i, x, y;
        String side;

        init_board();
        out.println(
            "Enter 5 co-ordinates in the form x y" );
        
        try {
            /* Create a StreamTokenizer to allow us to read in the start numbers
            */
            StreamTokenizer sin = new StreamTokenizer( in );
            for( i = 1; i <= 5; i++ ) {
                out.print( ">" );
                sin.nextToken();
                x = (int)sin.nval;
                sin.nextToken();
                y = (int)sin.nval;
                Board[x][y] = Atom;
            }
            show_board();
            out.println();

            /* Main program loop: read in a character/number pair and then
               perform that action */
            do {
                out.print( ">" );
                sin.nextToken();
                side = sin.sval;
                sin.nextToken();
                i = (int)sin.nval;
                if( (side.equalsIgnoreCase("T") || side.equalsIgnoreCase("B") ||
                     side.equalsIgnoreCase("L") || side.equalsIgnoreCase("R")) &&
                    (i > 0) && (i < 11) ) {
                    trace_ray( side, i );
                    show_board();
                    reset_board();
                    out.println( result );
                    out.println();
                }
                else if( !side.equalsIgnoreCase("X") )
                    out.println( "Invalid input '" + side + " " + i + "'" );
            } while ( !side.equalsIgnoreCase("X") );
        } catch (IOException e) { out.println("I/O failure"); };
        out.println( "Program finished." );
    }

    /**
     *
     */
    public void init_board() {
        int i, j;
        for( i = 0; i < 12; i++ )
            for( j = 0; j < 12; j++ )
                Board[i][j] = Blank;
    }

    /**
     *
     */
    public void reset_board() {
        int x, y;
        for( x = 0; x < 12; x++ )
            for( y = 0; y < 12; y++ )
                switch (Board[x][y]) {
                    case 0: Board[x][y] = Blank; break;
                    case 1: Board[x][y] = Atom; break;
                    case 2: Board[x][y] = Blank; break;
                    case 3: Board[x][y] = Atom; break;
                }
    }

    /**
     * Display the current board.
     */
    public void show_board() {
        int x, y;
        for( y = 10; y >= 1; y-- ) {
            for( x = 1; x <= 10; x++ )
            switch (Board[x][y]) {
                case 0: out.print( "." ); break;
                case 1: out.print( "A" ); break;
                case 2: out.print( "+" ); break;
                case 3: out.print( "*" ); break;
            }
            out.print( "\n" );
        }
    }

    /**
     * Follow the path of the ray.
     */
    public void trace_ray( String side, int pos ) {
        int direct;
        int x, y, nx, ny;
        
        /* Starting position and direction */
        if( side.equalsIgnoreCase("B") ) { direct = 0; x = pos; y = 1; }
        else if( side.equalsIgnoreCase("L") ) { direct = 1; y = pos; x = 1; }
        else if( side.equalsIgnoreCase("T") ) { direct = 2; x = pos; y = 10; }
        else if( side.equalsIgnoreCase("R") ) { direct = 3; y = pos; x = 10; }
        else return;

        /* Follow ray until it runs out of the box */
        while( (x > 0) && (x < 11) && (y > 0) && (y < 11) ) {
            Board[x][y] = Ray;

            /* Find new position then apply the rules */
            nx = x; ny = y;
            switch (direct) {
                case 0: ny = y + 1; break;
                case 1: nx = x + 1; break;
                case 2: ny = y - 1; break;
                case 3: nx = x - 1; break;
            }

            /* If absorbed, show the hit and return */
            if( Board[nx][ny] == Atom ) {
                Board[nx][ny] = Hit;
                result = "Absorbed";
                return;
            }

            /* If reflected, simply return - the ray will retrace its path */
            if( (direct == 0) || (direct == 2) ) {
                if( (Board[nx-1][ny] == Atom) && (Board[nx+1][ny] == Atom) ) {
                    result = "Reflected"; return;
                }
            }
            else {
                if( (Board[nx][ny-1] == Atom) && (Board[nx][ny+1] == Atom) ) {
                    result = "Reflected"; return;
                }
            }

            /* Check for a deflection.  If we deflect, move back to the last
               position and change direction. */
            if( (direct == 0) || (direct == 2) ) {
                if( Board[nx-1][ny] == Atom) { direct = 1; ny = y; }
                if( Board[nx+1][ny] == Atom) { direct = 3; ny = y; }
            }
            else {
                if( Board[nx][ny-1] == Atom) { direct = 0; nx = x; }
                if( Board[nx][ny+1] == Atom) { direct = 2; nx = x; }
            }

            /* Update position */
            x = nx;
            y = ny;
        }
        /* Find exit point */
        if( x == 0 ) result = "L " + y;
        if( y == 0 ) result = "B " + x;
        if( x == 11 ) result = "R " + y;
        if( y == 11 ) result = "T " + x;
        result = "Exits at " + result;
    }
}
