Skip to content

Commit cd2769b

Browse files
authored
Add files via upload
1 parent 0978dac commit cd2769b

File tree

4 files changed

+288
-1
lines changed

4 files changed

+288
-1
lines changed

Zig/build.bat

+2-1
Original file line numberDiff line numberDiff line change
@@ -1 +1,2 @@
1-
1+
@echo off
2+
zig build-exe -O ReleaseFast sudoku.zig

Zig/grid.zig

+256
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,256 @@
1+
const std = @import("std");
2+
3+
var grid = [_]u8{0} ** 81; // Sudoku grid stored linearly here
4+
5+
const matrix = fill9x9: { // matrix array allows accessing a
6+
var m : [9][*]u8 = undefined; // grid element as a matrix, giving
7+
var pt : [*]u8 = &grid; // i and j: element = matrix[i][j]
8+
for (0..9) |i| { //
9+
m[i] = pt; // stores the pointers of each line
10+
pt += 9; // at each position of matrix array
11+
} //
12+
break :fill9x9 m; // initializes matrix array with m
13+
}; //
14+
15+
var lines = [_]u9{0} ** 9; // all elements present in each line
16+
var columns = [_]u9{0} ** 9; // all elements present in each column
17+
var cells = [_]u9{0} ** 9; // all elements present in each cell
18+
// i' = cindx[i],
19+
// j' = cindx[j]
20+
// cell[i'][j'] = elements in the cell of element in matrix[i][j]
21+
const cindx = [_]usize{ 0,0,0, 1,1,1, 2,2,2 };
22+
23+
const cell = fill3x3: { // cell array allows accessing all elements
24+
var m : [3][*]u9 = undefined; // present in a cell using cells as a matrix,
25+
var pt : [*]u9 = &cells; // in this way: cell[cindx[i]][cindx[j]]
26+
for (0..3) |i| { //
27+
m[i] = pt; // stores the pointers of each line
28+
pt += 3; // at each position of cell array
29+
} //
30+
break :fill3x3 m; // initializes cell array with m
31+
}; //
32+
33+
const c1 = [_]u8{ 0, 1, 2, 0, 3 };
34+
const c2 = [_]u8{ 0, 4, 5, 0, 6 };
35+
const c3 = [_]u8{ 0, 7, 8, 0, 9 };
36+
37+
fn reinit() void { // reinitilizes lines, columns and cells
38+
for (0..9) |i| {
39+
lines[i] = 0;
40+
columns[i] = 0;
41+
cells[i] = 0;
42+
}
43+
}
44+
45+
//
46+
// sets a new grid giving all elements line by line in a string
47+
//
48+
49+
pub fn set( s : [:0]const u8 ) void {
50+
var k : usize = 0;
51+
var code : u9 = undefined;
52+
var c : u4 = undefined;
53+
var line : [*]u8 = undefined;
54+
reinit(); // resets data structures to allow several sets
55+
for ( 0..9 ) |i| {
56+
line = matrix[i];
57+
for ( 0..9 ) |j| {
58+
c = @intCast(s[k]-'0');
59+
if (s[k] == '.') c = 0;
60+
if (c != 0) {
61+
code = @as(u9,1) << (c-1);
62+
// check if there is no error before inserting
63+
if (((lines[i]|columns[j]|cell[cindx[i]][cindx[j]]) & code) != 0 ) {
64+
std.debug.print("*** Duplicate digit {} at position {}, line {}, column {}\n", .{c, k, i, j});
65+
unreachable;
66+
}
67+
lines[i] |= code;
68+
columns[j] |= code;
69+
cell[cindx[i]][cindx[j]] |= code;
70+
}
71+
line[j] = c;
72+
k+= 1;
73+
}
74+
}
75+
}
76+
77+
//
78+
// prints the grid on the console
79+
//
80+
81+
pub fn print() void {
82+
var line : [*]u8 = undefined;
83+
var c : u8 = undefined;
84+
for ( 0..9 ) |i| {
85+
line = matrix[i];
86+
std.debug.print("|",.{});
87+
for ( 0..9 ) |j| {
88+
c = line[j];
89+
c = if (c == 0) ' ' else (c + 48);
90+
std.debug.print("{c}|", .{c});
91+
}
92+
std.debug.print("\n",.{});
93+
}
94+
}
95+
96+
test " => testing set and print functions" {
97+
set("800000000003600000070090200050007000000045700000100030001000068008500010090000400");
98+
std.debug.print("\n===================\n Input Grid\n===================\n", .{});
99+
print();
100+
}
101+
102+
103+
// simple and fast implementation of a stack for backtracking
104+
const StkNode = packed struct {
105+
code: u16,
106+
i: u8,
107+
j: u8
108+
};
109+
110+
const Stack = struct {
111+
stk: [81]StkNode,
112+
pt: isize,
113+
114+
pub fn init() Stack {
115+
return Stack {
116+
.stk = undefined,
117+
.pt = -1,
118+
};
119+
}
120+
121+
pub fn size(self: *Stack) isize { // for testing purposes
122+
return self.pt + 1;
123+
}
124+
125+
pub fn reset(self: *Stack) void {
126+
self.pt = -1;
127+
}
128+
129+
pub fn push(self: *Stack, i: u8, j: u8, code: u16) callconv(.Inline) void {
130+
self.pt += 1;
131+
self.stk[@intCast(self.pt)] = .{
132+
.i = i,
133+
.j = j,
134+
.code = code,
135+
};
136+
//@prefetch(&matrix[i][j], .{.rw = .write, .locality = 0, .cache = .data});
137+
matrix[i][j] = c1[code&7]|c2[(code>>3)&7]|c3[code>>6];
138+
const code9 : u9 = @intCast(code);
139+
//@prefetch(&lines[i], .{.rw = .write, .locality = 0, .cache = .data});
140+
lines[i] |= code9;
141+
//@prefetch(&columns[j], .{.rw = .write, .locality = 0, .cache = .data});
142+
columns[j] |= code9;
143+
cell[cindx[i]][cindx[j]] |= code9;
144+
//cell[(i+@popCount(i))>>2][(j+@popCount(j))>>2] |= code9;
145+
}
146+
147+
pub fn pop(self: *Stack) callconv(.Inline) *StkNode {
148+
const node = &self.stk[@intCast(self.pt)];
149+
const i = node.i;
150+
const j = node.j;
151+
const code9 : u9 = ~@as(u9,@truncate(node.code));
152+
//@prefetch(&matrix[i][j], .{.rw = .write, .locality = 0, .cache = .data});
153+
matrix[i][j] = 0;
154+
//@prefetch(&lines[i], .{.rw = .write, .locality = 0, .cache = .data});
155+
lines[i] &= code9;
156+
//@prefetch(&columns[j], .{.rw = .write, .locality = 0, .cache = .data});
157+
columns[j] &= code9;
158+
cell[cindx[i]][cindx[j]] &= code9;
159+
//cell[(i+@popCount(i))>>2][(j+@popCount(j))>>2] &= code9;
160+
self.pt -= 1;
161+
return node;
162+
}
163+
};
164+
165+
var stack = Stack.init();
166+
167+
test " => testing push and pop functions" {
168+
std.debug.print("\nelement ({},{}) = {}\n", .{2, 0, matrix[2][0]});
169+
std.debug.print("elements in line {b}\n", .{lines[2]});
170+
std.debug.print("elements in column {b}\n", .{columns[0]});
171+
std.debug.print("elements in cell {b}\n", .{cell[0][0]});
172+
std.debug.print("stack size {}\n", .{ stack.size() });
173+
stack.push(2,0,0b1000);
174+
std.debug.print("\n=> ***push executed***\n\n", .{});
175+
std.debug.print("===================\n Changed Grid\n===================\n", .{});
176+
print();
177+
std.debug.print("\nelement ({},{}) = {}\n", .{2, 0, matrix[2][0]});
178+
std.debug.print("code pushed {b}\n", .{0b1000});
179+
std.debug.print("elements in line {b}\n", .{lines[2]});
180+
std.debug.print("elements in column {b}\n", .{columns[0]});
181+
std.debug.print("elements in cell {b}\n", .{cell[0][0]});
182+
std.debug.print("stack size {}\n", .{ stack.size() });
183+
const node = stack.pop();
184+
std.debug.print("\n=> ***pop executed***\n\n", .{});
185+
std.debug.print("element ({},{}) = {}\n", .{node.i, node.j, matrix[2][0]});
186+
std.debug.print("code poped {b}\n", .{node.code});
187+
std.debug.print("elements in line {b}\n", .{lines[node.i]});
188+
std.debug.print("elements in column {b}\n", .{columns[node.j]});
189+
std.debug.print("elements in cell {b}\n", .{cell[0][0]});
190+
std.debug.print("stack size {}\n", .{ stack.size() });
191+
}
192+
193+
pub fn solve() void {
194+
var node : *StkNode = undefined;
195+
var code : u16 = 1;
196+
var inserted : u16 = undefined;
197+
var j : u8 = 0;
198+
var i : u8 = 0;
199+
var line : [*]u8 = matrix[0];
200+
var li : u16 = lines[0];
201+
var ci : [*]u9 = cell[0];
202+
var c : u8 = undefined;
203+
@prefetch(&line[0], .{.rw = .read, .locality = 0, .cache = .data});
204+
while (true) {
205+
c = line[j];
206+
if ( c == 0 ) { // jump over non empty elements
207+
// "inserted" is the occupation set, the inverse of the candidate set
208+
inserted = li|columns[j]|(ci[cindx[j]]);
209+
// if adding candidate with occupation set overflows -> no candidate
210+
if ( (inserted + code ) >= 512 ) {// backtrack if there isn't any candidate
211+
node = stack.pop(); // pop previous inserted i, j, and code
212+
i = node.i;
213+
j = node.j;
214+
line = matrix[i]; // line might have changed
215+
ci = cell[cindx[i]];
216+
//ci = cell[(i+@popCount(i))>>2];
217+
li = lines[i];
218+
code = (node.code) << 1; // get next candidate
219+
@prefetch(&line[j], .{.rw = .read, .locality = 0, .cache = .data});
220+
continue; // short-circuits line by line logic
221+
}
222+
// chosen candidate is the next empty place in the occupation set
223+
code = (((inserted + code ) ^ inserted) + code) >> 1;
224+
stack.push(i, j, code); // store and save candidate
225+
li |= code;
226+
code = 1; // next candidate starts with 1
227+
}
228+
if ( j == 8 ) { // reached last element in the line
229+
if ( i == 8 ) break; // reached last element -> exit
230+
i += 1; // go to the next line
231+
j = 0; // starts with first element in the line
232+
line = matrix[i]; // update line from grid matrix
233+
ci = cell[cindx[i]]; // update cell helper
234+
li = lines[i]; // update lines helper
235+
continue;
236+
}
237+
j += 1; // next element in the line
238+
@prefetch(&line[j], .{.rw = .read, .locality = 0, .cache = .data});
239+
}
240+
stack.reset();
241+
}
242+
243+
244+
//pub fn main() !void {
245+
// set("800000000003600000070090200050007000000045700000100030001000068008500010090000400");
246+
// std.debug.print("\n===================\n Input Grid\n===================\n", .{});
247+
// print();
248+
// var timer = try std.time.Timer.start();
249+
// solve();
250+
// const time_0 : u64 = timer.read();
251+
// std.debug.print("\n===================\n Solution\n===================\n", .{});
252+
// print();
253+
// @setFloatMode(.Optimized);
254+
// const ftime = @as(f64,@floatFromInt(time_0))/1000000.0;
255+
// std.debug.print("\ntime in milliseconds: {d:.5}", .{ftime} );
256+
//}

Zig/sudoku.exe

184 KB
Binary file not shown.

Zig/sudoku.zig

+30
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
const std = @import("std");
2+
const grid = @import("grid.zig");
3+
4+
pub fn main() !void {
5+
// Get allocator
6+
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
7+
const allocator = gpa.allocator();
8+
defer _ = gpa.deinit();
9+
10+
// Parse args into string array (error union needs 'try')
11+
const args = try std.process.argsAlloc(allocator);
12+
defer std.process.argsFree(allocator, args);
13+
14+
if ((args.len > 1) and (args[1].len == 81)) {
15+
grid.set(args[1]);
16+
}
17+
else {
18+
grid.set("800000000003600000070090200050007000000045700000100030001000068008500010090000400");
19+
}
20+
std.debug.print("\n===================\n Input Grid\n===================\n", .{});
21+
grid.print();
22+
var timer = try std.time.Timer.start();
23+
grid.solve();
24+
const time_0 : u64 = timer.read();
25+
std.debug.print("\n===================\n Solution\n===================\n", .{});
26+
grid.print();
27+
@setFloatMode(.Optimized);
28+
const ftime = @as(f64,@floatFromInt(time_0))/1000000.0;
29+
std.debug.print("\ntime in milliseconds: {d:.5}", .{ftime} );
30+
}

0 commit comments

Comments
 (0)