sclass OnePath { new ByteBuffer steps; static final Pt[] directions = { pt(0, 0), pt(-1, -1), pt(0, -1), pt(1, -1), pt(1, 0), pt(1, 1), pt(0, 1), pt(-1, 1), pt(-1, 0) }; *() {} *(S path) { int n = l(path); steps.allocate(n); for i to n: steps.add(parseDigit(path, i)); } *(Iterable points) { var it = iterator(points); if (empty(it)) ret; Pt p = it.next(); while (it.hasNext()) { Pt p2 = it.next(); steps.add(ptToDigit(ptMinus(p2, p))); p = p2; } } int size aka length() { ret steps.size(); } toString { ret singleDigitBytesToString(steps); } // includes first point, so returns length()+1 points in total ItIt pointIterator(Pt startPt default origin()) { ret new ItIt { int i = 0, n = length(); Pt p = startPt; public bool hasNext() { ret i <= n; } public Pt next() { var p = this.p; if (i < n) this.p = translatePt(this.p, getStepAsPt(i)); ++i; ret p; } }; } Pt getStepAsPt(int i) { ret directions[steps.get(i)]; } static int ptToDigit(Pt p) { ret p.y < 0 ? p.x < 0 ? 1 : p.x == 0 ? 2 : 3 : p.y == 0 ? p.x < 0 ? 8 : p.x == 0 ? 0 : 4 : p.x < 0 ? 7 : p.x == 0 ? 6 : 5; } Pt drift() { ret last(pointIterator()); } }