| ... | ... | @@ -0,0 +1,744 @@ |
| 1 | const std = @import("std"); |
| 2 | const extras = @import("extras"); |
| 3 | |
| 4 | /// GF(256)[0...255] |
| 5 | const GF = blk: { |
| 6 | var gf: [256]u8 = @splat(2); |
| 7 | for (0..256) |n| { |
| 8 | if (n == 0) { |
| 9 | gf[n] = 1; |
| 10 | continue; |
| 11 | } |
| 12 | if (n < 8) { |
| 13 | gf[n] <<= @intCast(n - 1); |
| 14 | continue; |
| 15 | } |
| 16 | gf[n] = gf[n - 1] *% 2; |
| 17 | if (gf[n - 1] > 127) gf[n] ^= 0b00011101; |
| 18 | } |
| 19 | const out = gf; |
| 20 | break :blk out; |
| 21 | }; |
| 22 | |
| 23 | pub fn encode(comptime mode: Mode, comptime level: Level, comptime version: u16, input: []const u8) BitGrid(4 * version + 17) { |
| 24 | _ = &version; |
| 25 | _ = &mode; |
| 26 | _ = &level; |
| 27 | _ = &input; |
| 28 | |
| 29 | std.log.warn("mode: {s}", .{@tagName(mode)}); |
| 30 | std.log.warn("level: {s}", .{@tagName(level)}); |
| 31 | |
| 32 | if (mode == .numeric) std.debug.assert(extras.matchesAll(u8, input, isNumeric)); |
| 33 | if (mode == .alphanumeric) std.debug.assert(extras.matchesAll(u8, input, isAlphanumeric)); |
| 34 | // latin1 is a full 1-byte format, some readers can detect utf-8 |
| 35 | // shift jis is a full 2-byte format |
| 36 | |
| 37 | const max_lengths = comptime maxLenPerModeLevelVersion(mode, level); |
| 38 | const max_length = max_lengths[version]; |
| 39 | std.log.warn("actual version: {d},{d},{d}", .{ version, max_length, input.len }); |
| 40 | std.debug.assert(input.len <= max_length); |
| 41 | for (max_lengths, 0..) |l, i| if (l > input.len) break std.log.warn("reccom version: {d},{d}", .{ i, l }); |
| 42 | |
| 43 | const mode_indicator: u4 = switch (mode) { |
| 44 | .numeric => 0b0001, |
| 45 | .alphanumeric => 0b0010, |
| 46 | .latin1 => 0b0100, |
| 47 | .shiftjis => 0b1000, |
| 48 | }; |
| 49 | std.log.warn("mode_indicator: {d}", .{mode_indicator}); |
| 50 | |
| 51 | const LenIndicator = switch (mode) { |
| 52 | .numeric => switch (version) { |
| 53 | 1...9 => u10, |
| 54 | 10...26 => u12, |
| 55 | 27...40 => u14, |
| 56 | else => unreachable, |
| 57 | }, |
| 58 | .alphanumeric => switch (version) { |
| 59 | 1...9 => u9, |
| 60 | 10...26 => u11, |
| 61 | 27...40 => u13, |
| 62 | else => unreachable, |
| 63 | }, |
| 64 | .latin1 => switch (version) { |
| 65 | 1...9 => u8, |
| 66 | 10...26 => u16, |
| 67 | 27...40 => u16, |
| 68 | else => unreachable, |
| 69 | }, |
| 70 | .shiftjis => switch (version) { |
| 71 | 1...9 => u8, |
| 72 | 10...26 => u10, |
| 73 | 27...40 => u12, |
| 74 | else => unreachable, |
| 75 | }, |
| 76 | }; |
| 77 | const len_indicator: LenIndicator = @intCast(input.len); |
| 78 | std.log.warn("len_indicator: {d}", .{len_indicator}); |
| 79 | |
| 80 | const total_bits = (max_length + 2) * 8; |
| 81 | std.log.warn("total_bits: {d}", .{total_bits}); |
| 82 | |
| 83 | var scratch: std.bit_set.ArrayBitSet(u8, total_bits) = .initEmpty(); |
| 84 | _ = &scratch; |
| 85 | var scratchw: BitsetWriter(u8, total_bits) = .{ .set = &scratch }; |
| 86 | _ = &scratchw; |
| 87 | |
| 88 | scratchw.writeInt(mode_indicator); |
| 89 | scratchw.writeInt(len_indicator); |
| 90 | for (input) |x| scratchw.writeInt(x); |
| 91 | |
| 92 | const data_bits = input.len * 8 + @bitSizeOf(@TypeOf(mode_indicator)) + @bitSizeOf(@TypeOf(len_indicator)); |
| 93 | std.log.warn("data_bits: {d}", .{data_bits}); |
| 94 | std.debug.assert(scratchw.idx == data_bits); |
| 95 | std.debug.assert(scratchw.idx == 44); //temp |
| 96 | |
| 97 | // write @max(4, padding_bits) 0s |
| 98 | for (0..@min(4, total_bits - scratchw.idx)) |_| scratchw.writeInt(@as(u1, 0)); |
| 99 | std.debug.assert(scratchw.idx == 48); //temp |
| 100 | |
| 101 | // add zero bits to make data_bits%8 == 0 |
| 102 | for (0..-%scratchw.idx & 7) |_| scratchw.writeInt(@as(u1, 0)); |
| 103 | std.debug.assert(scratchw.idx == 48); //temp |
| 104 | |
| 105 | // add 236(11101100) 17(00010001) until we reach total_bits |
| 106 | while (scratchw.idx < total_bits) { |
| 107 | scratchw.writeInt(@as(u8, 0xec)); |
| 108 | scratchw.writeInt(@as(u8, 0x11)); |
| 109 | } |
| 110 | |
| 111 | // std.log.warn("{b:0>8}", .{&bitReverse(scratch.masks)}); |
| 112 | // std.log.warn("{d}", .{&bitReverse(scratch.masks)}); |
| 113 | // std.log.warn("{x}", .{&bitReverse(scratch.masks)}); |
| 114 | |
| 115 | std.debug.assert(@bitReverse(scratch.masks[0]) == 0b01000000); //temp |
| 116 | std.debug.assert(!scratch.isSet(0)); //temp |
| 117 | std.debug.assert(scratch.isSet(1)); //temp |
| 118 | std.debug.assert(!scratch.isSet(2)); //temp |
| 119 | std.debug.assert(!scratch.isSet(3)); //temp |
| 120 | // 01000000 01000101 01100110 01010111 00100011 00010000 11101100 00010001 11101100 00010001 11101100 00010001 11101100 00010001 11101100 00010001 11101100 00010001 11101100 |
| 121 | // 01000000 01000101 01100110 01010111 00100011 00010000 11101100 00010001 11101100 00010001 11101100 00010001 11101100 00010001 11101100 00010001 11101100 00010001 11101100 |
| 122 | |
| 123 | const groups = 1; // ? |
| 124 | _ = &groups; |
| 125 | const blocks = 1; // ? |
| 126 | _ = &blocks; |
| 127 | const dc_per_block = 19; //? |
| 128 | _ = &dc_per_block; |
| 129 | const ecc_per_block = 7; //? |
| 130 | _ = &ecc_per_block; |
| 131 | |
| 132 | var message_polynomial = scratch.masks; |
| 133 | _ = &message_polynomial; |
| 134 | std.log.warn("message_polynomial: {d}", .{&bitReverse(message_polynomial)}); |
| 135 | |
| 136 | const generator_polynomial = reverseArray(generatorPolynomial(ecc_per_block)); |
| 137 | _ = &generator_polynomial; |
| 138 | std.log.warn("generator_polynomial: {d}", .{generator_polynomial}); |
| 139 | |
| 140 | const generator_polynomial_alpha = to_alpha(generator_polynomial); |
| 141 | _ = &generator_polynomial_alpha; |
| 142 | std.log.warn("generator_polynomial_alpha: {d}", .{generator_polynomial_alpha}); |
| 143 | |
| 144 | // Now that the message and generator polynomials have been created, divide them to get the error codewords. |
| 145 | { |
| 146 | // 1. Multiply the message polynomial by x^n where n is the number of error correction codewords to be generated |
| 147 | // and multiply the generator polynomial by x^m where m is the leading exponent of the message polynomial. |
| 148 | // 2. Multiply the generator polynomial by the lead term of the message polynomial. |
| 149 | // 3. XOR the result of Step 2 with the message polynomial and discard the lead 0 term. |
| 150 | // 4. Repeat Steps 2-3 n-1 more times where n is the number of data codewords. |
| 151 | } |
| 152 | var mp: [scratch.masks.len + ecc_per_block]?u8 = @splat(null); |
| 153 | for (&message_polynomial, 0..) |x, i| mp[i] = to_alpha(.{@bitReverse(x)})[0]; |
| 154 | |
| 155 | for (0..scratch.masks.len) |i| { |
| 156 | const lead = mp[i].?; |
| 157 | for (&generator_polynomial_alpha, 0..) |x, j| { |
| 158 | var y = GF[(@as(usize, x) + lead) % 255]; |
| 159 | if (mp[i + j]) |z| y ^= GF[z]; |
| 160 | mp[i + j] = if (y == 0) null else to_alpha(.{y})[0]; |
| 161 | } |
| 162 | } |
| 163 | |
| 164 | var error_codewords: [ecc_per_block]u8 = @splat(0); |
| 165 | for (0..ecc_per_block) |i| error_codewords[i] = if (mp[message_polynomial.len..][i]) |x| GF[x] else 0; |
| 166 | std.log.warn("error_codewords: {d}", .{error_codewords}); |
| 167 | |
| 168 | const interleaved_message = scratch.masks ++ bitReverse(error_codewords); |
| 169 | _ = &interleaved_message; |
| 170 | std.log.warn("interleaved_message: {b:0>8}", .{&bitReverse(interleaved_message)}); |
| 171 | |
| 172 | // remainder bits |
| 173 | |
| 174 | // |
| 175 | |
| 176 | const size = 4 * version + 17; |
| 177 | var grid: BitGrid(size) = .initEmpty(); |
| 178 | _ = &grid; |
| 179 | |
| 180 | // top left finder pattern |
| 181 | for (0..7) |i| for (0..7) |j| grid.setT(0 + i, 0 + j); |
| 182 | for (0..5) |i| for (0..5) |j| grid.setF(1 + i, 1 + j); |
| 183 | for (0..3) |i| for (0..3) |j| grid.setT(2 + i, 2 + j); |
| 184 | |
| 185 | // top right finder pattern |
| 186 | for (0..7) |i| for (0..7) |j| grid.setT(size - 7 + 0 + i, 0 + j); |
| 187 | for (0..5) |i| for (0..5) |j| grid.setF(size - 7 + 1 + i, 1 + j); |
| 188 | for (0..3) |i| for (0..3) |j| grid.setT(size - 7 + 2 + i, 2 + j); |
| 189 | |
| 190 | // bottom left finder pattern |
| 191 | for (0..7) |i| for (0..7) |j| grid.setT(0 + i, size - 7 + 0 + j); |
| 192 | for (0..5) |i| for (0..5) |j| grid.setF(1 + i, size - 7 + 1 + j); |
| 193 | for (0..3) |i| for (0..3) |j| grid.setT(2 + i, size - 7 + 2 + j); |
| 194 | |
| 195 | // timing pattern |
| 196 | for (8..size) |i| if (i % 2 == 0) grid.set(i, 6); |
| 197 | for (8..size) |i| if (i % 2 == 0) grid.set(6, i); |
| 198 | |
| 199 | // alignment patterns |
| 200 | |
| 201 | // dark module |
| 202 | grid.set(8, 4 * (version - 1) + 13); |
| 203 | |
| 204 | // version block |
| 205 | |
| 206 | // data mask (data cannot be placed where this is set) |
| 207 | var data_mask: BitGrid(size) = .initEmpty(); |
| 208 | for (0..9) |y| for (0..9) |x| data_mask.set(x, y); |
| 209 | for (0..9) |y| for (0..8) |x| data_mask.set(size - 8 + x, y); |
| 210 | for (0..8) |y| for (0..9) |x| data_mask.set(x, size - 8 + y); |
| 211 | for (0..size) |i| data_mask.set(i, 6); |
| 212 | for (0..size) |i| data_mask.set(6, i); |
| 213 | |
| 214 | // write data |
| 215 | var data_iter: BufBiterator = .init(&bitReverse(interleaved_message)); |
| 216 | _ = &data_iter; |
| 217 | |
| 218 | var griditer: GridZigZag = .init(size, 6); |
| 219 | while (griditer.next()) |idx| { |
| 220 | const x = idx % size; |
| 221 | const y = (idx - x) / size; |
| 222 | // std.log.warn("idx: {d} {d},{d}", .{ idx, x, y }); |
| 223 | if (data_mask.isSet(x, y)) continue; |
| 224 | grid.debug.set((y * size) + x); |
| 225 | if (@bitCast(data_iter.next() orelse break)) grid.set(x, y); |
| 226 | } |
| 227 | |
| 228 | // |
| 229 | |
| 230 | for (0..8) |y| for (0..8) |x| grid.debug.set((y * size) + x); |
| 231 | for (0..8) |y| for (0..8) |x| grid.debug.set((y * size) + size - 8 + x); |
| 232 | for (0..8) |y| for (0..8) |x| grid.debug.set(((size - 8 + y) * size) + x); |
| 233 | for (0..size) |i| grid.debug.set((6 * size) + i); |
| 234 | for (0..size) |i| grid.debug.set((i * size) + 6); |
| 235 | |
| 236 | // format info |
| 237 | var masks = [_]std.bit_set.IntegerBitSet(15){ |
| 238 | .{ .mask = @bitReverse(formatPattern(level, 0)) }, |
| 239 | .{ .mask = @bitReverse(formatPattern(level, 1)) }, |
| 240 | .{ .mask = @bitReverse(formatPattern(level, 2)) }, |
| 241 | .{ .mask = @bitReverse(formatPattern(level, 3)) }, |
| 242 | .{ .mask = @bitReverse(formatPattern(level, 4)) }, |
| 243 | .{ .mask = @bitReverse(formatPattern(level, 5)) }, |
| 244 | .{ .mask = @bitReverse(formatPattern(level, 6)) }, |
| 245 | .{ .mask = @bitReverse(formatPattern(level, 7)) }, |
| 246 | }; |
| 247 | var grids = [_]BitGrid(size){ |
| 248 | grid, |
| 249 | grid, |
| 250 | grid, |
| 251 | grid, |
| 252 | grid, |
| 253 | grid, |
| 254 | grid, |
| 255 | grid, |
| 256 | }; |
| 257 | for (&grids, &masks) |*g, m| { |
| 258 | g.setV(0, 8, m.isSet(0)); |
| 259 | g.setV(1, 8, m.isSet(1)); |
| 260 | g.setV(2, 8, m.isSet(2)); |
| 261 | g.setV(3, 8, m.isSet(3)); |
| 262 | g.setV(4, 8, m.isSet(4)); |
| 263 | g.setV(5, 8, m.isSet(5)); |
| 264 | g.setV(7, 8, m.isSet(6)); |
| 265 | g.setV(8, 8, m.isSet(7)); |
| 266 | g.setV(8, 7, m.isSet(8)); |
| 267 | g.setV(8, 5, m.isSet(9)); |
| 268 | g.setV(8, 4, m.isSet(10)); |
| 269 | g.setV(8, 3, m.isSet(11)); |
| 270 | g.setV(8, 2, m.isSet(12)); |
| 271 | g.setV(8, 1, m.isSet(13)); |
| 272 | g.setV(8, 0, m.isSet(14)); |
| 273 | |
| 274 | g.setV(8, size - 1 - 0, m.isSet(0)); |
| 275 | g.setV(8, size - 1 - 1, m.isSet(1)); |
| 276 | g.setV(8, size - 1 - 2, m.isSet(2)); |
| 277 | g.setV(8, size - 1 - 3, m.isSet(3)); |
| 278 | g.setV(8, size - 1 - 4, m.isSet(4)); |
| 279 | g.setV(8, size - 1 - 5, m.isSet(5)); |
| 280 | g.setV(8, size - 1 - 6, m.isSet(6)); |
| 281 | g.setV(size - 8 + 0, 8, m.isSet(7)); |
| 282 | g.setV(size - 8 + 1, 8, m.isSet(8)); |
| 283 | g.setV(size - 8 + 2, 8, m.isSet(9)); |
| 284 | g.setV(size - 8 + 3, 8, m.isSet(10)); |
| 285 | g.setV(size - 8 + 4, 8, m.isSet(11)); |
| 286 | g.setV(size - 8 + 5, 8, m.isSet(12)); |
| 287 | g.setV(size - 8 + 6, 8, m.isSet(13)); |
| 288 | g.setV(size - 8 + 7, 8, m.isSet(14)); |
| 289 | } |
| 290 | |
| 291 | // masking patterns |
| 292 | // Pattern 0: (row + column) mod 2 == 0 |
| 293 | for (0..size) |row| for (0..size) |col| if (!data_mask.isSet(col, row) and (row + col) % 2 == 0) grids[0].flip(col, row); |
| 294 | // Pattern 1: row mod 2 == 0 |
| 295 | for (0..size) |row| for (0..size) |col| if (!data_mask.isSet(col, row) and row % 2 == 0) grids[1].flip(col, row); |
| 296 | // Pattern 2: column mod 3 == 0 |
| 297 | for (0..size) |row| for (0..size) |col| if (!data_mask.isSet(col, row) and col % 3 == 0) grids[2].flip(col, row); |
| 298 | // Pattern 3: (row + column) mod 3 == 0 |
| 299 | for (0..size) |row| for (0..size) |col| if (!data_mask.isSet(col, row) and (row + col) % 3 == 0) grids[3].flip(col, row); |
| 300 | // Pattern 4: (floor(row/2) + floor(column / 3)) mod 2 == 0 |
| 301 | for (0..size) |row| for (0..size) |col| if (!data_mask.isSet(col, row) and (row / 2 + col / 3) % 2 == 0) grids[4].flip(col, row); |
| 302 | // Pattern 5: ((row * column) mod 2) + ((row * column) mod 3) == 0 |
| 303 | for (0..size) |row| for (0..size) |col| if (!data_mask.isSet(col, row) and (((row * col) % 2) + ((row * col) % 3)) == 0) grids[5].flip(col, row); |
| 304 | // Pattern 6: ( ((row * column) mod 2) + ((row * column) mod 3) ) mod 2 == 0 |
| 305 | for (0..size) |row| for (0..size) |col| if (!data_mask.isSet(col, row) and (((row * col) % 2) + ((row * col) % 3)) % 2 == 0) grids[6].flip(col, row); |
| 306 | // Pattern 7: ( ((row + column) mod 2) + ((row * column) mod 3) ) mod 2 == 0 |
| 307 | for (0..size) |row| for (0..size) |col| if (!data_mask.isSet(col, row) and (((row + col) % 2) + ((row * col) % 3)) % 2 == 0) grids[7].flip(col, row); |
| 308 | |
| 309 | // penalty |
| 310 | var penaltys: [8][4]u32 = @splat(@splat(0)); |
| 311 | for (&grids, 0..) |*g, i| { |
| 312 | var prev = false; |
| 313 | var run: u16 = 0; |
| 314 | for (0..size) |y| { |
| 315 | for (0..size) |x| { |
| 316 | if (x == 0) { |
| 317 | run = 0; |
| 318 | prev = g.isSet(0, y); |
| 319 | } |
| 320 | const this = g.isSet(x, y); |
| 321 | if (this == prev) { |
| 322 | run += 1; |
| 323 | penaltys[i][0] += if (run == 5) 3 else if (run > 5) 1 else 0; |
| 324 | } else { |
| 325 | run = 1; |
| 326 | } |
| 327 | prev = this; |
| 328 | } |
| 329 | } |
| 330 | for (0..size) |x| { |
| 331 | for (0..size) |y| { |
| 332 | if (y == 0) { |
| 333 | run = 0; |
| 334 | prev = g.isSet(x, 0); |
| 335 | } |
| 336 | const this = g.isSet(x, y); |
| 337 | if (this == prev) { |
| 338 | run += 1; |
| 339 | penaltys[i][0] += if (run == 5) 3 else if (run > 5) 1 else 0; |
| 340 | } else { |
| 341 | run = 1; |
| 342 | } |
| 343 | prev = this; |
| 344 | } |
| 345 | } |
| 346 | } |
| 347 | for (&grids, 0..) |*g, i| { |
| 348 | for (0..size - 1) |y| { |
| 349 | for (0..size - 1) |x| { |
| 350 | const p0 = g.isSet(x, y); |
| 351 | const p1 = g.isSet(x + 1, y); |
| 352 | const p2 = g.isSet(x, y + 1); |
| 353 | const p3 = g.isSet(x + 1, y + 1); |
| 354 | penaltys[i][1] += if (p0 == p1 and p1 == p2 and p2 == p3) 3 else 0; |
| 355 | } |
| 356 | } |
| 357 | } |
| 358 | for (&grids, 0..) |*g, i| { |
| 359 | for (0..size) |y| { |
| 360 | for (0..size - 10) |x| { |
| 361 | const sel = g.sliceX(y, x, 11); |
| 362 | penaltys[i][2] += if (sel.mask == 0b00001011101) 40 else 0; |
| 363 | penaltys[i][2] += if (sel.mask == 0b10111010000) 40 else 0; |
| 364 | } |
| 365 | } |
| 366 | for (0..size) |x| { |
| 367 | for (0..size - 10) |y| { |
| 368 | const sel = g.sliceY(x, y, 11); |
| 369 | penaltys[i][2] += if (sel.mask == 0b00001011101) 40 else 0; |
| 370 | penaltys[i][2] += if (sel.mask == 0b10111010000) 40 else 0; |
| 371 | } |
| 372 | } |
| 373 | } |
| 374 | for (&grids, 0..) |*g, i| { |
| 375 | const total_modules: comptime_float = size * size; |
| 376 | var dark_modules: f32 = 0; |
| 377 | for (0..size) |y| { |
| 378 | for (0..size) |x| { |
| 379 | if (g.isSet(x, y)) { |
| 380 | dark_modules += 1; |
| 381 | } |
| 382 | } |
| 383 | } |
| 384 | const percent: u32 = @intFromFloat(@ceil(dark_modules / total_modules * 100)); |
| 385 | const round1 = percent + (-%percent & 4); |
| 386 | const round2 = round1 -| 5; |
| 387 | const sub = [_]u32{ @abs(@as(i32, @intCast(round1)) - 50), @abs(@as(i32, @intCast(round2)) - 50) }; |
| 388 | const div = [_]u32{ @divFloor(sub[0], 5), @divFloor(sub[1], 5) }; |
| 389 | penaltys[i][3] += std.mem.min(u32, &div) * 10; |
| 390 | } |
| 391 | for (&penaltys) |x| std.log.warn("penaltys: {d}", .{&x}); |
| 392 | |
| 393 | var penalty: [8]u32 = @splat(0); |
| 394 | for (0..8) |i| penalty[i] = extras.sum(u32, &penaltys[i]); |
| 395 | |
| 396 | const min_penalty = std.mem.min(u32, &penalty); |
| 397 | std.log.warn("min_penalty: {d}", .{min_penalty}); |
| 398 | const min_mask = std.mem.indexOfScalar(u32, &penalty, min_penalty).?; |
| 399 | std.log.warn("min_mask: {d}", .{min_mask}); |
| 400 | |
| 401 | std.log.warn("", .{}); |
| 402 | return grids[min_mask]; |
| 403 | } |
| 404 | |
| 405 | fn BitGrid(comptime size: usize) type { |
| 406 | return struct { |
| 407 | bset: std.bit_set.ArrayBitSet(usize, size * size), |
| 408 | debug: std.bit_set.ArrayBitSet(usize, size * size), |
| 409 | comptime size: usize = size, |
| 410 | |
| 411 | pub fn initEmpty() @This() { |
| 412 | return .{ |
| 413 | .bset = .initEmpty(), |
| 414 | .debug = .initEmpty(), |
| 415 | }; |
| 416 | } |
| 417 | |
| 418 | pub fn isSet(self: *const @This(), x: usize, y: usize) bool { |
| 419 | return self.bset.isSet((y * size) + x); |
| 420 | } |
| 421 | |
| 422 | pub fn set(self: *@This(), x: usize, y: usize) void { |
| 423 | self.bset.set((y * size) + x); |
| 424 | self.debug.set((y * size) + x); |
| 425 | } |
| 426 | |
| 427 | pub fn setF(self: *@This(), x: usize, y: usize) void { |
| 428 | self.bset.setValue((y * size) + x, false); |
| 429 | self.debug.setValue((y * size) + x, true); |
| 430 | } |
| 431 | |
| 432 | pub fn setT(self: *@This(), x: usize, y: usize) void { |
| 433 | self.bset.setValue((y * size) + x, true); |
| 434 | self.debug.setValue((y * size) + x, true); |
| 435 | } |
| 436 | |
| 437 | pub fn setV(self: *@This(), x: usize, y: usize, value: bool) void { |
| 438 | self.bset.setValue((y * size) + x, value); |
| 439 | self.debug.setValue((y * size) + x, true); |
| 440 | } |
| 441 | |
| 442 | pub fn hasSet(self: *const @This(), x: usize, y: usize) bool { |
| 443 | return self.debug.isSet((y * size) + x); |
| 444 | } |
| 445 | |
| 446 | pub fn flip(self: *@This(), x: usize, y: usize) void { |
| 447 | std.debug.assert(self.debug.isSet((y * size) + x)); |
| 448 | self.bset.toggle((y * size) + x); |
| 449 | } |
| 450 | |
| 451 | pub fn sliceX(self: *@This(), y: usize, sx: usize, comptime len: usize) std.bit_set.IntegerBitSet(len) { |
| 452 | var result: std.bit_set.IntegerBitSet(len) = .initEmpty(); |
| 453 | for (0..len) |i| result.setValue(i, self.isSet(sx + i, y)); |
| 454 | return result; |
| 455 | } |
| 456 | |
| 457 | pub fn sliceY(self: *@This(), x: usize, sy: usize, comptime len: usize) std.bit_set.IntegerBitSet(len) { |
| 458 | var result: std.bit_set.IntegerBitSet(len) = .initEmpty(); |
| 459 | for (0..len) |i| result.setValue(i, self.isSet(x, sy + i)); |
| 460 | return result; |
| 461 | } |
| 462 | }; |
| 463 | } |
| 464 | |
| 465 | fn BitsetWriter(MaskIntType: type, size: usize) type { |
| 466 | return struct { |
| 467 | set: *std.bit_set.ArrayBitSet(MaskIntType, size), |
| 468 | idx: usize = 0, |
| 469 | |
| 470 | pub fn writeInt(self: *@This(), int: anytype) void { |
| 471 | return writeInt2(self, @bitReverse(int)); |
| 472 | } |
| 473 | fn writeInt2(self: *@This(), int: anytype) void { |
| 474 | const T = @TypeOf(int); |
| 475 | const info = @typeInfo(T).int; |
| 476 | comptime std.debug.assert(info.signedness == .unsigned); |
| 477 | if (self.idx == size) { |
| 478 | return; |
| 479 | } |
| 480 | if (T == u1) { |
| 481 | self.set.setValue(self.idx, @bitCast(int)); |
| 482 | self.idx += 1; |
| 483 | return; |
| 484 | } |
| 485 | self.set.setValue(self.idx, (int & 1) == 1); |
| 486 | self.idx += 1; |
| 487 | return writeInt2(self, @as(extras.OneSmallerInt(T), @intCast(int >> 1))); |
| 488 | } |
| 489 | }; |
| 490 | } |
| 491 | |
| 492 | fn bitReverse(array: anytype) [array.len]std.meta.Child(@TypeOf(array)) { |
| 493 | var result: [array.len]std.meta.Child(@TypeOf(array)) = @splat(0); |
| 494 | for (&array, &result) |x, *y| y.* = @bitReverse(x); |
| 495 | return result; |
| 496 | } |
| 497 | |
| 498 | fn reverseArray(array: anytype) @TypeOf(array) { |
| 499 | var result: @TypeOf(array) = array; |
| 500 | for (0..result.len / 2) |i| { |
| 501 | std.mem.swap(std.meta.Child(@TypeOf(result)), &result[i], &result[result.len - 1 - i]); |
| 502 | } |
| 503 | return result; |
| 504 | } |
| 505 | |
| 506 | // |
| 507 | |
| 508 | pub const Mode = enum { |
| 509 | numeric, |
| 510 | alphanumeric, |
| 511 | latin1, |
| 512 | shiftjis, |
| 513 | }; |
| 514 | |
| 515 | pub const Level = enum { |
| 516 | L, |
| 517 | M, |
| 518 | Q, |
| 519 | H, |
| 520 | }; |
| 521 | |
| 522 | // Sourced from https://gist.github.com/ZavierHenry/a4b3761212109d5598bb2db79c334782 |
| 523 | pub fn maxLenPerModeLevelVersion(mode: Mode, level: Level) *const [41]u16 { |
| 524 | return switch (mode) { |
| 525 | .numeric => switch (level) { |
| 526 | .L => &.{ 0, 41, 77, 127, 187, 255, 322, 370, 461, 552, 652, 772, 883, 1022, 1101, 1250, 1408, 1548, 1725, 1903, 2061, 2232, 2409, 2620, 2812, 3057, 2383, 3517, 3669, 3909, 4158, 4417, 4686, 4965, 5253, 5529, 5836, 6153, 6479, 6743, 7089 }, |
| 527 | .M => &.{ 0, 34, 63, 101, 149, 202, 255, 293, 365, 432, 513, 694, 691, 796, 871, 991, 1082, 1212, 1346, 1500, 1600, 1708, 1872, 2059, 2188, 2395, 2544, 2701, 2857, 3035, 3289, 3486, 3693, 3909, 4134, 4343, 4588, 4775, 5039, 5313, 5596 }, |
| 528 | .Q => &.{ 0, 27, 48, 77, 111, 144, 178, 207, 259, 312, 364, 427, 489, 580, 621, 703, 775, 876, 948, 1063, 1159, 1224, 1358, 1468, 1588, 1718, 1804, 1933, 2085, 2181, 2358, 2473, 2670, 2805, 2949, 3081, 3244, 3417, 3599, 3791, 3993 }, |
| 529 | .H => &.{ 0, 17, 34, 58, 82, 106, 139, 154, 202, 235, 288, 331, 374, 427, 468, 530, 602, 674, 746, 813, 919, 969, 1056, 1108, 1228, 1286, 1425, 1501, 1581, 1677, 1782, 1897, 2022, 2157, 2301, 2361, 2524, 2625, 2735, 2927, 3057 }, |
| 530 | }, |
| 531 | .alphanumeric => switch (level) { |
| 532 | .L => &.{ 0, 25, 47, 77, 114, 154, 195, 224, 279, 335, 395, 468, 535, 619, 667, 758, 854, 938, 1046, 1153, 1249, 1352, 1460, 1588, 1704, 1853, 1990, 2132, 2223, 2369, 2520, 2677, 2840, 3009, 3183, 3351, 3537, 3729, 3927, 4087, 4296 }, |
| 533 | .M => &.{ 0, 20, 38, 61, 90, 122, 154, 178, 221, 262, 311, 366, 419, 483, 528, 600, 656, 734, 816, 909, 970, 1035, 1134, 1248, 1326, 1451, 1542, 1637, 1732, 1839, 1994, 2113, 2238, 2369, 2506, 2632, 2780, 2894, 3054, 3220, 3391 }, |
| 534 | .Q => &.{ 0, 16, 29, 47, 67, 87, 108, 125, 157, 189, 221, 259, 296, 352, 376, 426, 470, 531, 574, 644, 702, 742, 823, 890, 963, 1041, 1094, 1172, 1263, 1322, 1429, 1499, 1618, 1700, 1787, 1867, 1966, 2071, 2181, 2298, 2420 }, |
| 535 | .H => &.{ 0, 10, 20, 35, 50, 64, 84, 93, 122, 143, 174, 200, 227, 259, 283, 321, 365, 408, 452, 493, 557, 587, 640, 672, 744, 779, 864, 910, 958, 1016, 1080, 1150, 1226, 1307, 1394, 1431, 1530, 1591, 1658, 1774, 1852 }, |
| 536 | }, |
| 537 | .latin1 => switch (level) { |
| 538 | .L => &.{ 0, 17, 32, 53, 78, 106, 134, 154, 192, 230, 271, 321, 367, 425, 458, 520, 586, 644, 718, 792, 858, 929, 1003, 1091, 1171, 1273, 1367, 1465, 1528, 1628, 1732, 1840, 1952, 2068, 2188, 2303, 2431, 2563, 2699, 2809, 2953 }, |
| 539 | .M => &.{ 0, 14, 26, 42, 62, 84, 106, 122, 152, 180, 213, 251, 287, 331, 362, 412, 450, 504, 560, 624, 666, 711, 779, 857, 911, 997, 1059, 1125, 1190, 1264, 1370, 1452, 1538, 1628, 1722, 1809, 1911, 1989, 2099, 2213, 2331 }, |
| 540 | .Q => &.{ 0, 11, 20, 32, 46, 60, 74, 86, 108, 130, 151, 177, 203, 241, 258, 292, 322, 364, 394, 442, 482, 509, 565, 611, 661, 715, 751, 805, 868, 908, 982, 1030, 1112, 1168, 1228, 1283, 1351, 1423, 1499, 1579, 1663 }, |
| 541 | .H => &.{ 0, 7, 14, 24, 34, 44, 58, 64, 84, 98, 119, 137, 155, 177, 194, 220, 250, 280, 310, 338, 382, 403, 439, 461, 511, 535, 593, 625, 658, 698, 742, 790, 842, 898, 958, 983, 1051, 1093, 1139, 1219, 1273 }, |
| 542 | }, |
| 543 | .shiftjis => switch (level) { |
| 544 | .L => &.{ 0, 10, 20, 32, 48, 65, 82, 95, 118, 141, 167, 198, 226, 262, 282, 320, 361, 397, 442, 488, 528, 572, 618, 672, 721, 784, 842, 902, 940, 1002, 1066, 1132, 1201, 1273, 1347, 1417, 1496, 1577, 1661, 1729, 1817 }, |
| 545 | .M => &.{ 0, 8, 16, 26, 38, 52, 65, 75, 93, 111, 131, 155, 177, 204, 223, 254, 277, 310, 345, 384, 410, 438, 480, 528, 561, 614, 652, 692, 732, 778, 843, 894, 947, 1002, 1060, 1113, 1176, 1224, 1292, 1362, 1435 }, |
| 546 | .Q => &.{ 0, 7, 12, 20, 28, 37, 45, 53, 66, 80, 93, 109, 125, 149, 159, 180, 198, 224, 243, 272, 297, 314, 348, 376, 407, 440, 462, 496, 534, 559, 604, 634, 684, 719, 756, 790, 832, 876, 923, 972, 1024 }, |
| 547 | .H => &.{ 0, 4, 8, 15, 21, 27, 36, 39, 52, 60, 74, 85, 96, 109, 120, 136, 154, 173, 191, 208, 235, 248, 270, 284, 315, 330, 365, 385, 405, 430, 457, 486, 518, 553, 590, 605, 647, 673, 701, 750, 784 }, |
| 548 | }, |
| 549 | }; |
| 550 | } |
| 551 | |
| 552 | fn isNumeric(c: u8) bool { |
| 553 | return switch (c) { |
| 554 | '0'...'9' => true, |
| 555 | else => false, |
| 556 | }; |
| 557 | } |
| 558 | |
| 559 | fn isAlphanumeric(c: u8) bool { |
| 560 | return switch (c) { |
| 561 | '0'...'9' => true, |
| 562 | 'A'...'Z' => true, |
| 563 | ' ', '$', '%', '*', '+', '-', '.', '/', ':', ',' => true, |
| 564 | else => false, |
| 565 | }; |
| 566 | } |
| 567 | |
| 568 | fn generatorPolynomial(comptime n: usize) [n + 1]u8 { |
| 569 | if (n == 1) return .{ 1, 1 }; |
| 570 | |
| 571 | const prev = generatorPolynomial(n - 1); |
| 572 | const prev_alpha = to_alpha(prev); |
| 573 | const term_alpha: [2]u8 = .{ n - 1, 0 }; |
| 574 | |
| 575 | var multiply_alpha: [n * 2][2]u8 = @splat(@splat(0)); |
| 576 | for (&prev_alpha, 0..) |a, i| { |
| 577 | for (&term_alpha, 0..) |b, j| { |
| 578 | multiply_alpha[(term_alpha.len * i) + j] = .{ a + b, @intCast(i + j) }; |
| 579 | } |
| 580 | } |
| 581 | var combine_alpha: [n + 1]u8 = @splat(0); |
| 582 | for (0..n + 1) |i| { |
| 583 | for (&multiply_alpha) |el| { |
| 584 | if (el[1] == i) combine_alpha[i] ^= GF[el[0]]; |
| 585 | } |
| 586 | } |
| 587 | return combine_alpha; |
| 588 | } |
| 589 | |
| 590 | fn to_alpha(array: anytype) [array.len]u8 { |
| 591 | var result: [array.len]u8 = array; |
| 592 | for (&result) |*x| x.* = @intCast(std.mem.indexOfScalar(u8, &GF, x.*).?); |
| 593 | return result; |
| 594 | } |
| 595 | |
| 596 | fn formatPattern(level: Level, mask: u3) u15 { |
| 597 | return switch (level) { |
| 598 | .L => switch (mask) { |
| 599 | 0 => 0b111011111000100, |
| 600 | 1 => 0b111001011110011, |
| 601 | 2 => 0b111110110101010, |
| 602 | 3 => 0b111100010011101, |
| 603 | 4 => 0b110011000101111, |
| 604 | 5 => 0b110001100011000, |
| 605 | 6 => 0b110110001000001, |
| 606 | 7 => 0b110100101110110, |
| 607 | }, |
| 608 | .M => switch (mask) { |
| 609 | 0 => 0b101010000010010, |
| 610 | 1 => 0b101000100100101, |
| 611 | 2 => 0b101111001111100, |
| 612 | 3 => 0b101101101001011, |
| 613 | 4 => 0b100010111111001, |
| 614 | 5 => 0b100000011001110, |
| 615 | 6 => 0b100111110010111, |
| 616 | 7 => 0b100101010100000, |
| 617 | }, |
| 618 | .Q => switch (mask) { |
| 619 | 0 => 0b011010101011111, |
| 620 | 1 => 0b011000001101000, |
| 621 | 2 => 0b011111100110001, |
| 622 | 3 => 0b011101000000110, |
| 623 | 4 => 0b010010010110100, |
| 624 | 5 => 0b010000110000011, |
| 625 | 6 => 0b010111011011010, |
| 626 | 7 => 0b010101111101101, |
| 627 | }, |
| 628 | .H => switch (mask) { |
| 629 | 0 => 0b001011010001001, |
| 630 | 1 => 0b001001110111110, |
| 631 | 2 => 0b001110011100111, |
| 632 | 3 => 0b001100111010000, |
| 633 | 4 => 0b000011101100010, |
| 634 | 5 => 0b000001001010101, |
| 635 | 6 => 0b000110100001100, |
| 636 | 7 => 0b000100000111011, |
| 637 | }, |
| 638 | }; |
| 639 | } |
| 640 | |
| 641 | // |
| 642 | // |
| 643 | // |
| 644 | // |
| 645 | |
| 646 | const BufBiterator = struct { |
| 647 | buf: []const u8, |
| 648 | bits: std.bit_set.IntegerBitSet(8), |
| 649 | idx: u8, // buf index |
| 650 | jdx: u8, // bits index |
| 651 | |
| 652 | pub fn init(buf: []const u8) BufBiterator { |
| 653 | return .{ |
| 654 | .buf = buf, |
| 655 | .bits = .{ .mask = buf[0] }, |
| 656 | .idx = 0, |
| 657 | .jdx = 0, |
| 658 | }; |
| 659 | } |
| 660 | |
| 661 | pub fn next(self: *BufBiterator) ?u1 { |
| 662 | if (self.jdx == 8) { |
| 663 | self.jdx = 0; |
| 664 | self.idx += 1; |
| 665 | if (self.idx == self.buf.len) return null; |
| 666 | self.bits.mask = self.buf[self.idx]; |
| 667 | return self.next(); |
| 668 | } |
| 669 | const result = self.bits.isSet(7 - self.jdx); |
| 670 | self.jdx += 1; |
| 671 | return @intFromBool(result); |
| 672 | } |
| 673 | }; |
| 674 | |
| 675 | // |
| 676 | // |
| 677 | // |
| 678 | // |
| 679 | // |
| 680 | |
| 681 | const GridZigZag = struct { |
| 682 | grid_size: usize, |
| 683 | col_skip: usize, |
| 684 | dir: u1, |
| 685 | phase: u1, |
| 686 | y: usize, |
| 687 | x: usize, |
| 688 | |
| 689 | pub fn init(grid_size: usize, col_skip: usize) GridZigZag { |
| 690 | return .{ |
| 691 | .grid_size = grid_size, |
| 692 | .col_skip = col_skip, |
| 693 | .dir = 0, |
| 694 | .phase = 0, |
| 695 | .y = grid_size, |
| 696 | .x = grid_size - 2, |
| 697 | }; |
| 698 | } |
| 699 | |
| 700 | pub fn next(self: *@This()) ?usize { |
| 701 | blk: switch (self.dir) { |
| 702 | 0 => switch (self.phase) { //up |
| 703 | 0 => { //prev left |
| 704 | if (self.y == 0) { |
| 705 | self.x -= 1; |
| 706 | self.dir = 1; |
| 707 | self.phase = 1; |
| 708 | if (self.x == self.col_skip and self.col_skip == 0) return null; |
| 709 | if (self.x == self.col_skip) self.x -= 1; |
| 710 | break :blk; |
| 711 | } |
| 712 | self.y -= 1; |
| 713 | self.x += 1; |
| 714 | self.phase +%= 1; |
| 715 | }, |
| 716 | 1 => { //prev right |
| 717 | self.x -= 1; |
| 718 | self.phase +%= 1; |
| 719 | }, |
| 720 | }, |
| 721 | 1 => switch (self.phase) { //down |
| 722 | 0 => { //prev left |
| 723 | if (self.y == self.grid_size - 1) { |
| 724 | if (self.x == 0) return null; |
| 725 | self.x -= 1; |
| 726 | if (self.x == self.col_skip and self.col_skip == 0) return null; |
| 727 | if (self.x == self.col_skip) self.x -= 1; |
| 728 | self.dir = 0; |
| 729 | self.phase = 1; |
| 730 | break :blk; |
| 731 | } |
| 732 | self.x += 1; |
| 733 | self.y += 1; |
| 734 | self.phase +%= 1; |
| 735 | }, |
| 736 | 1 => { //prev right |
| 737 | self.x -= 1; |
| 738 | self.phase +%= 1; |
| 739 | }, |
| 740 | }, |
| 741 | } |
| 742 | return (self.y * self.grid_size) + self.x; |
| 743 | } |
| 744 | }; |