Skip to content

Instantly share code, notes, and snippets.

@evanchooly
Forked from anonymous/dailyprogrammer290.java
Created November 3, 2016 16:06
Show Gist options
  • Save evanchooly/de7926d11672c2d38dfb198896872068 to your computer and use it in GitHub Desktop.
Save evanchooly/de7926d11672c2d38dfb198896872068 to your computer and use it in GitHub Desktop.
reddit dailyprogrammer 290 2016-11-02
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