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

Tree @master (Download .tar.gz)

TwoIllState.java @masterraw · history · blame

/*
 * A TwoIllState implements the semantics of 2-ill.
 * The source code in this file has been placed into the public domain.
 */
package tc.catseye.yoob.twoill;

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

import java.util.List;
import java.util.ArrayList;
import java.util.Map;
import java.util.HashMap;


class TwoIll implements Language {
    public String getName() {
        return "2-ill";
    }

    public int numPlayfields() {
        return 1;
    }

    public int numTapes() {
        return 1;
    }

    public boolean hasProgramText() {
        return false;
    }

    public boolean hasInput() {
        return true;
    }

    public boolean hasOutput() {
        return true;
    }

    public List<String> exampleProgramNames() {
        ArrayList<String> names = new ArrayList<String>();
        names.add("example one");
        names.add("cat");
        names.add("tape test");
        return names;
    }

    public TwoIllState loadExampleProgram(int index) {
        // All examples from:
        // http://www.esolangs.org/wiki/2-ill
        // Various authors, including zzo38 and Chris Pressey.
        // From the esowiki, thus in the public domain.
        String[][] program = {
          {
            "'------'",
            "'@  @ @'",
            "'   @@ '",
            "'@#$ @ '",
            "'   #  '",
            "'      '",
            "'  @ @ '",
            "'  @@@ '",
            "'@    @'",
            "'------'"
          },
          {
            "@@@",
            "@$@",
            " | ",
            " # ",
            " | ",
            "@?@",
            "@@@"
          },
          {
            "@       @",
            "",
            "   @#   @",
            "   @   #@",
            "    @@  ",
            "@$#  @  ",
            "    @#  @"
          },
        };
        TwoIllState s = new TwoIllState();
        s.playfield.load(program[index]);
        return s;
    }

    public TwoIllState importFromText(String text) {
        TwoIllState s = new TwoIllState();
        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", "Aaron 'Zzo38' Black"},
        {"Implementer", "Chris Pressey"},
        {"Implementation notes",
         "Details of the language were discussed with Zzo38 on the talk page " +
         "of the esowiki article for the language, as implementation proceeded."},
    };

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

class TwoIllPlayfield extends CommonPlayfield {
    public TwoIllPlayfield clone() {
        TwoIllPlayfield c = new TwoIllPlayfield();
        c.copyBackingStoreFrom(this);
        c.ip = ip.clone();
        return c;
    }

    public void loadChar(int x, int y, char c) {
        switch (c) {
            // $ indicates start position of program, going east. If hit, it has no effect.
            case '$':
                ip.setX(x);
                ip.setY(y);
                ip.setDelta(1, 0);
                break;
        }
        super.loadChar(x, y, c);
    }
}

public class TwoIllState implements State {
    protected BasicTape<BitElement> tape;
    protected TwoIllPlayfield playfield;
    protected BasicPlayfieldView pfView;
    protected BasicTapeView tapeView;
    protected boolean halted = false;
    protected boolean needsInput = false;
    private static final TwoIll language = new TwoIll();

    public TwoIllState() {
        // The memory is a tape (similar to Brainfuck) infinite on both directions and starts all zero,
        // each cell can be only value 0 or 1, no other values are possible.
        tape = new BasicTape<BitElement>(BitElement.ZERO);
        playfield = new TwoIllPlayfield();
        pfView = new BasicPlayfieldView();
        tapeView = new BasicTapeView();
    }

    public Language getLanguage() {
        return language;
    }
    
    public TwoIllState clone() {
        TwoIllState c = new TwoIllState();
        c.playfield = (TwoIllPlayfield)this.playfield.clone();
        c.tape = this.tape.clone();
        c.halted = halted;
        c.needsInput = needsInput;
        return c;
    }

    public List<Error> step(World world) {
        ArrayList<Error> errors = new ArrayList<Error>();
        BasicCursor<CharacterElement> ip = playfield.getCursor(0);
        BasicHead<BitElement> h = tape.getHead(0);
        BitElement bit = h.read();
        char instruction = ip.get().getChar();

        if (instruction == '@') {
            // @ turns program pointer clockwise if value at pointer is 1, or counter-clockwise if is 0.
            ip.rotate(bit.getBoolean() ? 90 : -90);
        } else if (instruction == '#') {
            // # has different effects depending on direction of program pointer:
            if (ip.isHeaded(0, -1)) {
                // North = output bit at tape pointer, skip 2 program cells
                world.output(bit);
                ip.advance(2);
            } else if (ip.isHeaded(0, 1)) {
                // South = input bit, store at tape pointer, skip 2 program cells
                CharacterElement c = world.inputCharacter();
                if (c == null) {
                    needsInput = true;
                    return errors;
                }
                bit = bit.fromChar(c.getChar());
                h.write(bit);
                ip.advance(2);
            } else if (ip.isHeaded(1, 0)) {
                // East = toggle bit at tape pointer and then move tape pointer 1 space forwards, skip 2 program cells 
                h.write(bit.invert());
                h.move(1);
                ip.advance(2);
            } else if (ip.isHeaded(-1, 0)) {
                // West = move tape pointer 1 space backwards, skip 2 program cells
                h.move(-1);
                ip.advance(2);
            } else {
                // TODO: add error to errors
            }
        } else {
            // Anything else does nothing and can be used for comments. 
        }

        ip.advance();
        if (playfield.hasFallenOffEdge(ip)) {
            halted = true;
        }

        needsInput = false;
        return errors;
    }

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

    public Tape getTape(int index) {
        if (index == 0)
            return tape;
        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 tapeView;
    }

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

    public boolean hasHalted() {
        return halted;
    }

    public boolean needsInput() {
        return needsInput;
    }

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