Created
November 3, 2016 06:57
-
-
Save anonymous/3aa8110dad75970a3f0be6b4587b7ded to your computer and use it in GitHub Desktop.
reddit dailyprogrammer 290 2016-11-02
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import java.io.BufferedReader; | |
import java.io.FileReader; | |
import java.io.IOException; | |
import java.util.*; | |
import java.util.regex.Matcher; | |
import java.util.regex.Pattern; | |
/* https://www.reddit.com/r/dailyprogrammer/comments/5as91q/20161102_challenge_290_intermediate_blinking_leds/ */ | |
class Machine { | |
static String[] loadInstructions(String fileName) throws IOException { | |
List<String> data = new ArrayList<>(); | |
BufferedReader reader = new BufferedReader(new FileReader(fileName)); | |
String line = reader.readLine(); | |
while (line != null) { | |
line = line.trim(); | |
data.add(line); | |
line = reader.readLine(); | |
} | |
/* Perf optimisation LOL */ | |
String[] rv = new String[data.size()]; | |
data.toArray(rv); | |
return rv; | |
} | |
/* ========== OPCODES ========== */ | |
interface OpCode { | |
void opcode(Matcher m, int lineno) throws Exception; | |
} | |
private class OpCodeJump implements OpCode { | |
@Override | |
public void opcode(Matcher m, int lineno) throws Exception { | |
String label = m.group(1); | |
if (!labels.containsKey(label)) | |
throw new Exception(String.format("No such label %s line %d.", label, lineno)); | |
if (--regB != 0) | |
pc = labels.get(label); | |
} | |
} | |
private class OpCodeLabel implements OpCode { | |
@Override | |
public void opcode(Matcher m, int lineno) throws Exception { | |
String label = m.group(1); | |
if (labels.containsKey(label)) | |
throw new Exception(String.format("Duplicate label %s line %d.", label, lineno)); | |
labels.put(label, lineno); | |
} | |
} | |
private class OpCodeLoad implements OpCode { | |
@Override | |
public void opcode(Matcher m, int lineno) throws Exception { | |
int value = Integer.parseInt(m.group(2)); | |
if (m.group(1).equals("a")) | |
regA = value; | |
else if (m.group(1).equals("b")) | |
regB = value; | |
else throw new Exception("Bad register."); | |
} | |
} | |
private class OpCodeShift implements OpCode { | |
@Override | |
public void opcode(Matcher m, int lineno) { | |
if (m.group(0).equals("rlca")) { | |
leftshift(); | |
} else { | |
rightshift(); | |
} | |
} | |
void leftshift() { | |
boolean overflow = (regA & 1 << 7) == 1 << 7; | |
regA = regA << 1; | |
if (overflow) | |
regA = regA | 1; | |
} | |
void rightshift() { | |
boolean overflow = (regA & 1) == 1; | |
regA = regA >> 1; | |
if (overflow) | |
regA = regA | (1 << 7); | |
} | |
} | |
private class OpCodeOut implements OpCode { | |
@Override | |
public void opcode(Matcher m, int lineno) { | |
char buffer[] = "........".toCharArray(); | |
for (int i = 0; i < 8; ++i) { | |
if ((1 << i) == (regA & (1 << i))) { | |
buffer[7 - i] = '*'; | |
} | |
} | |
output.add(new String(buffer)); | |
if (!print_suppressed) | |
System.out.println(buffer); | |
} | |
} | |
/* ========== REGISTER MACHINE ========== */ | |
private Map<String, Integer> labels = new HashMap<>(); | |
private Map<Pattern, OpCode> opcodeDict = new HashMap<>(); | |
private String[] instructions = new String[0]; | |
private int regA = 0; | |
private boolean print_suppressed = false; | |
int pc = 0; // program counter (current instruction) | |
private int regB = 0; | |
List<String> output = new ArrayList<>(); | |
public void suppress_print() { | |
this.print_suppressed = true; | |
} | |
List<String> getOutput() { | |
return output; | |
} | |
Machine(String[] instructions) { | |
this.instructions = instructions; | |
opcodeDict.put(Pattern.compile("ld\\s+(a|b)\\s*,\\s*(\\d+)"), new OpCodeLoad()); | |
opcodeDict.put(Pattern.compile("out\\s*\\(0\\)\\s*,\\s*a"), new OpCodeOut()); | |
opcodeDict.put(Pattern.compile("rlca"), new OpCodeShift()); | |
opcodeDict.put(Pattern.compile("rrca"), new OpCodeShift()); | |
opcodeDict.put(Pattern.compile("(\\w+):"), new OpCodeLabel()); | |
opcodeDict.put(Pattern.compile("djnz\\s+(\\w+)"), new OpCodeJump()); | |
} | |
void run() throws Exception { | |
pc = 0; | |
while (pc < instructions.length) { | |
boolean matched = false; | |
String line = instructions[pc]; | |
for (Map.Entry pair : opcodeDict.entrySet()) { | |
Pattern p = (Pattern) pair.getKey(); | |
Matcher m = p.matcher(line); | |
if (m.matches()) { | |
matched = true; | |
OpCode op = (OpCode) pair.getValue(); | |
op.opcode(m, pc); | |
} | |
} | |
if (!matched && !"".equals(line)) | |
throw new Exception(String.format("Can't understand %s on line %d.", line, pc)); | |
++pc; | |
} | |
} | |
} | |
public class Woo { | |
public static void main(String[] args) throws Exception { | |
String[] test = new String[]{ | |
"ld a, 3", | |
"ld b, 2", | |
"out (0), a", | |
"rrca", | |
"out (0), a", | |
"foo:", | |
"rlca", | |
"out (0), a", | |
"djnz foo" | |
}; | |
String[] testTarget = new String[]{ | |
"......**", | |
"*......*", | |
"......**", | |
".....**." | |
}; | |
Machine testMachine = new Machine(test); | |
testMachine.suppress_print(); | |
testMachine.run(); | |
List<String> testResult = testMachine.getOutput(); | |
// Run JVM with -enableassertions for test. | |
assert testTarget.length == testResult.size(); | |
for (int i = 0; i < testTarget.length; ++i) | |
assert testTarget[i].equals(testResult.get(i)) : String.format("Line %d: %s", i, testResult); | |
String[] instructions = Machine.loadInstructions("input/wooinput2.txt"); | |
Machine machine = new Machine(instructions); | |
machine.run(); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment