### Rotating wired cube

Random walks on cube (with rotations)

```const seed = 1100; // min=1, max=2000, step=1
const N = 250; // min=10, max=1000, step=1
const min_step = 0.005;
const phi_x = -35.0; // min=-180.0, max=180.0, step=0.1
const phi_y = 35.0; // min=-180.0, max=180.0, step=0.1
const phi_z = 25.0; // min=-180.0, max=180.0, step=0.1

Canvas.setpenopacity(-1);

const dash = 2.0;

const t = new Turtle();

const verts = [[-1, -1, -1], [-1, -1, +1], [-1, +1, +1], [-1, +1, -1],
[+1, -1, -1], [+1, -1, +1], [+1, +1, +1], [+1, +1, -1]];

const edges = [[0, 1], [1, 2], [2, 3], [3, 0],
[4, 5], [5, 6], [6, 7], [7, 4],
[0, 4], [1, 5], [2, 6], [3, 7]];

const faces = [[3, 0, 1, 2], [4, 7, 6, 5], [1, 0, 4, 5], [2, 1, 5, 6], [3, 2, 6, 7], [0, 3, 7, 4]];

let cur_rand = seed;
function rand() { cur_rand = (cur_rand * 48271) % (2**31 - 1); return cur_rand; }
function rand_float() { return rand() / (2**31 - 1); }
function rand_bool() { return (rand() % 2 == 0); }

function deg2rad(x) { return x / 180.0 * Math.PI}

function plus(v1, v2) { return [v1[0] + v2[0], v1[1] + v2[1], v1[2] + v2[2]]; }
function minus(v1, v2) { return [v1[0] - v2[0], v1[1] - v2[1], v1[2] - v2[2]]; }
function mul(v, scale) { return [v[0] * scale, v[1] * scale, v[2] * scale] }
function len(v) { return Math.sqrt(v[0]**2 + v[1]**2); }
function cross(v1, v2) { return [v1[1] * v2[2] - v1[2] * v2[1], v1[2] * v2[0] - v1[0] * v2[2], v1[0] * v2[1] - v1[1] * v2[0]]; }
function rotate(v, phi) { return [v[0] * Math.cos(phi) + v[1] * Math.sin(phi), -v[0] * Math.sin(phi) + v[1] * Math.cos(phi)]; }

function draw_cube(dx, dy, dz, scale, phi_x, phi_y, phi_z) {
let v = [];

for (let i = 0; i < verts.length; i++) {
let vi = verts[i];
let [x, y, z] = vi;

[x, y, z] = mul([x, y, z], scale);

[y, z] = rotate([y, z], phi_x);
[x, z] = rotate([x, z], phi_y);
[x, y] = rotate([x, y], phi_z);

[x, y, z] = plus([x, y, z], [dx, dy, dz]);

v[i] = [x, y, z];
}

let f_invisible = [];

let v_invisible = [];
for (let i = 0; i < verts.length; i++) {
v_invisible[i] = true;
}

for (let i = 0; i < faces.length; i++) {
let f = faces[i];
let v1 = v[f[0]], v2 = v[f[1]], v3 = v[f[2]], v4 = v[f[3]];

let v12 = minus(v2, v1), v13 = minus(v3, v1);
let n = cross(v12, v13);

f_invisible[i] = (n[2] < 0);

for (let j = 0; j < f.length; j++) {
v_invisible[f[j]] &&= f_invisible[i];
}
}

let e_invisible = [];
for (let i = 0; i < edges.length; i++) {
let e = edges[i];

e_invisible[i] = v_invisible[e[0]] || v_invisible[e[1]]
}

for (let i = 0; i < edges.length; i++) {
let e = edges[i];
let v1 = v[e[0]], v2 = v[e[1]];

if (e_invisible[i]) {
if (! v_invisible[e[0]]) {
[v1, v2] = [v2, v1]
}

let v12 = minus(v2, v1)
let L = len(v12)
let dx = v12[0] / L * dash, dy = v12[1] / L * dash

for (let x = v1[0], y = v1[1], cL = 0; cL <= L - dash; cL += 2 * dash, x += 2 * dx, y += 2 * dy) {
t.jump(x, y)
t.goto(x + dx, y + dy)
}
}
else {
t.jump(v1[0], v1[1])
t.goto(v2[0], v2[1])
}
}

let traj = [];
traj[0] = [0, rand_float(), rand_float()];

let prev_dir = rand() % 4; // 0 -- left, 1 -- up, 2 -- right, 3 -- down
const stepx = [-1, 0, 1, 0];
const stepy = [0, -1, 0, 1];

for (let i = 1; i <= N; i++) {
let new_dir = rand_bool() ? ((prev_dir + 1) % 4) : ((prev_dir + 3) % 4);

//let new_step = min_step + (max_step - min_step) * rand_float();

let maxs = (new_dir == 0) ? traj[i - 1][1] : ((new_dir == 1) ? (traj[i - 1][2]) : ((new_dir == 2) ? (1 - traj[i - 1][1]) : (1 - traj[i - 1][2])))
let new_step = min_step + rand_float() * (maxs - min_step);

traj[i] = [0, traj[i - 1][1] + stepx[new_dir] * new_step, traj[i - 1][2] + stepy[new_dir] * new_step];

prev_dir = new_dir;
}

const gap = 0.02;

let segm = [];

segm.push([[traj[0][1], traj[0][2]], [traj[1][1], traj[1][2]]]);

for (let i = 2; i <= N; i++) {
let p1x = traj[i - 1][1], p1y = traj[i - 1][2];
let p2x = traj[i][1], p2y = traj[i][2];

if (p1x == p2x) {
let px = p1x;
[p1y, p2y] = [Math.min(p1y, p2y), Math.max(p1y, p2y)];

let y = [];

for (let s of segm) {
if (s[0][1] == s[1][1]) {
let sy = s[0][1];
let sx1 = Math.min(s[0][0], s[1][0]), sx2 = Math.max(s[0][0], s[1][0]);

if ((sx1 < px) && (px < sx2) && (p1y < sy) && (sy < p2y)) {
y.push(sy)
}
}
}

if (y.length > 0) {
y.sort((a, b) => a - b);

if (p1y < y[0] - gap) {
segm.push([[px, p1y], [px, y[0] - gap]])
}

for (let j = 1; j < y.length; j++) {
if (y[j - 1] + gap < y[j] - gap) {
segm.push([[px, y[j - 1] + gap], [px, y[j] - gap]])
}
}

if (y[y.length - 1] + gap < p2y) {
segm.push([[px, y[y.length - 1] + gap], [px, p2y]])
}
}
else {
segm.push([[px, p1y], [px, p2y]])
}
}
else {
let py = p1y;
[p1x, p2x] = [Math.min(p1x, p2x), Math.max(p1x, p2x)];

let x = [];

for (let s of segm) {
if (s[0][0] == s[1][0]) {
let sx = s[0][0];
let sy1 = Math.min(s[0][1], s[1][1]), sy2 = Math.max(s[0][1], s[1][1]);

if ((sy1 < py) && (py < sy2) && (p1x < sx) && (sx < p2x)) {
x.push(sx)
}
}
}

if (x.length > 0) {
x.sort((a, b) => a - b);

if (p1x < x[0] - gap) {
segm.push([[p1x, py], [x[0] - gap, py]])
}

for (let j = 1; j < x.length; j++) {
if (x[j - 1] + gap < x[j] - gap) {
segm.push([[x[j - 1] + gap, py], [x[j] - gap, py]])
}
}

if (x[x.length - 1] + gap < p2x) {
segm.push([[x[x.length - 1] + gap, py], [p2x, py]])
}
}
else {
segm.push([[p1x, py], [p2x, py]])
}
}
}

for (let i = 0; i < faces.length; i++) {
if (! f_invisible[i]) {
let i1 = faces[i][0], i2 = faces[i][1], i3 = faces[i][3]

let x0 = v[i1][0], y0 = v[i1][1];
let ax = v[i2][0] - v[i1][0], ay = v[i2][1] - v[i1][1];
let bx = v[i3][0] - v[i1][0], by = v[i3][1] - v[i1][1];

for (let s of segm) {
t.jump(x0 + s[0][0] * ax + s[0][1] * bx, y0 + s[0][0] * ay + s[0][1] * by);
t.goto(x0 + s[1][0] * ax + s[1][1] * bx, y0 + s[1][0] * ay + s[1][1] * by);
}
}
}
}