Skip to content

Instantly share code, notes, and snippets.

@kurgm
Last active December 19, 2016 13:56
Show Gist options
  • Save kurgm/d79ff17a5aaf14189e4a8e3dce8a478c to your computer and use it in GitHub Desktop.
Save kurgm/d79ff17a5aaf14189e4a8e3dce8a478c to your computer and use it in GitHub Desktop.
Hexagonyを可視化

手順

Hexagonyのインタプリタを入手する

ruby interpreter.rb -D bin2dec.hxg > log.txt
python parseLog.py

mkdir sketch_161217a
cd sketch_161217a
mv ../sketch_161217a.pde ./
mkdir anim


Processing3でアニメーション生成(sketch_161217a.pde)

convert -layers=optimize-frame -delay=50 anim/*.png anim.gif

(ImageMagickが必要)

?{10\>
/1"'<|.
.>'2}{//
.........
.........:
%'*'+{=&{}/
.>''!@....
<........
>""*{=&\
../&''<
..>}=.
# -*- coding: utf-8 -*-
import json
import re
with open("log.txt", "r") as f:
dat = f.read().split("\n")
rTick = re.compile(r"^Tick (\d+):$")
rIPP = re.compile(r"^! 0: \((-?\d+),(-?\d+)\), [A-Za-z ]+$")
rDir = re.compile(r"^\d*New direction: ([A-Za-z ]+)$") # 出力した数値が先頭に来るかもしれない
rMem = re.compile(r"^Memory: #<Memory:0x[0-9a-f]+ @memory={([^}]*)}, @mp=\[(-?\d+), (-?\d+), :([NEWS]+)\], @cw=(false|true)>$")
rMem_m = re.compile(r"\[(-?\d+), (-?\d+), :([NEWS]+)\]=>(-?\d+)")
EAST = 0
SOUTHEAST = 1
SOUTHWEST = 2
WEST = 3
NORTHWEST = 4
NORTHEAST = 5
srcdirs = {
'East': EAST,
'South East': SOUTHEAST,
'South West': SOUTHWEST,
'West': WEST,
'North West': NORTHWEST,
'North East': NORTHEAST,
}
M_NE = -1
M_E = 0
M_SE = 1
memdirs = {
'NE': M_NE,
'E': M_E,
'SE': M_SE,
}
class TickData(object):
def __init__(self, tick):
self.tick = tick
self.ipp = None # instruction pointerのposition
self.dir = None # instruction pointerのdirection
self.mem = [] # memoryの状況
self.mp = None # memory pointerのposition
self.md = None # memory pointerのdirection (clockwiseかどうか)
datas = []
tick = -1
for l in dat:
l = l.strip()
if not l:
continue
m = rTick.match(l)
if m:
assert int(m.group(1)) == tick + 1
tick += 1
datas.append(TickData(tick))
m = rIPP.match(l)
if m:
datas[tick].ipp = (int(m.group(1)), int(m.group(2)))
m = rDir.match(l)
if m:
datas[tick].dir = srcdirs[m.group(1)]
m = rMem.match(l)
if m:
for m2 in rMem_m.finditer(m.group(1)):
datas[tick].mem.append([[int(m2.group(1)), int(m2.group(2)), memdirs[m2.group(3)]], int(m2.group(4))])
datas[tick].mp = (int(m.group(2)), int(m.group(3)), memdirs[m.group(4)])
datas[tick].md = m.group(5) == 'true'
class JSONTickDataEncoder(json.JSONEncoder):
def default(self, o):
return dict((key, getattr(o, key)) for key in [
"tick",
"ipp",
"dir",
"mem",
"mp",
"md"
]) if isinstance(o, TickData) else json.JSONEncoder.default(o)
with open("log.json", "w") as f:
json.dump(datas, f, cls=JSONTickDataEncoder, separators=(',', ':'))
// sketch_161217a/sketch_161217a.pde
String[] src;
JSONArray tickdatas;
PFont src_mono, mem_mono;
float src_fs = 18.0;
float src_cx = 160.0;
float src_cy = 180.0;
float src_intvl = 28.0;
float mem_fs = 15.0;
float mem_cx = 350.0;
float mem_cy = 240.0;
float mem_radius = 80.0;
float circle_radius = 40.0;
float memarrowhead = 10.0;
float memarrowheadangle = PI / 6;
color memcolor, curcolor, strokecolor;
float src_intvl_y, mem_radius_edge;
int startFrame = 5;
int endFrame;
int tick;
ArrayList<int[]> srcposhistory;
void setup() {
size(640, 360);
frameRate(2);
src_mono = createFont("Consolas", src_fs);
mem_mono = createFont("Consolas", mem_fs);
memcolor = color(0, 0, 120);
curcolor = color(255, 120, 0);
strokecolor = color(255, 240, 160);
src_intvl_y = src_intvl * sqrt(3.0) / 2.0;
mem_radius_edge = mem_radius * sqrt(3.0) / 2.0;
srcposhistory = new ArrayList<int[]>();
srcposhistory.add(new int[]{0, -5, 0});
src = loadStrings("../bin2dec.hxg");
tickdatas = loadJSONArray("../log.json");
endFrame = startFrame + tickdatas.size();
}
void draw() {
background(255);
textAlign(CENTER, CENTER);
tick = -1;
if (frameCount >= startFrame) {
tick = frameCount - startFrame;
}
if (frameCount >= endFrame) {
// 最後の状態でしばらく止めておく
tick = endFrame - startFrame - 1;
}
if (frameCount >= endFrame + startFrame) {
// 終了
noLoop();
}
JSONObject tickdata;
if (tick == -1) {
// まだ実行が始まっていない状態
tickdata = new JSONObject();
tickdata.setInt("tick", -1);
tickdata.setJSONArray("mem", new JSONArray());
JSONArray mp = new JSONArray();
mp.setInt(0, 0);
mp.setInt(1, 0);
mp.setInt(2, 0);
tickdata.setJSONArray("mp", mp);
tickdata.setBoolean("md", false);
} else {
tickdata = tickdatas.getJSONObject(tick);
}
drawMem(tickdata);
drawSrc(tickdata);
textAlign(LEFT);
if (tick >= 0) {
text("t = " + tick, 5, src_fs);
}
saveFrame("anim/######.png");
}
PVector getSrcPosition(int x, int y) {
return new PVector(
src_cx + src_intvl * (y * 0.5 + x),
src_cy + src_intvl_y * y
);
}
void drawSrc(JSONObject tickdata) {
textFont(src_mono);
noStroke();
fill(255);
rect(0, 0, width / 2, height);
int[] ipp = {};
int ipd = 0;
if (tick >= 0) {
ipp = tickdata.getJSONArray("ipp").getIntArray();
ipd = tickdata.getInt("dir", -1);
srcposhistory.add(new int[]{ipp[0], ipp[1], ipd});
}
float sw = 20.0;
noFill();
stroke(strokecolor);
for (int i = srcposhistory.size() - 1; i > 0 && sw > 0.0; i--) {
int[] stt = srcposhistory.get(i - 1);
int[] end = srcposhistory.get(i);
PVector sttv = getSrcPosition(stt[0], stt[1]);
PVector endv = getSrcPosition(end[0], end[1]);
strokeWeight(sw);
sw -= 1.0;
if (PVector.sub(endv, sttv).mag() > src_intvl + 1) {
PVector dv = new PVector(src_intvl * 0.5, 0);
dv.rotate(PI * stt[2] / 3);
PVector mv;
mv = PVector.add(sttv, dv);
line(sttv.x, sttv.y, mv.x, mv.y);
mv = PVector.sub(endv, dv);
line(endv.x, endv.y, mv.x, mv.y);
continue;
}
line(sttv.x, sttv.y, endv.x, endv.y);
}
strokeWeight(1);
for (int i = 0; i < src.length; i++) {
String line = src[i];
for (int j = 0; j < line.length(); j++) {
int x = j - 5, y = i - 5;
char cmd = line.charAt(j);
if (tick >= 0 && x == ipp[0] && y == ipp[1]) {
fill(curcolor);
} else if (cmd == '.') {
fill(160);
} else {
fill(0);
}
PVector vpos = getSrcPosition(x, y);
text(cmd, vpos.x, vpos.y);
}
}
}
PVector[] getMemEdgePositions(int x, int y, int dir) {
PVector center = new PVector(
mem_cx + mem_radius_edge * 2 * (y * 0.5 + x),
mem_cy + mem_radius * 1.5 * y
);
PVector dv1 = new PVector(mem_radius, 0);
PVector dv2 = new PVector(mem_radius, 0);
dv1.rotate(PI * (dir + 0.5) / 3);
dv2.rotate(PI * (dir - 0.5) / 3);
return new PVector[]{PVector.add(center, dv1), PVector.add(center, dv2)};
}
PVector getMemPosition(int x, int y, int dir) {
PVector center = new PVector(
mem_cx + mem_radius_edge * 2 * (y * 0.5 + x),
mem_cy + mem_radius * 1.5 * y
);
PVector dv = new PVector(mem_radius_edge, 0);
dv.rotate(PI * dir / 3);
return center.add(dv);
}
void drawMemCell(int x, int y, int dir, String data) {
color fillcolor, textcolor;
if (tick >= 164 && x == 1 && y == -1 && dir == -1) {
fillcolor = color(0, 0, 140);
textcolor = 255;
} else {
fillcolor = 250;
textcolor = memcolor;
}
PVector memv = getMemPosition(x, y, dir);
fill(fillcolor);
stroke(0);
ellipse(memv.x, memv.y, circle_radius, circle_radius);
fill(textcolor);
noStroke();
text(data, memv.x, memv.y);
}
void drawMem(JSONObject tickdata) {
JSONArray mp = tickdata.getJSONArray("mp");
int mpx = mp.getInt(0), mpy = mp.getInt(1), mpd = mp.getInt(2);
boolean iscw = tickdata.getBoolean("md");
textFont(mem_mono);
for (int y = -4; y <= 4; y++) {
for (int x = -4; x <= 4; x++) {
for (int dir = -1; dir <= 1; dir++) {
PVector[] eps = getMemEdgePositions(x, y, dir);
noFill();
if (x == mpx && y == mpy && dir == mpd) {
stroke(curcolor);
strokeWeight(4);
PVector arrowv, arrowend;
if (iscw) {
arrowv = PVector.sub(eps[0], eps[1]);
arrowend = eps[0];
} else {
arrowv = PVector.sub(eps[1], eps[0]);
arrowend = eps[1];
}
PVector v1 = arrowv.copy();
v1.setMag(memarrowhead);
PVector v2 = v1.copy();
v1.rotate(PI - memarrowheadangle);
v2.rotate(PI + memarrowheadangle);
v1.add(arrowend);
v2.add(arrowend);
line(arrowend.x, arrowend.y, v1.x, v1.y);
line(arrowend.x, arrowend.y, v2.x, v2.y);
} else {
stroke(0);
strokeWeight(1);
}
line(eps[0].x, eps[0].y, eps[1].x, eps[1].y);
strokeWeight(1);
drawMemCell(x, y, dir, "0");
}
}
}
JSONArray mem = tickdata.getJSONArray("mem");
int memsize = mem.size();
for (int i = 0; i < memsize; i++) {
JSONArray memcell = mem.getJSONArray(i);
JSONArray memcellpos = memcell.getJSONArray(0);
int memcelldata = memcell.getInt(1);
int memx = memcellpos.getInt(0);
int memy = memcellpos.getInt(1);
int memd = memcellpos.getInt(2);
PVector memv = getMemPosition(memx, memy, memd);
fill(255);
noStroke();
ellipse(memv.x, memv.y, circle_radius + 1, circle_radius + 1);
drawMemCell(memx, memy, memd, String.valueOf(memcelldata));
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment