on master help sign in
bridge/src/lib/card.js
190 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};
17const mapToRange = (v, l1, h1, l2, h2) =>
18 l2 + ((h2 - l2) * (v - l1)) / (h1 - l1);
20const seq = num => Array.from(Array(num), (_, i) => i);
22const compose = (...fns) =>
23 fns.reduce((f, g) => (...xs) => {
24 const r = g(...xs);
25 return Array.isArray(r) ? f(...r) : f(r);
26 });
28const Matrix = {
29 get: {
30 at: (m, r, c) => m[r][c],
31 nn: (m, r, c) => m[r - 1][c],
32 ne: (m, r, c) => m[r - 1][c + 1],
33 ee: (m, r, c) => m[r][c + 1],
34 se: (m, r, c) => m[r + 1][c + 1],
35 ss: (m, r, c) => m[r + 1][c],
36 sw: (m, r, c) => m[r + 1][c - 1],
37 ww: (m, r, c) => m[r][c - 1],
38 nw: (m, r, c) => m[r - 1][c - 1],
39 },
40 set: {
41 at: (m, r, c, v) => (m[r][c] = v),
42 nn: (m, r, c, v) => (m[r - 1][c] = v),
43 ne: (m, r, c, v) => (m[r - 1][c + 1] = v),
44 ee: (m, r, c, v) => (m[r][c + 1] = v),
45 se: (m, r, c, v) => (m[r + 1][c + 1] = v),
46 ss: (m, r, c, v) => (m[r + 1][c] = v),
47 sw: (m, r, c, v) => (m[r + 1][c - 1] = v),
48 ww: (m, r, c, v) => (m[r][c - 1] = v),
49 nw: (m, r, c, v) => (m[r - 1][c - 1] = v),
50 },
51 coord: {
52 at: (r, c) => ({ r: r, c: c }),
53 nn: (r, c) => ({ r: r - 1, c: c }),
54 ne: (r, c) => ({ r: r - 1, c: c + 1 }),
55 ee: (r, c) => ({ r: r, c: c + 1 }),
56 se: (r, c) => ({ r: r + 1, c: c + 1 }),
57 ss: (r, c) => ({ r: r + 1, c: c }),
58 sw: (r, c) => ({ r: r + 1, c: c - 1 }),
59 ww: (r, c) => ({ r: r, c: c - 1 }),
60 nw: (r, c) => ({ r: r - 1, c: c - 1 }),
61 },
62 dirs: {
63 NN: 'nn',
64 NE: 'ne',
65 EE: 'ee',
66 SE: 'se',
67 SS: 'ss',
68 SW: 'sw',
69 WW: 'ww',
70 NW: 'nw',
71 },
72 new: (rs, cs) => seq(rs).map(_ => seq(cs).map(_ => 0)),
73 rows: m => m.length - 1,
74 cols: m => m[0].length - 1,
75};
77const chunkStr = (str, size) => {
78 const r = new RegExp(`.{1,${size}}`, 'g');
79 return str.match(r);
80};
82const Base3Mapping = [
83 Matrix.dirs.NN,
84 Matrix.dirs.NE,
85 Matrix.dirs.EE,
86 Matrix.dirs.SE,
87 Matrix.dirs.SS,
88 Matrix.dirs.SW,
89 Matrix.dirs.WW,
90 Matrix.dirs.NW,
91];
93const walk = (int, matrix) => {
94 // convert the int to a base8 string, split to array
95 var chunks = int.toString(8).split('');
97 // convert the int to a base10 string
98 var b10 = int.toString(10);
100 // get number of rows and cols
101 var rows = Matrix.rows(matrix);
102 var cols = Matrix.cols(matrix);
104 // split the length-4 number into 2 parts, which is a number from 0-99
105 // if the substring is empty, substitute 10
106 var sx = parseInt(b10.substring(0, 2) || 0, 10);
107 var sy = parseInt(b10.substring(2, 4) || 0, 10);
109 // generate a starting coordinate
110 var coord = {
111 c: ~~mapToRange(sx, 0, 99, 0, cols),
112 r: ~~mapToRange(sy, 0, 99, 0, rows),
113 };
115 var vect;
116 var next;
118 for (var i = 0; i < chunks.length; i++) {
119 // Each chunk is a number from 0-7 which refers to a direction assigned in Base3Mapping.
120 // Get the current chunk, and then get the direction it has been paired with.
121 vect = Base3Mapping[chunks[i]];
123 // generate the next coordinate to go to, based on the current coordinate and the direction stored in vect.
124 next = Matrix.coord[vect](coord.r, coord.c);
126 // If at an edge of the matrix, substitute the opposite direction.
127 if (next.r < 0) vect = Matrix.dirs.SS;
128 if (next.c < 0) vect = Matrix.dirs.EE;
129 if (next.r > rows) vect = Matrix.dirs.NN;
130 if (next.c > cols) vect = Matrix.dirs.WW;
132 // If at in the corner of the matrix, substitute an alternative direction.
133 if (next.r === 0 && coord.c === 0) vect = Matrix.dirs.SE;
134 if (next.r > rows && coord.c === 0) vect = Matrix.dirs.NE;
135 if (next.r === 0 && coord.c > cols) vect = Matrix.dirs.SW;
136 if (next.r > rows && coord.c > cols) vect = Matrix.dirs.NW;
138 // get the next coordinate again in case there was an edge/cornercase
139 next = Matrix.coord[vect](coord.r, coord.c);
141 // increment the value at the next coordinate.
142 Matrix.set.at(
143 matrix,
144 next.r,
145 next.c,
146 Matrix.get.at(matrix, next.r, next.c) + 1
147 );
149 // set the new current coordinate.
150 coord = next;
151 }
153 // return a 2-ary array in order to pass both values to the next function in the compose pipeline.
154 return [int, matrix];
155};
157const rand = (int, matrix) => {
158 // break base10 integer into chunks with length of 4
159 var chunks = chunkStr(int.toString(10), 4);
160 var cols = Matrix.cols(matrix);
161 var rows = Matrix.rows(matrix);
162 var ch;
163 var x;
164 var y;
165 var c;
166 var r;
168 for (var i = 0; i < chunks.length; i++) {
169 // for each chunk in chunks
170 ch = chunks[i];
172 // split the length-4 number into 2 parts, which is a number from 0-99
173 // if the substring is empty, substitute 10
174 x = parseInt(ch.substring(0, 2) || 0, 10);
175 y = parseInt(ch.substring(2, 4) || 0, 10);
177 // map num from 0-99 to 0 - num of cols, then use ~~ for fast math.floor
178 // c (col) and r (row) are coordinates
179 c = ~~mapToRange(x, 0, 99, 0, cols);
180 r = ~~mapToRange(y, 0, 99, 0, rows);
182 // increment number at the coordinate
183 Matrix.set.at(matrix, r, c, Matrix.get.at(matrix, r, c) + 1);
184 }
186 // return a 2-ary array in order to pass both values to the next function in the compose pipeline.
187 return [int, matrix];
188};
190export { chunkStr, initCanvas, seq, Matrix, compose, mapToRange, walk, rand };