Commits

Anonymous committed 7379209

Add yoob implementation of Wunnel.

  • Participants
  • Parent commits 4e11aa5

Comments (0)

Files changed (4)

+# Makefile for Wunnel (yoob version).
+
+JAVAC?=javac
+JAVA?=java
+PATHSEP?=:
+
+JFLAGS?=-Xlint:deprecation -Xlint:unchecked
+CDIR=bin/tc/catseye/wunnel
+CLASSES=$(CDIR)/WunnelState.class
+
+YOOBDIR?=../yoob
+CLASSPATH?=bin$(PATHSEP)$(YOOBDIR)/bin
+
+all: $(CLASSES)
+
+$(CDIR)/WunnelState.class: src/WunnelState.java
+	$(JAVAC) $(JFLAGS) -cp "$(CLASSPATH)" -d bin src/WunnelState.java
+
+clean:
+	rm -rf $(CDIR)/*.class
+
+test: $(CLASSES)
+	$(JAVA) -cp "$(CLASSPATH)" tc.catseye.yoob.GUI -c "tc.catseye.wunnel.WunnelState/Wunnel" -s Wunnel

File README.markdown

 This is the reference distribution of Wunnel, an esoteric programming
 language.
 
-However, at present, it only contains the specification of the language,
-copied from [Wunnel article][] on the esolangs.org wiki.  (Which is in the
-public domain and was mostly written by me anyway.)
+At present, it contains:
+
+*   the specification of the language, copied from [Wunnel article][] on
+    the esolangs.org wiki.  (Which is in the public domain and was mostly
+    written by me anyway.)
+*   the [yoob][] implementation of Wunnel.
 
 [Wunnel article]: http://esolangs.org/wiki/Wunnel
+[yoob]: http://catseye.tc/node/yoob.html
+

File bin/README.txt

+This is where compiled Java classfiles will go.

File src/WunnelState.java

+/*
+ * A WunnelState implements the semantics of Wunnel.
+ * The source code in this file has been placed into the public domain.
+ */
+package tc.catseye.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) {
+    }
+}