git @ Cat's Eye Technologies yoob / master src / lang / BackFlipState.java
master

Tree @master (Download .tar.gz)

BackFlipState.java @masterraw · history · blame

/*
 * A BackFlipState implements the semantics of BackFlip.
 * The source code in this file has been placed into the public domain.
 */
package tc.catseye.yoob.backflip;

import tc.catseye.yoob.*;
import tc.catseye.yoob.Error;

import java.util.List;
import java.util.ArrayList;

class BackFlip implements Language {
    public String getName() {
        return "BackFlip";
    }

    public int numPlayfields() {
        return 1;
    }

    public int numTapes() {
        return 0;
    }

    public boolean hasProgramText() {
        return false;
    }

    public boolean hasInput() {
        return false;
    }

    public boolean hasOutput() {
        return false;
    }

    public List<String> exampleProgramNames() {
        ArrayList<String> names = new ArrayList<String>();
        names.add("counter w/fixed mirror");
        names.add("decimal numeral register");
        return names;
    }

    public BackFlipState loadExampleProgram(int index) {
        // All examples from: http://www.esolangs.org/wiki/BackFlip
        // and presumably by ais523.
        // From the esowiki, thus in the public domain.
        String[][] program = {
          {
            "\\----------------------",
            "              ",
            "    V V V V V V V    V",
            "\\   />/>/>/>/>/>/    \\<",
            "   >\\>\\>\\>\\>\\>\\>\\<",
            "<   ^ ^ ^ ^ ^ ^ ^ ",
            "                  ",
            "                  ",
            "                  ",
            "                  ",
            "                     ^",
          },
          {
            "\\----------------------------",
            "                          \\",
            "\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\/",
            "              ",
            "   >  >  >  >  >  >  >  > V",
            " >> >> >> >> >> >> >> >> > V",
            "",
            "                        0 >/<",
            "                        1 ^/<",
            "                        2 ^/<",
            "                        3 ^/<",
            "                        4 ^/<",
            "                        5 ^/<",
            "                        6 ^/<",
            "                        7 ^/<",
            "                        8 ^/<",
            "                           ^",
          },
        };
        BackFlipState s = new BackFlipState();
        s.playfield.load(program[index]);
        return s;
    }

    public BackFlipState importFromText(String text) {
        BackFlipState s = new BackFlipState();
        s.playfield.load(text.split("\\r?\\n"));
        return s;
    }

    public List<String> getAvailableOptionNames() {
        ArrayList<String> names = new ArrayList<String>();
        return names;
    }

    private static final String[][] properties = {
        {"Author", "Alex Smith"},
        {"Implementer", "Chris Pressey"},
        {"Implementation notes",
         "In this implementation, the width of the playfield need not be determined " +
         "by the length of the first line; instead, the length of whichever line is " +
         "the longest determines the width."}
    };

    public String[][] getProperties() {
        return properties;
    }
}

public class BackFlipState implements State {
    protected CommonPlayfield playfield;
    protected BasicPlayfieldView pfView;
    protected boolean halted = false;
    private static final BackFlip language = new BackFlip();
  
    public BackFlipState() {
        /* The instruction pointer starts to the left of the top-left
         * corner of the program, going right.
         */
        playfield = new CommonPlayfield();
        pfView = new BasicPlayfieldView();
    }
    
    public BackFlipState clone() {
        BackFlipState c = new BackFlipState();
        c.playfield = this.playfield.clone();
        c.halted = halted;
        return c;
    }

    public BackFlip getLanguage() {
        return language;
    }

    private CharacterElement getReverseArrow(BasicCursor<CharacterElement> ip) {
        char a = ' ';
        if (ip.isHeaded(0, -1))
            a = 'V';
        else if (ip.isHeaded(0, 1))
            a = '^';
        else if (ip.isHeaded(-1, 0))
            a = '>';
        else if (ip.isHeaded(1, 0))
            a = '<';
        /* else error */
        return new CharacterElement(a);
    }

    public List<Error> step(World world) {
        ArrayList<Error> errors = new ArrayList<Error>();
        BasicCursor<CharacterElement> ip = playfield.getCursor(0);
        char instruction = ip.get().getChar();

        switch (instruction) {
            /*
             * If it encounters a backtracking direction change, the IP
             * moves in the direction suggested by that change, which
             * changes to point to the direction the IP came from.
             */
            case '<':
                ip.set(getReverseArrow(ip));
                ip.setDelta(-1, 0);
                break;
            case '>':
                ip.set(getReverseArrow(ip));
                ip.setDelta(1, 0);
                break;
            case '^':
                ip.set(getReverseArrow(ip));
                ip.setDelta(0, -1);
                break;
            case 'V':
                ip.set(getReverseArrow(ip));
                ip.setDelta(0, 1);
                break;
            /*
             * If it encounters a flipping mirror, the IP bounces off the
             * mirror like a ray of light would, and then the mirror changes
             * to the other sort of flipping mirror.
             */
            case '/':
                ip.set(new CharacterElement('\\'));
                ip.setDelta(ip.getDeltaY().negate(), ip.getDeltaX().negate());
                break;
            case '\\':
                ip.set(new CharacterElement('/'));
                ip.setDelta(ip.getDeltaY(), ip.getDeltaX());
                break;
            default:
                // nop
                break;
        }

        ip.advance();
        /*
         * If the IP goes off the edge of the file, execution terminates.
         * (Infinite loops are impossible in BackFlip, so this always happens).
         */
        if (playfield.hasFallenOffEdge(ip)) {
            halted = true;
        }

        return errors;
    }

    public Playfield getPlayfield(int index) {
        if (index == 0)
            return playfield;
        return null;
    }

    public Tape getTape(int index) {
        return null;
    }

    public String getProgramText() {
        return "";
    }

    public int getProgramPosition() {
        return 0;
    }

    public List<Error> setProgramText(String text) {
        ArrayList<Error> errors = new ArrayList<Error>();
        return errors;
    }

    public View getPlayfieldView(int index) {
        return pfView;
    }

    public View getTapeView(int index) {
        return null;
    }

    public String exportToText() {
        return playfield.dump();
    }

    public boolean hasHalted() {
        return halted;
    }

    public boolean needsInput() {
        return false;
    }

    public void setOption(String name, boolean value) {
    }

}