Skip to content

Commit

Permalink
implement backtracking solver
Browse files Browse the repository at this point in the history
  • Loading branch information
revolt3245 committed Nov 10, 2023
1 parent f8d4002 commit 591c1db
Show file tree
Hide file tree
Showing 7 changed files with 310 additions and 61 deletions.
4 changes: 2 additions & 2 deletions BnW_Picross/Test3/+Draw/initialize.m
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,7 @@
FontWeight='bold', ...
HorizontalAlignment='center', ...
FontUnits='centimeters', ...
FontSize=grid_size/3);
FontSize=grid_size/2);
end
end

Expand All @@ -129,7 +129,7 @@
FontWeight='bold', ...
HorizontalAlignment='center', ...
FontUnits='centimeters', ...
FontSize=grid_size/3);
FontSize=grid_size/2);
end
end

Expand Down
49 changes: 49 additions & 0 deletions BnW_Picross/Test3/+Solver/backtrack_solver.asv
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
function [state, flag] = backtrack_solver(param, state, graphics)
%% find minimum line
line_num = 0;
min_n_line = inf;
for i = 1:(param.n_row + param.n_col)
if i <= param.n_row
if(any(state.row_const{i}) && (min_n_line > state.n_lines(i)))
min_n_line = state.n_lines(i);
line_num = i;
end
else
if (any(state.col_const{i-param.n_row}) && (min_n_line > state.n_lines(i)))
min_n_line = state.n_lines(i);
line_num = i;
end
end
end

%% solver
gl_bound = state.bounds(1, line_num);
gh_bound = state.bounds(2, line_num);
cl_bound = state.bounds(3, line_num);
ch_bound = state.bounds(4, line_num);
state_temp = state;
if cl_bound == ch_bound
line_width = gh_bound - gl_bound + 1;
first_clue = param.row_const{line_num}(cl_bound);
upper_bound = line_width - first_clue;

for i=1:upper_bound
if i == 1
t_line = ones(1, line_width, 'uint8');
t_line(1:first_clue) = uint8(3);
else
t_line(i-1) = 1;
t_line(i+first_clue-1) = 3;
end

state_temp.board(line_num, gl_bound:gh_bound) = t_line;
[state_temp, flag] = Solver.branch_solver(param, state_temp, graphics);

if ~flag
state_temp = state;
end

end
else
end
end
162 changes: 162 additions & 0 deletions BnW_Picross/Test3/+Solver/backtrack_solver.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,162 @@
function [state, flag] = backtrack_solver(param, state, graphics)
%% find minimum line
line_num = 0;
min_n_line = inf;
for i = 1:(param.n_row + param.n_col)
if i <= param.n_row
if(any(state.row_const{i}) && (min_n_line > state.n_lines(i)))
min_n_line = state.n_lines(i);
line_num = i;
end
else
if (any(state.col_const{i-param.n_row}) && (min_n_line > state.n_lines(i)))
min_n_line = state.n_lines(i);
line_num = i;
end
end
end

%% solver
gl_bound = state.bounds(1, line_num);
gh_bound = state.bounds(2, line_num);
cl_bound = state.bounds(3, line_num);
ch_bound = state.bounds(4, line_num);
state_temp = state;
if cl_bound == ch_bound
if line_num <= param.n_row
line_width = gh_bound - gl_bound + 1;
first_clue = param.row_const{line_num}(cl_bound);
upper_bound = line_width - first_clue;

for i=1:upper_bound
if i == 1
t_line = ones(1, line_width, 'uint8');
t_line(1:first_clue) = uint8(2);
else
t_line(i-1) = 1;
t_line(i+first_clue-1) = 2;
end

if any(bitand(state_temp.board(line_num, gl_bound:gh_bound), t_line) == 0)
flag = false;
break;
end
state_temp.board(line_num, gl_bound:gh_bound) = t_line;
[state_temp, flag] = Solver.branch_solver(param, state_temp, graphics);

if flag && ~Util.check_all_complete(param, state_temp)
[state_temp, flag] = Solver.backtrack_solver(param, state_temp, graphics);
end

if ~flag
state_temp = state;
else
state = state_temp;
return
end
end
else
line_width = gh_bound - gl_bound + 1;
first_clue = param.col_const{line_num-param.n_row}(cl_bound);
upper_bound = line_width - first_clue;

for i=1:upper_bound
if i == 1
t_line = ones(line_width, 1, 'uint8');
t_line(1:first_clue) = uint8(2);
else
t_line(i-1) = 1;
t_line(i+first_clue-1) = 2;
end

if any(bitand(state_temp.board(gl_bound:gh_bound, line_num-param.n_row), t_line) == 0)
flag = false;
break;
end
state_temp.board(gl_bound:gh_bound, line_num-param.n_row) = t_line;
[state_temp, flag] = Solver.branch_solver(param, state_temp, graphics);

if flag && ~Util.check_all_complete(param, state_temp)
[state_temp, flag] = Solver.backtrack_solver(param, state_temp, graphics);
end

if ~flag
state_temp = state;
else
state = state_temp;
return
end
end
end
else
if line_num <= param.n_row
line_width = gh_bound - gl_bound + 1;
first_clue = param.row_const{line_num}(cl_bound);
upper_bound = line_width - sum(param.row_const{line_num}(cl_bound:ch_bound)) - size(param.row_const{line_num}) + 2;

for i=1:upper_bound
if i == 1
t_line = ones(1, first_clue+1, 'uint8');
t_line(1:first_clue) = uint8(2);
else
t_line(i-1) = 1;
t_line(i+first_clue-1) = 2;
t_line(i+first_clue) = 1;
end

if any(bitand(state_temp.board(line_num, gl_bound:gl_bound+first_clue+i-1), t_line) == 0)
flag = false;
break;
end

state_temp.board(line_num, gl_bound:gl_bound+first_clue+i-1) = t_line;
[state_temp, flag] = Solver.branch_solver(param, state_temp, graphics);

if flag && ~Util.check_all_complete(param, state_temp)
[state_temp, flag] = Solver.backtrack_solver(param, state_temp, graphics);
end

if ~flag
state_temp = state;
else
state = state_temp;
return
end
end
else
line_width = gh_bound - gl_bound + 1;
first_clue = param.col_const{line_num-param.n_row}(cl_bound);
upper_bound = line_width - sum(param.col_const{line_num - param.n_row}) - size(param.col_const{line_num-param.n_row}) + 2;

for i=1:upper_bound
if i == 1
t_line = ones(first_clue+1, 1, 'uint8');
t_line(1:first_clue) = uint8(2);
else
t_line(i-1) = 1;
t_line(i+first_clue-1) = 2;
t_line(i+first_clue) = 1;
end

if any(bitand(state_temp.board(gl_bound:gl_bound+first_clue+i-1, line_num-param.n_row), t_line) == 0)
flag = false;
break;
end

state_temp.board(gl_bound:gl_bound+first_clue+i-1, line_num-param.n_row) = t_line;
[state_temp, flag] = Solver.branch_solver(param, state_temp, graphics);

if flag && ~Util.check_all_complete(param, state_temp)
[state_temp, flag] = Solver.backtrack_solver(param, state_temp, graphics);
end

if ~flag
state_temp = state;
else
state = state_temp;
return
end
end
end
end
end
67 changes: 25 additions & 42 deletions BnW_Picross/Test3/+Solver/branch_solver.m
Original file line number Diff line number Diff line change
@@ -1,29 +1,12 @@
function [state, flag] = branch_solver(param, state, graphics)
%% solving
n_lines = zeros(1, param.n_row + param.n_col);
bounds = [ones(1, param.n_row+param.n_col)
param.n_col*ones(1,param.n_row) param.n_row*ones(1,param.n_col)
ones(1, param.n_row+param.n_col)
zeros(1, param.n_row + param.n_col)];

for i = 1:(param.n_col + param.n_row)
if i <= param.n_row
n_lines(i) = Util.get_possible_lines_memo(param.n_col, param.row_const{i});
bounds(4, i) = size(param.row_const{i}, 2);
else
n_lines(i) = Util.get_possible_lines_memo(param.n_row, param.col_const{i-param.n_row});
bounds(4, i) = size(param.col_const{i-param.n_row}, 2);
end
end

is_in_queue = true(1, param.n_row + param.n_col);

[pq_lines, pq_ind] = sort(n_lines, 2);
[pq_lines, pq_ind] = sort(state.n_lines, 2);
pq = [pq_lines
pq_ind
bounds(:, pq_ind)];
state.bounds(:, pq_ind)];

tic;
while any(is_in_queue)
%% pop minimum line
pq_top = pq(:,1);
Expand All @@ -44,7 +27,7 @@

if(any(o_line == 0))
flag = false;
break;
return;
end

changed = o_line ~= i_line;
Expand All @@ -55,9 +38,9 @@
new_ind = 1:(param.n_row+param.n_col);
new_ind = new_ind(has_to_push);

new_n_lines = n_lines(has_to_push);
new_n_lines = state.n_lines(has_to_push);

pq = [pq [new_n_lines; new_ind; bounds(:, new_ind)]];
pq = [pq [new_n_lines; new_ind; state.bounds(:, new_ind)]];

[~, pq_ind] = sort(pq(1,:));
pq = pq(1:end,pq_ind);
Expand All @@ -69,12 +52,12 @@
state.board(ind_top,gl_bound:gh_bound) = o_line;

%% bound n_lines update
new_gl_bound = bounds(1, ind_top) + find(o_line == uint8(3), 1, 'first')-1;
new_gh_bound = bounds(1, ind_top) + find(o_line == uint8(3), 1, 'last')-1;
new_gl_bound = state.bounds(1, ind_top) + find(o_line == uint8(3), 1, 'first')-1;
new_gh_bound = state.bounds(1, ind_top) + find(o_line == uint8(3), 1, 'last')-1;

if ~isempty(new_gl_bound) && ~isempty(new_gh_bound)
bounds(1, ind_top) = new_gl_bound;
bounds(2, ind_top) = new_gh_bound;
state.bounds(1, ind_top) = new_gl_bound;
state.bounds(2, ind_top) = new_gh_bound;

if new_gl_bound ~= gl_bound && ~isempty(new_gl_bound)
o_line_l = o_line(1:(new_gl_bound-gl_bound));
Expand All @@ -83,7 +66,7 @@
check_l = [o_line_l(1) == 2 check_l];

new_cl_bound = cl_bound + sum(check_l);
bounds(3, ind_top) = new_cl_bound;
state.bounds(3, ind_top) = new_cl_bound;

state.row_const{ind_top}(1:new_cl_bound-1) = false;
end
Expand All @@ -96,16 +79,16 @@

new_ch_bound = ch_bound - sum(check_h);

bounds(4, ind_top) = new_ch_bound;
state.bounds(4, ind_top) = new_ch_bound;

state.row_const{ind_top}(new_ch_bound+1:end) = false;
end

s_lines = bounds(2, ind_top) - bounds(1, ind_top)+1;
s_clues = bounds(4, ind_top) - bounds(3, ind_top)+1;
s_lines = state.bounds(2, ind_top) - state.bounds(1, ind_top)+1;
s_clues = state.bounds(4, ind_top) - state.bounds(3, ind_top)+1;

new_clues = param.row_const{ind_top}(state.row_const{ind_top});
n_lines(ind_top) = Util.get_possible_lines(s_lines, new_clues);
state.n_lines(ind_top) = Util.get_possible_lines(s_lines, new_clues);
else
state.row_const{ind_top}(:) = false;
end
Expand All @@ -116,7 +99,7 @@

if(any(o_line == 0))
flag = false;
break;
return;
end

changed = o_line ~= i_line;
Expand All @@ -130,9 +113,9 @@
new_ind = 1:(param.n_row+param.n_col);
new_ind = new_ind(has_to_push);

new_n_lines = n_lines(has_to_push);
new_n_lines = state.n_lines(has_to_push);

pq = [pq [new_n_lines; new_ind; bounds(:, new_ind)]];
pq = [pq [new_n_lines; new_ind; state.bounds(:, new_ind)]];

[pq_lines, pq_ind] = sort(pq(1,:));
pq = pq(:,pq_ind);
Expand All @@ -148,8 +131,8 @@
new_gh_bound = gl_bound + find(o_line == uint8(3), 1, 'last')-1;

if ~isempty(new_gl_bound) && ~isempty(new_gh_bound)
bounds(1, ind_top) = new_gl_bound;
bounds(2, ind_top) = new_gh_bound;
state.bounds(1, ind_top) = new_gl_bound;
state.bounds(2, ind_top) = new_gh_bound;

if new_gl_bound ~= gl_bound && ~isempty(new_gl_bound)
o_line_l = o_line(1:(new_gl_bound-gl_bound));
Expand All @@ -159,7 +142,7 @@
check_l];

new_cl_bound = cl_bound + sum(check_l);
bounds(3, ind_top) = new_cl_bound;
state.bounds(3, ind_top) = new_cl_bound;

state.col_const{ind_top-param.n_row}(1:new_cl_bound-1) = false;
end
Expand All @@ -173,19 +156,19 @@

new_ch_bound = ch_bound - sum(check_h);

bounds(4, ind_top) = new_ch_bound;
state.bounds(4, ind_top) = new_ch_bound;
state.col_const{ind_top-param.n_row}(new_ch_bound+1:end) = false;
end

s_lines = bounds(2, ind_top) - bounds(1, ind_top)+1;
s_clues = bounds(4, ind_top) - bounds(3, ind_top)+1;
s_lines = state.bounds(2, ind_top) - state.bounds(1, ind_top)+1;
s_clues = state.bounds(4, ind_top) - state.bounds(3, ind_top)+1;
new_clues = param.col_const{ind_top-param.n_row}(state.col_const{ind_top-param.n_row});
n_lines(ind_top) = Util.get_possible_lines(s_lines, new_clues);
state.n_lines(ind_top) = Util.get_possible_lines(s_lines, new_clues);
else
state.col_const{ind_top-param.n_row}(:)=false;
end
end
state.time = toc;
state.time = toc(state.tick);

Draw.update(graphics, state, param);
drawnow;
Expand Down
Loading

0 comments on commit 591c1db

Please sign in to comment.