on abd024f help sign in
bridge/src/lib/card.js
191 lines 5.6 kB history raw
1const initCanvas = (canvas, size, ratio) => {
2 const { x, y } = size;
3 // let ctx = canvas.getContext('2d')
5 const dpi200 = window.devicePixelRatio * (200 / 72);
7 canvas.width = x * dpi200;
8 canvas.height = y * dpi200;
9 canvas.style.width = x + 'px';
10 canvas.style.height = y + 'px';
12 canvas.getContext('2d').scale(dpi200, dpi200);
14 return canvas;
15};
17// takes a
18const mapToRange = (v, l1, h1, l2, h2) =>
19 l2 + ((h2 - l2) * (v - l1)) / (h1 - l1);
21const seq = num => Array.from(Array(num), (_, i) => i);
23const compose = (...fns) =>
24 fns.reduce((f, g) => (...xs) => {
25 const r = g(...xs);
26 return Array.isArray(r) ? f(...r) : f(r);
27 });
29const Matrix = {
30 get: {
31 at: (m, r, c) => m[r][c],
32 nn: (m, r, c) => m[r - 1][c],
33 ne: (m, r, c) => m[r - 1][c + 1],
34 ee: (m, r, c) => m[r][c + 1],
35 se: (m, r, c) => m[r + 1][c + 1],
36 ss: (m, r, c) => m[r + 1][c],
37 sw: (m, r, c) => m[r + 1][c - 1],
38 ww: (m, r, c) => m[r][c - 1],
39 nw: (m, r, c) => m[r - 1][c - 1],
40 },
41 set: {
42 at: (m, r, c, v) => (m[r][c] = v),
43 nn: (m, r, c, v) => (m[r - 1][c] = v),
44 ne: (m, r, c, v) => (m[r - 1][c + 1] = v),
45 ee: (m, r, c, v) => (m[r][c + 1] = v),
46 se: (m, r, c, v) => (m[r + 1][c + 1] = v),
47 ss: (m, r, c, v) => (m[r + 1][c] = v),
48 sw: (m, r, c, v) => (m[r + 1][c - 1] = v),
49 ww: (m, r, c, v) => (m[r][c - 1] = v),
50 nw: (m, r, c, v) => (m[r - 1][c - 1] = v),
51 },
52 coord: {
53 at: (r, c) => ({ r: r, c: c }),
54 nn: (r, c) => ({ r: r - 1, c: c }),
55 ne: (r, c) => ({ r: r - 1, c: c + 1 }),
56 ee: (r, c) => ({ r: r, c: c + 1 }),
57 se: (r, c) => ({ r: r + 1, c: c + 1 }),
58 ss: (r, c) => ({ r: r + 1, c: c }),
59 sw: (r, c) => ({ r: r + 1, c: c - 1 }),
60 ww: (r, c) => ({ r: r, c: c - 1 }),
61 nw: (r, c) => ({ r: r - 1, c: c - 1 }),
62 },
63 dirs: {
64 NN: 'nn',
65 NE: 'ne',
66 EE: 'ee',
67 SE: 'se',
68 SS: 'ss',
69 SW: 'sw',
70 WW: 'ww',
71 NW: 'nw',
72 },
73 new: (rs, cs) => seq(rs).map(_ => seq(cs).map(_ => 0)),
74 rows: m => m.length - 1,
75 cols: m => m[0].length - 1,
76};
78const chunkStr = (str, size) => {
79 const r = new RegExp(`.{1,${size}}`, 'g');
80 return str.match(r);
81};
83const Base3Mapping = [
84 Matrix.dirs.NN,
85 Matrix.dirs.NE,
86 Matrix.dirs.EE,
87 Matrix.dirs.SE,
88 Matrix.dirs.SS,
89 Matrix.dirs.SW,
90 Matrix.dirs.WW,
91 Matrix.dirs.NW,
92];
94const walk = (int, matrix) => {
95 // convert the int to a base8 string, split to array
96 var chunks = int.toString(8).split('');
98 // convert the int to a base10 string
99 var b10 = int.toString(10);
101 // get number of rows and cols
102 var rows = Matrix.rows(matrix);
103 var cols = Matrix.cols(matrix);
105 // split the length-4 number into 2 parts, which is a number from 0-99
106 // if the substring is empty, substitute 10
107 var sx = parseInt(b10.substring(0, 2) || 0, 10);
108 var sy = parseInt(b10.substring(2, 4) || 0, 10);
110 // generate a starting coordinate
111 var coord = {
112 c: ~~mapToRange(sx, 0, 99, 0, cols),
113 r: ~~mapToRange(sy, 0, 99, 0, rows),
114 };
116 var vect;
117 var next;
119 for (var i = 0; i < chunks.length; i++) {
120 // Each chunk is a number from 0-7 which refers to a direction assigned in Base3Mapping.
121 // Get the current chunk, and then get the direction it has been paired with.
122 vect = Base3Mapping[chunks[i]];
124 // generate the next coordinate to go to, based on the current coordinate and the direction stored in vect.
125 next = Matrix.coord[vect](coord.r, coord.c);
127 // If at an edge of the matrix, substitute the opposite direction.
128 if (next.r < 0) vect = Matrix.dirs.SS;
129 if (next.c < 0) vect = Matrix.dirs.EE;
130 if (next.r > rows) vect = Matrix.dirs.NN;
131 if (next.c > cols) vect = Matrix.dirs.WW;
133 // If at in the corner of the matrix, substitute an alternative direction.
134 if (next.r === 0 && coord.c === 0) vect = Matrix.dirs.SE;
135 if (next.r > rows && coord.c === 0) vect = Matrix.dirs.NE;
136 if (next.r === 0 && coord.c > cols) vect = Matrix.dirs.SW;
137 if (next.r > rows && coord.c > cols) vect = Matrix.dirs.NW;
139 // get the next coordinate again in case there was an edge/cornercase
140 next = Matrix.coord[vect](coord.r, coord.c);
142 // increment the value at the next coordinate.
143 Matrix.set.at(
144 matrix,
145 next.r,
146 next.c,
147 Matrix.get.at(matrix, next.r, next.c) + 1
148 );
150 // set the new current coordinate.
151 coord = next;
152 }
154 // return a 2-ary array in order to pass both values to the next function in the compose pipeline.
155 return [int, matrix];
156};
158const rand = (int, matrix) => {
159 // break base10 integer into chunks with length of 4
160 var chunks = chunkStr(int.toString(10), 4);
161 var cols = Matrix.cols(matrix);
162 var rows = Matrix.rows(matrix);
163 var ch;
164 var x;
165 var y;
166 var c;
167 var r;
169 for (var i = 0; i < chunks.length; i++) {
170 // for each chunk in chunks
171 ch = chunks[i];
173 // split the length-4 number into 2 parts, which is a number from 0-99
174 // if the substring is empty, substitute 10
175 x = parseInt(ch.substring(0, 2) || 0, 10);
176 y = parseInt(ch.substring(2, 4) || 0, 10);
178 // map num from 0-99 to 0 - num of cols, then use ~~ for fast math.floor
179 // c (col) and r (row) are coordinates
180 c = ~~mapToRange(x, 0, 99, 0, cols);
181 r = ~~mapToRange(y, 0, 99, 0, rows);
183 // increment number at the coordinate
184 Matrix.set.at(matrix, r, c, Matrix.get.at(matrix, r, c) + 1);
185 }
187 // return a 2-ary array in order to pass both values to the next function in the compose pipeline.
188 return [int, matrix];
189};
191export { chunkStr, initCanvas, seq, Matrix, compose, mapToRange, walk, rand };