Pattern Overlay Method

Advanced methods and approaches for solving Sudoku puzzles

Re: Pattern Overlay Method

Postby rjamil » Thu Feb 06, 2025 7:43 pm

Hi P.O.,

First of all, thanks for your quick and detail reply.

P.O. wrote:
rjamil wrote:Similarly, it did not mentioned to check all templates of one digit against one of the template of another digit for validity.

Ruud's algorithm does this operation, first post here:
"My program keeps a library of all 46656 configuration templates, and maintains a list for each of the 9 values.
When a cell is filled, the list is filtered to the templates that contain that value at the cell's position.
When a cell is blocked for a value, all templates containing that value at the cell's position are removed from the list."

If I understand correctly, Ruud copy all 46656 templates in to some kind of an array (either linked list or memory allocation). Then start filling the sudoku grid one by one cell. Now, for each digit, remove templates from copied array if they did not contain that cell for particular digit. This process repeats 81 times for each digit. Imagine, if a particular digit did not present at r1c1 position, the process is removing 5184 templates from array. If it did not present at r1c2345678 positions then it will remove further 7 x 5184 templates respectively. Similarly, for each cell position in row 2, if particular digit did not present then remove 864 templates from array. And so on. At last, remaining template counting will be enough to eliminate/place a digit from/to cell. Similarly, read angusj doubt (being Site Admin) in fifth post.

Similarly, showing all possible templates are not necessary. Only count valid templates are enough to place/eliminate the digit from all/none count cell(s).

here is another list of 17c puzzles that i classify as 2-template and solve with more than one size 2 combination, i would be interested to know if your double-digit POM implementation solves them all

Find my results as, total 71 out of 139 puzzles solved without guessing.

R. Jamil
rjamil
 
Posts: 810
Joined: 15 October 2014
Location: Karachi, Pakistan

Re: Pattern Overlay Method

Postby P.O. » Sat Feb 08, 2025 11:46 am

hi R.Jamil, i checked some of your results and here is a reason why your template implementation does not solve more puzzles
i'll take puzzle #4544 as an example, but all the ones i've checked show the same phenomenon
Code: Select all
.  .  .  .  .  .  .  .  .
.  .  .  .  .  .  .  1  2
.  .  3  .  .  4  .  .  .
.  .  .  .  .  .  5  .  .
.  .  .  .  1  .  .  .  .
.  6  4  3  .  .  7  .  .
.  .  .  .  .  8  4  9  .
.  7  .  .  .  .  .  .  .
2  1  .  .  5  .  .  .  .

................12..3..4.........5......1.....643..7.......849..7.......21..5....

( n1r8c7   n2r8c8   n2r5c7   n4r9c4   n4r8c1   n8r6c8   n1r7c4
  n1r1c6   n2r7c5   n4r4c5   n4r2c2   n7r9c6   n7r7c9   n9r9c3
  n9r6c5   n1r6c9   n5r6c1   n2r6c6   n6r4c6   n3r4c8   n9r4c9
  n5r5c6   n6r9c8   n4r5c8   n6r5c9   n1r4c3   n1r3c1   n2r4c2
  n2r1c3   n4r1c9   n5r8c9   n8r8c3   n8r3c9   n7r5c3   n8r5c4
  n3r9c9   n8r4c1   n7r4c4   n8r9c7   n2r3c4   n8r2c5   n8r1c2
  n7r2c1 )

69   8    2    569  367  1    369  57   4             
7    4    56   569  8    39   369  1    2             
1    59   3    2    67   4    69   57   8             
8    2    1    7    4    6    5    3    9             
39   39   7    8    1    5    2    4    6             
5    6    4    3    9    2    7    8    1             
36   35   56   1    2    8    4    9    7             
4    7    8    69   36   39   1    2    5             
2    1    9    4    5    7    8    6    3             
47 candidates.

after initializing the puzzle here is the resolution state (and i don't really understand why you edit a pm after each single)
single-digit POM gives nothing so you check the 36 combinations of size 2 with the following templates
Code: Select all
#1: ((6 17 19 30 41 54 58 70 74))

#2: ((3 18 22 29 43 51 59 71 73))
 
#3: ((7 15 21 35 38 49 55 68 81) (7 15 21 35 37 49 56 68 81)
     (5 16 21 35 38 49 55 69 81) (5 16 21 35 37 49 56 69 81))
     
#4: ((9 11 24 32 44 48 61 64 76))

#5: ((8 13 20 34 42 46 57 72 77) (4 12 26 34 42 46 56 72 77))

#6: ((7 12 23 33 45 47 55 67 80) (5 12 25 33 45 47 55 67 80)
     (4 12 25 33 45 47 55 68 80) (1 16 23 33 45 47 57 67 80)
     (1 13 25 33 45 47 57 68 80))
     
#7: ((8 10 23 31 39 52 63 65 78) (5 10 26 31 39 52 63 65 78))

#8: ((2 14 27 28 40 53 60 66 79))

#9: ((7 15 20 36 37 50 62 67 75) (7 13 20 36 37 50 62 69 75)
     (4 16 20 36 37 50 62 69 75) (1 15 25 36 38 50 62 67 75)
     (1 13 25 36 38 50 62 69 75))

there are only 3 combinations that eliminate templates:
Code: Select all
(3 9)
#VT: (1 1 4 1 2 5 2 1 4)
Cells: nil nil nil nil nil nil nil nil nil
Candidates:nil nil nil nil nil nil nil nil nil

(5 9)
#VT: (1 1 4 1 2 5 2 1 4)
Cells: nil nil nil nil nil nil nil nil nil
Candidates:nil nil nil nil nil nil nil nil (4 16)

(6 9)
#VT: (1 1 4 1 2 5 2 1 4)
Cells: nil nil nil nil nil nil nil nil nil
Candidates:nil nil nil nil nil nil nil nil nil

each of these three combinations removes one template for 9 but only one of them (5 9) has immediate consequences on the candidates, it leads to the elimination of 9 from r1c4 and r2c7 (cells 4 and 16), you find it and do the eliminations:
Code: Select all
Double-digit POM: 9 in r1c147 r2c467 r3c27 r4c9 r5c12 r6c5 r7c8 r8c46 r9c3
         and POM: 5 in r1c48 r2c34 r3c28 r4c7 r5c6 r6c1 r7c23 r8c9 r9c5
Digit 9 not in 4 Templates => -9 @ r1c4 r2c7

i guess you check the combinations again but you don't find anything more

but the template for 9 that the combination (6 9) eliminates has consequences on the combination (5 9), with this template less it realizes the placement of 5 in the cells (4 12 26 56) and solves the puzzle
Hidden Text: Show
Code: Select all
(6 9): 9 instances
...9..6....6...9...9..6.........6..99.......6.6..9....6......9....6.9.....9....6.
9.....6....69.........6.9.......6..9.9......6.6..9....6......9....6.9.....9....6.
....6.9....69......9....6.......6..99.......6.6..9....6......9....6.9.....9....6.
...96......6...9...9....6.......6..99.......6.6..9....6......9....6.9.....9....6.
...6..9....6..9....9....6.......6..99.......6.6..9....6......9....96......9....6.
...6..9....69......9....6.......6..99.......6.6..9....6......9.....69.....9....6.
6.....9.....9..6...9..6.........6..99.......6.6..9......6....9....6.9.....9....6.
6.....9.....6.9....9....6.......6..99.......6.6..9......6....9....96......9....6.
6..9........6..9...9....6.......6..99.......6.6..9......6....9.....69.....9....6.

......6....6..........6.........6...........6.6.......6...........6............6.
....6......6............6.......6...........6.6.......6...........6............6.
...6.......6............6.......6...........6.6.......6............6...........6.
6..............6......6.........6...........6.6.........6.........6............6.
6...........6...........6.......6...........6.6.........6..........6...........6.

......9.......9....9...............99............9...........9....9.......9......
......9.....9......9...............99............9...........9......9.....9......
...9...........9...9...............99............9...........9......9.....9......
9...........9...........9..........9.9...........9...........9......9.....9......

#VT: (1 1 4 1 2 5 2 1 4)
Cells: nil nil nil nil nil nil nil nil nil
Candidates:nil nil nil nil nil nil nil nil nil

69   8    2    569  367  1    369  57   4             
7    4    56   569  8    39   369  1    2             
1    59   3    2    67   4    69   57   8             
8    2    1    7    4    6    5    3    9             
39   39   7    8    1    5    2    4    6             
5    6    4    3    9    2    7    8    1             
36   35   56   1    2    8    4    9    7             
4    7    8    69   36   39   1    2    5             
2    1    9    4    5    7    8    6    3             
47 candidates.

(5 9): 3 instances
...5..9....5..9....9.....5.......5.99....5...5...9.....5.....9....9....5..9.5....
...5..9....59......9.....5.......5.99....5...5...9.....5.....9......9..5..9.5....
9..5.......59...........95.......5.9.9...5...5...9.....5.....9......9..5..9.5....

...5.......5.............5.......5.......5...5.........5...............5....5....

......9.......9....9...............99............9...........9....9.......9......
......9.....9......9...............99............9...........9......9.....9......
9...........9...........9..........9.9...........9...........9......9.....9......

#VT: (1 1 4 1 1 5 2 1 3)
Cells: nil nil nil nil (4 12 26 56) nil nil nil nil
SetVC: ( n5r1c4   n7r1c8   n5r2c3   n9r3c2   n6r3c7   n5r3c8
         n3r5c2   n5r7c2   n6r7c3   n6r1c1   n3r1c5   n9r1c7
         n9r2c6   n3r2c7   n7r3c5   n9r5c1   n3r7c1   n6r8c5
         n3r8c6   n6r2c4   n9r8c4 )
6 8 2   5 3 1   9 7 4
7 4 5   6 8 9   3 1 2
1 9 3   2 7 4   6 5 8
8 2 1   7 4 6   5 3 9
9 3 7   8 1 5   2 4 6
5 6 4   3 9 2   7 8 1
3 5 6   1 2 8   4 9 7
4 7 8   9 6 3   1 2 5
2 1 9   4 5 7   8 6 3

so it is the fact that you do not take into account the elimination of templates which have no immediate effects on the candidates which restricts the resolution power of your implementation
P.O.
 
Posts: 1828
Joined: 07 June 2021

Re: Pattern Overlay Method

Postby rjamil » Sat Feb 08, 2025 6:05 pm

Hi P.O.,

First of all, many thanks for your quick feedback.

I have read your analysis and concluded that my double-digit POM implementation is perfectly fine and considered as complete based on your below comment:

...
each of these three combinations removes one template for 9 but only one of them (5 9) has immediate consequences on the candidates, it leads to the elimination of 9 from r1c4 and r2c7 (cells 4 and 16), you find it and do the eliminations:
...
i guess you check the combinations again but you don't find anything more

No, I did not check the combination again. Similarly I checked 72 combinations of double digit, i.e., each 9 digit against 8 other digits => 9 x 8 = 72.

but the template for 9 that the combination (6 9) eliminates has consequences on the combination (5 9), with this template less it realizes the placement of 5 in the cells (4 12 26 56) and solves the puzzle

Wait a minute. Did you not implemented triple-digit and quad-digit POM method separately?

If I understand correctly, you are doing exactly as how Ruud explain in 10th post:
Ruud wrote:Here's an example:
compare templates for digits 1 and 2 and build a list of valid combinations
compare templates for digits 3 and 4 and build a list of valid combinations
compare templates for digits 5 and 6 and build a list of valid combinations
compare templates for digits 7 and 8 and build a list of valid combinations
compare merged templates for 1/2 and 3/4 and build a list of valid combinations
compare merged templates for 5/6 and 7/8 and build a list of valid combinations
compare merged templates for 1/2/3/4 and 5/6/7/8 and build a list of valid combinations
compare the final merged result with the templates for 9 and you have your solution(s).

Ruud's first four examples are exactly the same as double-digit POM.
Next two examples are merging two different double-digit POM, result what I considered as quad-digit POM.
Similarly, last one example is merging two different quad-digit POM.

However, if merging two double-digit POM having one common digit, it will be considered as triple-digit POM.

I will code triple-digit POM and quad-digit POM when I have time. If you have also implemented the same then disable your double-digit POM merging routine and let see if the same found under triple-digit POM routine.

R. Jamil
rjamil
 
Posts: 810
Joined: 15 October 2014
Location: Karachi, Pakistan

Re: Pattern Overlay Method

Postby P.O. » Sun Feb 09, 2025 8:06 am

there are only 36 combinations of size 2, 72 is the number of permutations, when combining templates of one value with those of another value the order is not relevant: doing (1 2) or (2 1) is doing the same thing

there is no merging of combinations, these are made one after the other and take into account the results of the previous ones

and as the order in which the combinations are made matters, (6 9) then (5 9) is different from (5 9) then (6 9) (for example puzzle #4544: (6 9)(5 9) solves the puzzle, (5 9)(6 9) does not), in order to ensure that the consequences of all combinations are taken into account as long as there are template eliminations the combinations must be made again

and this is why a list of all possible templates for each value must be kept because it is on this list that template eliminations are taken into account decreasing with each elimination

until your implementation solves all the size 2 puzzles that i proposed with size 2 combinations, you can't say it's fine and complete
P.O.
 
Posts: 1828
Joined: 07 June 2021

Re: Pattern Overlay Method

Postby rjamil » Sun Feb 09, 2025 6:38 pm

Hi P.O.,

Thank you for your patience and continued support.

Actually, what I am thinking to implement the triple-digit POM method is as follows:

  1. For each digitA in ( 1 ... 9 )
  2. For each valid templateA of digitA
  3. For each digitB in ( 1 ... 9 ) - digitA
  4. For each valid templateB of digitB (i.e., non-overlapping with templateA)
  5. If digitB valid templateB found then goto step 7 else goto step 3
  6. Goto step 2
  7. For each digitC in ( 1 ... 9) - digitA - digitB
  8. For each valid templateC of digitC (i.e., non-overlapping with templateA and templateB)
  9. If digitC valid templateC found then count templateA cell positions; goto step 11 else goto step 5
  10. Goto step 3
  11. Goto step 2
  12. Perform digitA placement/elimination move if applicable
  13. Goto step 1
For puzzle #4544, consider digitA = 5; digitB and digitC are 6 and 9 in any order.

R. Jamil
rjamil
 
Posts: 810
Joined: 15 October 2014
Location: Karachi, Pakistan

Re: Pattern Overlay Method

Postby StrmCkr » Mon Feb 17, 2025 11:26 pm

https://www.mediafire.com/file/0ag5an04 ... t.txt/file

my code generates this 0 based cell list for each of 46656 the templates
step 1) generate the list of templates per digit cycle the collection 1 by 1 , if the template matches in full save the corresponding
the "id" code. that is the digits collection of templates.

rule 1) single digit template, combine all the templates
Delete: any 1 cell that is in every template must be the solution exclude each of the matching templates id# from all other digits.
Omission: collate all the templates if a cell is missing compared to the grids pencil-marks from all the templates that cell never has this digit as solution and can be eliminated.

that's as far as my template methods go atm, i haven't wrote multi digit codes as my solver couldn't use sets greater then 256 and the average collection hits 320+~

i might look at mutlti digit template ommissions and deletes once i get my new solver operational.

my pascal code is pretty rough but ill copy it over
Hidden Text: Show
// 46,656 potential single digit grids.

procedure potential;

type
hold = array of integer;
base = array of numberset;
digit = array of numberset;


var
w1,w2,w3:TWordSet;

setstuff: array [digits] of Twordset;
Cellsetstuff: array [ digits,cell] of twordset;

locked: array [digits] of numberset;
deleted: array [digits] of numberset;

stuff: array [digits] of numberset;

alist:array[digits] of word;

xn,w,p,n,n2,xn2,q,g,L,j,m,o,xn3,xn4,xn5:integer;
output: text;

step: base;
h: hold;
z:digit;

begin

for n:=1 to 9 do
begin
setstuff[n]:= twordset.create;
for q in digitcell[n] do
cellsetstuff[n,q]:=twordset.create;
end;

for n:= 1 to 9 do
alist[n]:=0;

for N:= 1 to 9 do
begin
locked[n]:=[];
deleted[n]:=[];
stuff[n]:= [];

for xn:= 0 to 80 do
begin

if s[xn] = [n]
then
locked[n]:= locked[n]+ [xn];

if (s[xn] <> [n] ) and not( n in pm[xn])
then
deleted[n]:= deleted[n] + [xn];

end;
end;

{startin cell}

{delete the exsiting output if you want to rebuild it unhash this section}
{assign(output,'C:\sudoku\pom\output.txt');
erase(output);
rewrite(output);
close(output); }

assign(output,'c:\sudoku\pom\exclusions.txt');
erase(output);
rewrite(output);
close(output);


{smashes all prebuilt txt files of potential solutions for digits 1-9 }
for n:= 1 to 9 do
begin
case n of
1: assign(output,'C:\sudoku\pom\1.txt');
2: assign(output,'C:\sudoku\pom\2.txt');
3: assign(output,'C:\sudoku\pom\3.txt');
4: assign(output,'C:\sudoku\pom\4.txt');
5: assign(output,'C:\sudoku\pom\5.txt');
6: assign(output,'C:\sudoku\pom\6.txt');
7: assign(output,'C:\sudoku\pom\7.txt');
8: assign(output,'C:\sudoku\pom\8.txt');
9: assign(output,'C:\sudoku\pom\9.txt');
end;

erase(output);
rewrite(output);
close(output);
end;

setlength(step,0);
setlength(z,0);
setlength(h,0);

for xn:= 80 downto 72 do

begin

w:=0; {step count}

setlength(h,(w+1)); {set the array size to w}

h[w]:=xn; {starting point for first substep}

setlength(step,(w+1)); {set the array size to w}

step[w]:= [xn]; { keeps track of what cells are used at each step W }

setlength(z,w+1); {prevent occupy "new starting point" }

z[w]:= peer[xn] + [xn]; {used cells starting point}

repeat

for p:= h[w] downto (72-((w+1)*9)) do {iteration of peers}

if p in ([0..80] - z[w] ) // added check used state
then
begin

h[w]:=h[w]-1; { advance the peer count for step w}

inc(w); {increase the step count}

setlength(h,(w+1));
setlength(step,(w+1)); {increse the array size to w}

step[w]:= step[w-1] + [p] ; {set the step cell active for the newly created step w}

h[w]:= 71 - ((w)*9) ; {set the new step w as 71 potential choice cells}

setlength(z,w+1); { increase size to w}

z[w]:= z[w-1] + peer[p] + [p]; {used cells new point}

break;

end
else
h[w]:=h[w]-1; {if the above is false then advance the peer number}


if w = 8
then
begin


{ generate the whole list to a specific file}
{assign(output,'C:\sudoku\pom\output.txt');
append(output);
for n in step[w] do
write(output,n,' ');

writeln(output);

close(output); }

for n:= 1 to 9 do
begin

case n of
1: assign(output,'C:\sudoku\pom\1.txt');

2: assign(output,'C:\sudoku\pom\2.txt');

3: assign(output,'C:\sudoku\pom\3.txt');

4: assign(output,'C:\sudoku\pom\4.txt');

5: assign(output,'C:\sudoku\pom\5.txt');

6: assign(output,'C:\sudoku\pom\6.txt');

7: assign(output,'C:\sudoku\pom\7.txt');

8: assign(output,'C:\sudoku\pom\8.txt');

9: assign(output,'C:\sudoku\pom\9.txt');
end;

if ( step[w] * locked[n] = locked[n] )
and ( step[w] * deleted[n] = [] )
then
begin
inc(alist[n]);
append(output);

for q in (step[w] - locked[n]) do
begin
write(output, q,' ');

include2(cellsetstuff[n,q],alist[n]);
include2(setstuff[n],alist[n]);
end;

writeln(output);
close(output);

stuff[n]:= stuff[n] + (step[w] - locked[n]);

end;


end; { N choice}

end; {w=8}


if ((h[w] < 0 ) and (w > 0 ))
or (w=8)
or ( ( [0..80] - z[w] = [] ) and (W < 8) and (w > 0) )
or ( (h[w] < (72 - ( (w+1)*9) ) ) and (w > 0) )

{the following resets the step to the previous state}
then
repeat
begin
w:=(w-1);
setlength(h,(w+1));
h[w]:= h[w];
setlength(step,(w+1));
setlength(z,w+1);

end;
until ( w = 0 ) or (h[w] > ((71 - (w+1)*9)) )

until ((w = 0) and (h[w] < 0) ) or ( ( w = 0) and (h[w] < (72 -( (w+1)*9) ) ) )

end;
{size printing of all sets}
for n:= 1 to 9 do
begin
gotoxy(2,60+n);
write(n,':= ',alist[n]);
end;

{size 1}
for n:= 1 to 9 do
if (stuff[n] <> [])
and (stuff[n] * (digitcell[n] - (locked[n] + deleted[n]) ) = stuff[n])
and ( ((digitcell[n] - (locked[n] + deleted[n]) ) - stuff[n]) <> [] )
then
begin
assign(output,'C:\sudoku\pom\exclusions.txt');
append(output);
write(output,n, ' @: ');
// cell has no templates out of all of them.
for xn in ((digitcell[n] - (locked[n] + deleted[n])) - stuff[n])do
begin
write(output,xn,' ');
covered2[n]:=covered2[n]+[xn];
active:=true;
end;

//cell is exclusivly in all sets
for xn in digitcell[n] do
if equality(cellsetstuff[n,xn],setstuff[n])
then
begin
active:=true;
covered[xn]:=covered[xn] + (pm[xn]-[n]);
write(output,'*',xn,'<>( ');
for o in pm[xn]-[n] do
write(output,o,' ');
write(output,') ')
end;


writeln(output);
close(output);


end; {size 1}

{size 2}
for n in [1..9] do
for xn in digitcell[n] do
for xn2 in digitcell[n]*[(xn+1)..80] do
begin
w1:=twordset.create;

w1:= cellsetstuff[n,xn] + cellsetstuff[n,xn2];

if setstuff[n]<=w1
then
begin
for q in [1..9]-[n] do
begin
for g in setstuff[q] do
if [xn,xn2] * digitcell[q] = [xn,xn2]
then
if (g in (cellsetstuff[q,xn]))
and (g in (cellsetstuff[q,xn2]))
then
begin
w2:=twordset.create;

for L in digitcell[q] do
if (g in cellsetstuff[q,l])
then
begin
exclude2(cellsetstuff[q,L],g);
include2(w2,l);
end;


assign(output,'C:\sudoku\pom\exclusions.txt');
append(output);
write(output,'(',n,')',xn,',',xn2,':(');
for m in setstuff[n] do write(output,' ',m); write(output,' ) & ');
write(output,'(',q,')',xn,',',xn2,':(');
for o in (setstuff[q]) do write(output,' ',o); write(output,' ) ');
write(output,'RT: ', G,' @ Digit: ',q, ' =>> <> ');

exclude2(setstuff[q],g);

for L in digitcell[q] do
begin
{no templates left for cells}
w3:= setstuff[q] - cellsetstuff[q,l];
if equality(w3,cellsetstuff[q,l])
then
begin
write(output,L,' ');
active:=true;
covered2[q]:=covered2[q] + [L];
end;
{digits are locked to all sets}
if equality(cellsetstuff[q,l],setstuff[q])
then
begin
active:=true;
covered[l]:=covered[l] + (pm[l]-[q]);
write(output,'*',L,'<>( ');
for o in pm[l]-[q] do
write(output,o,' ');
write(output,') ')
end;
end;



writeln(output);
close(output);

include2(setstuff[q],g);
for L in w2 do
begin
include2(cellsetstuff[q,L],g);
end;
w2.free;
break;

end;
end;
end;
w1.free;

end; {size 2}


end;
Some do, some teach, the rest look it up.
stormdoku
User avatar
StrmCkr
 
Posts: 1441
Joined: 05 September 2006

Re: Pattern Overlay Method

Postby rjamil » Tue Feb 18, 2025 2:30 am

Hi StrmCkr,

Many thanks for your response. I am already using your generated 46,656 templates with thankfulness.

I see that your POM routine in Pascal code is focused on holding valid (possible) templates of a particular digit out of all 46,656 tmplates, instead of, just searching the valid template and increment the template cells count. I see Dobrichev proposed method's step D and implemented accordingly, and later, Dobrichev advised danger about template merging.

I have summerised steps in my previous posts as to how single-digit (and here), double-digit and triple-digit POM works without storing intermediate results and then merging the same.

The key point is that, if a single-digit POM searches all 46,656 templates for each digit's valid templates first, it definitely need to save the individually valid templates of each digit. BUT, on the contrary, if POM searches in indexed templates with intelegently optimized skipping, then there is no need to keep each individual digit valid templates for further merging/processing. Like I did in double-digit POM search; and planning to do the same for triple-digit and quad-digit POM move, when I have more free time (as I am fighting with my landlord, who wants me and my family to evict the rented premises this month, on court for permanent injunction).

R. Jamil
rjamil
 
Posts: 810
Joined: 15 October 2014
Location: Karachi, Pakistan

Previous

Return to Advanced solving techniques