import java.io.BufferedReader;
import java.io.StringReader;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Optional;
import java.util.function.Consumer;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
class Leds{
public final static String INPUT
= " ld a,14\n" +
" out (0),a\n" +
" ld a,12\n" +
" out (0),a\n" +
" ld a,8\n" +
" out (0),a\n" +
"\n" +
" out (0),a\n" +
" ld a,12\n" +
" out (0),a\n" +
" ld a,14\n" +
" out (0),a\n" +
" \n" +
" ld b,3\n" +
"\n" +
"triple:\n" +
" ld a,126\n" +
" out (0),a\n" +
" ld a,60\n" +
" out (0),a\n" +
" ld a,24\n" +
" out (0),a\n" +
" djnz triple\n" +
" \n" +
" ld a,1\n" +
" ld b,9\n" +
"\n" +
"loop:\n" +
" out (0),a\n" +
" rlca\n" +
" djnz loop\n" +
" \n" +
" ld a,2\n" +
" ld b,9\n" +
"\n" +
"loop2:\n" +
" out (0),a\n" +
" rrca\n" +
" djnz loop2";
public enum ACTION {
LD(Pattern.compile("^\\s*ld ([a-z]),(\\d*)"),
input
-> REG.
put(input.
get(0),
Byte.
valueOf(input.
get(1)))),
OUT(Pattern.compile("^\\s*out \\(0\\),([a-z])"),
input -> {
LEDS = REG.get(input.get(0));
outputLEDs();
}),
RLCA(Pattern.compile("^\\s*rlca"),
input
-> REG.
put("a", toByte
(Integer.
rotateLeft(REG.
get("a"),
1)))),
RRCA(Pattern.compile("^\\s*rrca"),
input -> {
Byte a
= (byte) (REG.
get("a")); byte rolled = (byte) ((((a & 0xff) >> 1) + ((a & 0x01) == 1 ? 1 << 7 : 0)));
REG.put("a", rolled);
}),
LABEL(Pattern.compile("^\\s*(.*):"),
input -> { }),
DJNZ(Pattern.compile("^\\s*djnz (.*)"),
input -> {
REG.put("b", (byte) (b - 1));
if (b > 1) {
IntStream.range(0, PROGRAM.size())
.filter(index -> (PROGRAM.get(index).action == LABEL && PROGRAM.get(index).params.get(0).equals(input.get(0))))
.findFirst()
.ifPresent(index -> PC = index);
}
});
public Pattern pattern;
public Consumer<List<String>> consumer;
private ACTION(Pattern pattern, Consumer<List<String>> consumer) {
this.pattern = pattern;
this.consumer = consumer;
}
}
public static byte toByte(int num) {
int tmp = num & 0xff;
return (byte) ((tmp & 0x80) == 0 ? tmp : tmp - 256);
}
public static final HashMap
<String, Byte
> REG
= new HashMap
<>(); public static Byte LEDS
= 0x00
; public static final List<ParsedAction> PROGRAM = new LinkedList<>();
public static int PC = 0;
public static Optional
<ParsedAction
> parseAction
(String line
) { return Arrays.
stream(ACTION.
values()) .filter(action -> action.pattern.matcher(line).matches())
.map(action -> {
Matcher m = action.pattern.matcher(line);
List<String> params = new ArrayList<>();
m.find();
return new ParsedAction(action, IntStream.range(1, m.groupCount()+1)
.mapToObj(index -> m.group(index))
.collect(Collectors.toList())
);
})
.findFirst();
}
public static void outputLEDs() {
for (int i = 7; i >= 0; i--) {
System.
out.
print((LEDS
>> i
& 0x01
) == 1 ? "*" : "."); }
}
public static void main
(String[] args
) {
.sequential()
.map(Leds::parseAction)
.filter(Optional::isPresent)
.map(Optional::get)
.forEachOrdered(action -> PROGRAM.add(action));
for (PC = 0; PC < PROGRAM.size(); PC++) {
ParsedAction action = PROGRAM.get(PC);
action.perform();
}
}
public static class ParsedAction {
public ACTION action;
public List<String> params;
public ParsedAction(ACTION action, List<String> params) {
this.action = action;
this.params = params;
}
public void perform() {
action.consumer.accept(params);
}
}
}
aW1wb3J0IGphdmEuaW8uQnVmZmVyZWRSZWFkZXI7CmltcG9ydCBqYXZhLmlvLlN0cmluZ1JlYWRlcjsKaW1wb3J0IGphdmEudXRpbC5BcnJheUxpc3Q7CmltcG9ydCBqYXZhLnV0aWwuQXJyYXlzOwppbXBvcnQgamF2YS51dGlsLkhhc2hNYXA7CmltcG9ydCBqYXZhLnV0aWwuTGlua2VkTGlzdDsKaW1wb3J0IGphdmEudXRpbC5MaXN0OwppbXBvcnQgamF2YS51dGlsLk9wdGlvbmFsOwppbXBvcnQgamF2YS51dGlsLmZ1bmN0aW9uLkNvbnN1bWVyOwppbXBvcnQgamF2YS51dGlsLnJlZ2V4Lk1hdGNoZXI7CmltcG9ydCBqYXZhLnV0aWwucmVnZXguUGF0dGVybjsKaW1wb3J0IGphdmEudXRpbC5zdHJlYW0uQ29sbGVjdG9yczsKaW1wb3J0IGphdmEudXRpbC5zdHJlYW0uSW50U3RyZWFtOwoKY2xhc3MgTGVkc3sKCiAgICBwdWJsaWMgZmluYWwgc3RhdGljIFN0cmluZyBJTlBVVAogICAgICAgICAgICA9ICIgIGxkIGEsMTRcbiIgKwoiICBvdXQgKDApLGFcbiIgKwoiICBsZCBhLDEyXG4iICsKIiAgb3V0ICgwKSxhXG4iICsKIiAgbGQgYSw4XG4iICsKIiAgb3V0ICgwKSxhXG4iICsKIlxuIiArCiIgIG91dCAoMCksYVxuIiArCiIgIGxkIGEsMTJcbiIgKwoiICBvdXQgKDApLGFcbiIgKwoiICBsZCBhLDE0XG4iICsKIiAgb3V0ICgwKSxhXG4iICsKIiAgXG4iICsKIiAgICBsZCBiLDNcbiIgKwoiXG4iICsKInRyaXBsZTpcbiIgKwoiICBsZCBhLDEyNlxuIiArCiIgIG91dCAoMCksYVxuIiArCiIgIGxkIGEsNjBcbiIgKwoiICBvdXQgKDApLGFcbiIgKwoiICBsZCBhLDI0XG4iICsKIiAgb3V0ICgwKSxhXG4iICsKIiAgZGpueiB0cmlwbGVcbiIgKwoiICBcbiIgKwoiICBsZCBhLDFcbiIgKwoiICBsZCBiLDlcbiIgKwoiXG4iICsKImxvb3A6XG4iICsKIiAgb3V0ICgwKSxhXG4iICsKIiAgcmxjYVxuIiArCiIgIGRqbnogbG9vcFxuIiArCiIgIFxuIiArCiIgIGxkIGEsMlxuIiArCiIgIGxkIGIsOVxuIiArCiJcbiIgKwoibG9vcDI6XG4iICsKIiAgb3V0ICgwKSxhXG4iICsKIiAgcnJjYVxuIiArCiIgIGRqbnogbG9vcDIiOwoKICAgIHB1YmxpYyBlbnVtIEFDVElPTiB7CiAgICAgICAgTEQoUGF0dGVybi5jb21waWxlKCJeXFxzKmxkIChbYS16XSksKFxcZCopIiksCiAgICAgICAgICAgICAgICBpbnB1dCAtPiBSRUcucHV0KGlucHV0LmdldCgwKSwgQnl0ZS52YWx1ZU9mKGlucHV0LmdldCgxKSkpKSwKICAgICAgICBPVVQoUGF0dGVybi5jb21waWxlKCJeXFxzKm91dCBcXCgwXFwpLChbYS16XSkiKSwKICAgICAgICAgICAgICAgIGlucHV0IC0+IHsKICAgICAgICAgICAgICAgICAgICBMRURTID0gUkVHLmdldChpbnB1dC5nZXQoMCkpOwogICAgICAgICAgICAgICAgICAgIG91dHB1dExFRHMoKTsKICAgICAgICAgICAgICAgIH0pLAogICAgICAgIFJMQ0EoUGF0dGVybi5jb21waWxlKCJeXFxzKnJsY2EiKSwKICAgICAgICAgICAgICAgIGlucHV0IC0+IFJFRy5wdXQoImEiLCB0b0J5dGUoSW50ZWdlci5yb3RhdGVMZWZ0KFJFRy5nZXQoImEiKSwgMSkpKSksCiAgICAgICAgUlJDQShQYXR0ZXJuLmNvbXBpbGUoIl5cXHMqcnJjYSIpLAogICAgICAgICAgICAgICAgaW5wdXQgLT4gewogICAgICAgICAgICAgICAgICAgIEJ5dGUgYSA9IChieXRlKSAoUkVHLmdldCgiYSIpKTsKICAgICAgICAgICAgICAgICAgICBieXRlIHJvbGxlZCA9IChieXRlKSAoKCgoYSAmIDB4ZmYpID4+IDEpICsgKChhICYgMHgwMSkgPT0gMSA/IDEgPDwgNyA6IDApKSk7CiAgICAgICAgICAgICAgICAgICAgUkVHLnB1dCgiYSIsIHJvbGxlZCk7CiAgICAgICAgICAgICAgICB9KSwKICAgICAgICBMQUJFTChQYXR0ZXJuLmNvbXBpbGUoIl5cXHMqKC4qKToiKSwKICAgICAgICAgICAgICAgIGlucHV0IC0+IHsgfSksCiAgICAgICAgREpOWihQYXR0ZXJuLmNvbXBpbGUoIl5cXHMqZGpueiAoLiopIiksCiAgICAgICAgICAgICAgICBpbnB1dCAtPiB7CiAgICAgICAgICAgICAgICAgICAgQnl0ZSBiID0gUkVHLmdldCgiYiIpOwogICAgICAgICAgICAgICAgICAgIFJFRy5wdXQoImIiLCAoYnl0ZSkgKGIgLSAxKSk7CiAgICAgICAgICAgICAgICAgICAgaWYgKGIgPiAxKSB7CiAgICAgICAgICAgICAgICAgICAgICAgIEludFN0cmVhbS5yYW5nZSgwLCBQUk9HUkFNLnNpemUoKSkKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAuZmlsdGVyKGluZGV4IC0+IChQUk9HUkFNLmdldChpbmRleCkuYWN0aW9uID09IExBQkVMICYmIFBST0dSQU0uZ2V0KGluZGV4KS5wYXJhbXMuZ2V0KDApLmVxdWFscyhpbnB1dC5nZXQoMCkpKSkKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAuZmluZEZpcnN0KCkKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAuaWZQcmVzZW50KGluZGV4IC0+IFBDID0gaW5kZXgpOwogICAgICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgIH0pOwoKICAgICAgICBwdWJsaWMgUGF0dGVybiBwYXR0ZXJuOwogICAgICAgIHB1YmxpYyBDb25zdW1lcjxMaXN0PFN0cmluZz4+IGNvbnN1bWVyOwoKICAgICAgICBwcml2YXRlIEFDVElPTihQYXR0ZXJuIHBhdHRlcm4sIENvbnN1bWVyPExpc3Q8U3RyaW5nPj4gY29uc3VtZXIpIHsKICAgICAgICAgICAgdGhpcy5wYXR0ZXJuID0gcGF0dGVybjsKICAgICAgICAgICAgdGhpcy5jb25zdW1lciA9IGNvbnN1bWVyOwogICAgICAgIH0KICAgIH0KCiAgICBwdWJsaWMgc3RhdGljIGJ5dGUgdG9CeXRlKGludCBudW0pIHsKICAgICAgICBpbnQgdG1wID0gbnVtICYgMHhmZjsKICAgICAgICByZXR1cm4gKGJ5dGUpICgodG1wICYgMHg4MCkgPT0gMCA/IHRtcCA6IHRtcCAtIDI1Nik7CiAgICB9CgogICAgcHVibGljIHN0YXRpYyBmaW5hbCBIYXNoTWFwPFN0cmluZywgQnl0ZT4gUkVHID0gbmV3IEhhc2hNYXA8PigpOwogICAgcHVibGljIHN0YXRpYyBCeXRlIExFRFMgPSAweDAwOwogICAgcHVibGljIHN0YXRpYyBmaW5hbCBMaXN0PFBhcnNlZEFjdGlvbj4gUFJPR1JBTSA9IG5ldyBMaW5rZWRMaXN0PD4oKTsKICAgIHB1YmxpYyBzdGF0aWMgaW50IFBDID0gMDsKCiAgICBwdWJsaWMgc3RhdGljIE9wdGlvbmFsPFBhcnNlZEFjdGlvbj4gcGFyc2VBY3Rpb24oU3RyaW5nIGxpbmUpIHsKICAgICAgICByZXR1cm4gQXJyYXlzLnN0cmVhbShBQ1RJT04udmFsdWVzKCkpCiAgICAgICAgICAgICAgICAuZmlsdGVyKGFjdGlvbiAtPiBhY3Rpb24ucGF0dGVybi5tYXRjaGVyKGxpbmUpLm1hdGNoZXMoKSkKICAgICAgICAgICAgICAgIC5tYXAoYWN0aW9uIC0+IHsKICAgICAgICAgICAgICAgICAgICBNYXRjaGVyIG0gPSBhY3Rpb24ucGF0dGVybi5tYXRjaGVyKGxpbmUpOwogICAgICAgICAgICAgICAgICAgIExpc3Q8U3RyaW5nPiBwYXJhbXMgPSBuZXcgQXJyYXlMaXN0PD4oKTsKICAgICAgICAgICAgICAgICAgICBtLmZpbmQoKTsKICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICByZXR1cm4gbmV3IFBhcnNlZEFjdGlvbihhY3Rpb24sIEludFN0cmVhbS5yYW5nZSgxLCBtLmdyb3VwQ291bnQoKSsxKQogICAgICAgICAgICAgICAgICAgICAgICAgICAgLm1hcFRvT2JqKGluZGV4IC0+IG0uZ3JvdXAoaW5kZXgpKQogICAgICAgICAgICAgICAgICAgICAgICAgICAgLmNvbGxlY3QoQ29sbGVjdG9ycy50b0xpc3QoKSkKICAgICAgICAgICAgICAgICAgICApOwogICAgICAgICAgICAgICAgfSkKICAgICAgICAgICAgICAgIC5maW5kRmlyc3QoKTsKICAgIH0KCiAgICBwdWJsaWMgc3RhdGljIHZvaWQgb3V0cHV0TEVEcygpIHsKICAgICAgICBmb3IgKGludCBpID0gNzsgaSA+PSAwOyBpLS0pIHsKICAgICAgICAgICAgU3lzdGVtLm91dC5wcmludCgoTEVEUyA+PiBpICYgMHgwMSkgPT0gMSA/ICIqIiA6ICIuIik7CiAgICAgICAgfQogICAgICAgIFN5c3RlbS5vdXQucHJpbnRsbigpOwogICAgfQoKICAgIHB1YmxpYyBzdGF0aWMgdm9pZCBtYWluKFN0cmluZ1tdIGFyZ3MpIHsKCiAgICAgICAgbmV3IEJ1ZmZlcmVkUmVhZGVyKG5ldyBTdHJpbmdSZWFkZXIoSU5QVVQpKS5saW5lcygpCiAgICAgICAgICAgICAgICAuc2VxdWVudGlhbCgpCiAgICAgICAgICAgICAgICAubWFwKExlZHM6OnBhcnNlQWN0aW9uKQogICAgICAgICAgICAgICAgLmZpbHRlcihPcHRpb25hbDo6aXNQcmVzZW50KQogICAgICAgICAgICAgICAgLm1hcChPcHRpb25hbDo6Z2V0KQogICAgICAgICAgICAgICAgLmZvckVhY2hPcmRlcmVkKGFjdGlvbiAtPiBQUk9HUkFNLmFkZChhY3Rpb24pKTsKCiAgICAgICAgZm9yIChQQyA9IDA7IFBDIDwgUFJPR1JBTS5zaXplKCk7IFBDKyspIHsKICAgICAgICAgICAgUGFyc2VkQWN0aW9uIGFjdGlvbiA9IFBST0dSQU0uZ2V0KFBDKTsKICAgICAgICAgICAgYWN0aW9uLnBlcmZvcm0oKTsKICAgICAgICB9CiAgICB9CgogICAgcHVibGljIHN0YXRpYyBjbGFzcyBQYXJzZWRBY3Rpb24gewoKICAgICAgICBwdWJsaWMgQUNUSU9OIGFjdGlvbjsKICAgICAgICBwdWJsaWMgTGlzdDxTdHJpbmc+IHBhcmFtczsKCiAgICAgICAgcHVibGljIFBhcnNlZEFjdGlvbihBQ1RJT04gYWN0aW9uLCBMaXN0PFN0cmluZz4gcGFyYW1zKSB7CiAgICAgICAgICAgIHRoaXMuYWN0aW9uID0gYWN0aW9uOwogICAgICAgICAgICB0aGlzLnBhcmFtcyA9IHBhcmFtczsKICAgICAgICB9CgogICAgICAgIHB1YmxpYyB2b2lkIHBlcmZvcm0oKSB7CiAgICAgICAgICAgIGFjdGlvbi5jb25zdW1lci5hY2NlcHQocGFyYW1zKTsKICAgICAgICB9CiAgICB9Cn0K