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

Tree @master (Download .tar.gz)

WunnelState.java @masterraw · history · blame

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

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;

import java.awt.Graphics;
import java.awt.Color;


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

    public int numPlayfields() {
        return 2;
    }

    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("bitwise cat");
        return names;
    }

    public WunnelState loadExampleProgram(int index) {
        String[][] program = {
          // From http://www.esolangs.org/wiki/Wunnel
          // By Chris Pressey.  From the esowiki, thus in the public domain.
          {
            "          o   ooo  o",
            "",
            "",
            "o",
            "o",
            "o",
            "o         o",
            "o         o",
            "o         o",
            "o         o",
            "o",
            "o        o     o",
            "o         o",
            "o",
            "o        o",
            "o              o",
            "o        o     o",
            "o              o",
            "",
            "         o",
            "o oooooooo     o",
            "         o",
            "         o",
            "         o",
            "",
            "         o    oooo o",
          }
        };
        WunnelState s = new WunnelState();
        s.playfield.load(program[index]);
        return s;
    }

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

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

    public static final String positiveGenus = "0689@%&QROPADBqeopadb";
  
    private static final String[][] properties = {
        {"Author", "Chris Pressey"},
        {"Implementer", "Chris Pressey"},
        {"Implementation notes",
         "This implementation assumes the user is viewing the program in a font in which " +
         "all of, and only, the following characters have a character genus greater than " +
         "zero:\n  " + positiveGenus + "\n" +
         "It also presents the operation table as an immutable, secondary Yoob playfield " +
         "for better visualization."}
    };

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

class Operation implements Element {
    public static Operation ROT = new Operation("ROT");
    public static Operation NOP = new Operation("NOP");
    public static Operation SHU = new Operation("SHU");
    public static Operation RIG = new Operation("RIG");
    public static Operation LEF = new Operation("LEF");
    public static Operation INP = new Operation("INP");
    public static Operation OUT = new Operation("OUT");
    public static Operation NEG = new Operation("NEG");
    public static Operation PLU = new Operation("PLU");
    public static Operation BLA = new Operation("BLA");
    public static Operation END = new Operation("END");
    public static Operation[][] table = {
        {ROT, ROT, SHU, NEG, PLU, NOP},
        {LEF, SHU, RIG, BLA, NOP, BLA},
        {RIG, INP, LEF, NOP, PLU, NEG},
        {NOP, OUT, SHU, SHU, LEF, END},
        {SHU, END, NOP, RIG, SHU, END},
        {ROT, NOP, ROT, ROT, ROT, ROT},
    };

    private String s;
    public Operation(String s) { this.s = s; }
    public String getName() { return s; }
    public Operation fromChar(char c) { return this; }
    public boolean equals(Element q) {
        if (q instanceof Operation) { return this == q; }
        return false;
    }
}

class OperationTable implements Playfield<Operation> {
    private static IntegerElement FIVE = new IntegerElement(5);
    private WrapCursor<Operation> cursor;

    public OperationTable() {
        cursor = new WrapCursor<Operation>(this);
        cursor.setDelta(0, 1);
    }

    public void set(IntegerElement x, IntegerElement y, Operation e) {
        // immutable! nothing happens!
    }

    public Operation get(IntegerElement x, IntegerElement y) {
        int xi = x.intValue() % 6;
        int yi = y.intValue() % 6;
        return Operation.table[yi][xi];
    }

    public Operation getDefault() {
        return Operation.NOP; // why not, eh?
    }

    public OperationTable clone() {
        OperationTable o = new OperationTable();
        o.cursor = cursor.clone();
        // immutable, so no need to update the pf that the cursor sees
        return o;
    }

    public IntegerElement getMinX() {
        return IntegerElement.ZERO;
    }

    public IntegerElement getMaxX() {
        return FIVE;
    }

    public IntegerElement getMinY() {
        return IntegerElement.ZERO;
    }

    public IntegerElement getMaxY() {
        return FIVE;
    }

    public int numCursors() {
        return 1;
    }

    public BasicCursor<Operation> getCursor(int index) {
        if (index == 0) return cursor;
        return null;
    }
}

class OpTableView extends BasicPlayfieldView {
    public int getPreferredCellWidth() {
        return 3;
    }

    public boolean getSquareOff() {
        return false;
    }
}

public class WunnelState implements State {
    static private final IntegerElement MINUS_ONE = new IntegerElement(-1);
    protected BasicTape<IntegerElement> tape; // XXX for now
    protected CommonPlayfield playfield;
    protected OperationTable opTable;
    protected BasicPlayfieldView pfView;
    protected OpTableView opView;
    protected BasicTapeView tapeView;
    protected boolean halted = false;
    protected boolean needsInput = false;
    private static final Wunnel language = new Wunnel();
  
    public WunnelState() {
        // The tape cells can actually only hold -1, 0, 1
        tape = new BasicTape<IntegerElement>(new IntegerElement(0));

        /*
         * The instruction pointer starts at the upper left corner of the source file moving down.
         */
        playfield = new CommonPlayfield();
        playfield.getCursor(0).setDelta(0, 1); // initially going down
        opTable = new OperationTable();
        pfView = new BasicPlayfieldView();
        opView = new OpTableView();
        tapeView = new BasicTapeView();
    }

    public Language getLanguage() {
	return language;
    }

    public WunnelState clone() {
        WunnelState c = new WunnelState();
        c.playfield = this.playfield.clone();
        c.opTable = this.opTable.clone();
        c.tape = this.tape.clone();
        c.halted = halted;
        c.needsInput = needsInput;
        return c;
    }

    public boolean genusMoreThanZero(char c) { // not all of them
        for (int i = 0; i < language.positiveGenus.length(); i++) {
            if (language.positiveGenus.charAt(i) == c)
                return true;
        }
        return false;
    }

    public List<Error> step(World world) {
        ArrayList<Error> errors = new ArrayList<Error>();
        BasicCursor<CharacterElement> ip = playfield.getCursor(0);
        BasicCursor<Operation> opp = opTable.getCursor(0);
        BasicHead<IntegerElement> h = tape.getHead(0);
        char instruction = ip.get().getChar();
        Operation k = opp.get();

        if (genusMoreThanZero(instruction)) {
            if (k == Operation.END) {
                halted = true;
                return errors;
            } else if (k == Operation.NOP) {
            } else if (k == Operation.SHU) {
                if (ip.isHeaded(-1, 0)) {
                    ip.setY(ip.getY().add(h.read().negate()));
                } else if (ip.isHeaded(1, 0)) {
                    ip.setY(ip.getY().add(h.read()));
                } else if (ip.isHeaded(0, -1)) {
                    ip.setX(ip.getX().add(h.read()));
                } else if (ip.isHeaded(0, 1)) {
                    ip.setX(ip.getX().add(h.read().negate()));
                }
            } else if (k == Operation.ROT) {
                ip.rotate(-90);
                opp.rotate(-90);
            } else if (k == Operation.LEF) {
                h.move(-1);
            } else if (k == Operation.RIG) {
                h.move(1);
            } else if (k == Operation.NEG) {
                h.write(MINUS_ONE);
            } else if (k == Operation.BLA) {
                h.write(IntegerElement.ZERO);
            } else if (k == Operation.PLU) {
                h.write(IntegerElement.ONE);
            } else if (k == Operation.OUT) {
                IntegerElement i = h.read();
                if (i.isZero()) {
                    world.output(new CharacterElement('0'));
                } else {
                    world.output(new CharacterElement('1'));
                }
            } else if (k == Operation.INP) {
                CharacterElement c = world.inputCharacter();
                if (c == null) {
                    needsInput = true;
                    return errors;
                }
                if (c.getChar() == '1') {
                    h.write(IntegerElement.ONE);
                } else {
                    h.write(IntegerElement.ZERO);
                }
            }
        } else {
            opp.advance();
        }

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

        needsInput = false;
        return errors;
    }

    public Playfield getPlayfield(int index) {
        if (index == 0)
            return playfield;
        if (index == 1)
            return opTable;
        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) {
        if (index == 0)
            return pfView;
        if (index == 1)
            return opView;
        return null;
    }

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

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

    public boolean hasHalted() {
        return halted;
    }

    public boolean needsInput() {
        return needsInput;
    }

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

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