Skip to content

Commit f252474

Browse files
committed
Sudoku Added
1 parent e0bb4ff commit f252474

File tree

4 files changed

+457
-0
lines changed

4 files changed

+457
-0
lines changed
Lines changed: 259 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,259 @@
1+
class SudokuDiagram {
2+
constructor(selector,h,w) {
3+
this.selector = selector;
4+
this.h = h;
5+
this.w = w;
6+
this.root = this.selector.html('')// Remove all previous elements
7+
.append('svg')
8+
.attr('height',this.h)
9+
.attr('width',this.w);
10+
}
11+
12+
init(problem,cellDetails) {
13+
this.problem = problem;
14+
this.cellDetails = cellDetails;
15+
this.maxRow = this.problem.maxRow;
16+
this.maxCol = this.problem.maxCol;
17+
this.blockSize = this.problem.blockSize;
18+
this.padding = 10;
19+
this.xScale = d3.scaleLinear()
20+
.domain([0,this.maxCol])
21+
.range([this.padding,this.w-this.padding]);
22+
this.yScale = d3.scaleLinear()
23+
.domain([0,this.maxRow])
24+
.range([this.padding,this.h-this.padding]);
25+
this.cellHeight = (this.h - (2*this.padding))/this.maxRow;
26+
this.cellWidth = (this.w - (2*this.padding))/this.maxCol;
27+
28+
this.highlights = [
29+
{
30+
name : 'Row',
31+
color : 'green',
32+
x : (i,j) => {return this.padding},
33+
y : (i,j) => {return this.padding + i*this.cellHeight},
34+
height : (i,j) => {return this.cellHeight},
35+
width : (i,j) => {return this.cellWidth*this.maxCol},
36+
show : (i,j) => {this.cellDetails.showConstraints('green',this.problem.getRow(i,j))}
37+
},
38+
{
39+
name : 'Column',
40+
color : 'blue',
41+
x : (i,j) => {return this.padding + j*this.cellWidth},
42+
y : (i,j) => {return this.padding},
43+
height : (i,j) => {return this.cellHeight*this.maxRow},
44+
width : (i,j) => {return this.cellWidth},
45+
show : (i,j) => {this.cellDetails.showConstraints('blue',this.problem.getColumn(i,j))}
46+
},
47+
{
48+
name : 'Block',
49+
color : 'red',
50+
x : (i,j) => {return this.padding + (j-(j%this.blockSize))*this.cellWidth},
51+
y : (i,j) => {return this.padding + (i-(i%this.blockSize))*this.cellWidth},
52+
height : (i,j) => {return this.cellHeight*this.blockSize},
53+
width : (i,j) => {return this.cellWidth*this.blockSize},
54+
show : (i,j) => {this.cellDetails.showConstraints('red',this.problem.getBlock(i,j))}
55+
}
56+
];
57+
this.drawAll();
58+
}
59+
60+
drawAll() {
61+
this.matrixDiv = this.root.append('g')
62+
.attr('class','matrix');
63+
this.borders = this.root.append('g').attr('class','border');
64+
this.drawCells();
65+
this.fillCells();
66+
}
67+
68+
highlight(i,j) {
69+
for(let k = 0; k < this.highlights.length; k++) {
70+
let highlight = this.highlights[k];
71+
this.borders.append('rect')
72+
.attr('class','highlight-border')
73+
.attr('x',highlight.x(i,j))
74+
.attr('y',highlight.y(i,j))
75+
.attr('height',highlight.height(i,j))
76+
.attr('width',highlight.width(i,j))
77+
.style('stroke',highlight.color);
78+
highlight.show(i,j)
79+
}
80+
this.cellDetails.showReducedDomain(this.problem.getDomain(i,j));
81+
}
82+
83+
clearHighlight() {
84+
this.borders.selectAll('*').remove();
85+
}
86+
87+
drawCells() {
88+
this.cells = [];
89+
for(let i = 0; i < this.maxRow; i++) {
90+
let row = [];
91+
for(let j = 0; j < this.maxCol; j++) {
92+
let cell = this.matrixDiv.append('g')
93+
.attr('class','cell clickable')
94+
.classed('grey', (Math.floor(i/this.blockSize)+Math.floor(j/this.blockSize))%2 == 0)
95+
.on('mousedown',() => {
96+
//If not already filled
97+
if(!this.problem.isFilled(i,j)){
98+
let x = this.problem.checkSingle(i,j);
99+
if(x){
100+
this.problem.assign(i,j,x);
101+
this.fillCells();
102+
}
103+
}
104+
})
105+
.on('mouseover',() => {
106+
//Highlight the hovered cell
107+
if(!this.problem.isFilled(i,j)){
108+
this.cellDetails.showDomain(this.problem.getDomain(i,j));
109+
this.highlight(i,j);
110+
this.cells[i][j].classed('active-cell',true);
111+
}
112+
})
113+
.on('mouseout', () => {
114+
this.clearHighlight();
115+
this.cells[i][j].classed('active-cell',false);
116+
this.cellDetails.removeDomain()
117+
});
118+
cell.append('rect')
119+
.attr('height',this.cellHeight)
120+
.attr('width',this.cellWidth)
121+
.attr('x', this.xScale(j))
122+
.attr('y',this.yScale(i));
123+
124+
row.push(cell);
125+
}
126+
this.cells.push(row);
127+
}
128+
}
129+
130+
fillCells() {
131+
for(let i = 0; i < this.maxRow; i++) {
132+
for(let j = 0; j < this.maxCol; j++) {
133+
//Remove the previous text
134+
this.cells[i][j].selectAll('.content').remove();
135+
if(this.problem.puzzle[i][j]) {
136+
this.cells[i][j].append('g')
137+
.attr('class','content')
138+
.append('text')
139+
.attr('class','cell-number')
140+
.attr('x', this.xScale(j) + this.cellWidth/2)
141+
.attr('y',this.yScale(i) + this.cellHeight/2)
142+
.text(() => this.problem.puzzle[i][j]);
143+
} else {
144+
this.cells[i][j]
145+
let domain = this.problem.getDomain(i,j);
146+
for(let y = 0; y < this.blockSize; y++) {
147+
for(let x = 0; x < this.blockSize; x++) {
148+
if(domain.has((y*3)+x+1)) {
149+
this.cells[i][j].append('g')
150+
.attr('class','content')
151+
.append('text')
152+
.attr('class','cell-dots')
153+
.attr('x',this.xScale(j) + (this.cellWidth*2*x)/6 + this.cellWidth/6)
154+
.attr('y',this.yScale(i) + (this.cellHeight*2*y)/6 + this.cellHeight/6)
155+
.text('\u2022')
156+
}
157+
}
158+
}
159+
}
160+
161+
}
162+
}
163+
}
164+
165+
}
166+
167+
class CellDetails {
168+
constructor(selector,h,w) {
169+
this.selector = selector;
170+
this.h = h;
171+
this.w = w;
172+
this.selector.select('svg').remove();
173+
this.root = this.selector.append('svg')
174+
.attr('height',this.h)
175+
.attr('width',this.w);
176+
}
177+
178+
init(problem) {
179+
this.problem = problem;
180+
this.gap = 60;
181+
this.padding = 40;
182+
this.border = this.root.append('rect')
183+
.attr('x',this.w/3 - this.padding)
184+
.attr('y',this.h/10 - this.padding)
185+
.attr('height',2*this.gap+ 2*this.padding)
186+
.attr('width',2*this.gap + 2*this.padding)
187+
.style('fill','hsla(150, 0%, 83%, 1)');
188+
189+
this.domainWrapper = this.root.append('g').attr('class','domain');
190+
191+
}
192+
193+
showConstraints(color,set) {
194+
for(let i = 0; i < 9; i++) {
195+
if(set.has(i+1)) {
196+
this.originalDomain.append('text')
197+
.attr('class','original-domain')
198+
.attr('x',this.w/3 + (i%3)*this.gap)
199+
.attr('y',this.h/10 + Math.floor(i/3)*this.gap)
200+
.style('font-size',30)
201+
.style('fill',color)
202+
.text('X');
203+
}
204+
}
205+
}
206+
207+
showDomain() {
208+
this.originalDomain = this.domainWrapper.append('g');
209+
this.domainElements = [];
210+
for(let i = 0; i < 9; i++) {
211+
this.domainElements.push(this.originalDomain.append('text')
212+
.attr('class','original-domain')
213+
.attr('x',this.w/3 + (i%3)*this.gap)
214+
.attr('y',this.h/10 + Math.floor(i/3)*this.gap)
215+
.style('font-size',30)
216+
.text(i+1));
217+
}
218+
219+
}
220+
221+
showReducedDomain(set) {
222+
if(set.size > 0) {
223+
let str = `Reduced Domain : (${[...set].toString()})`;
224+
this.domainWrapper.append('text')
225+
.attr('class','domain-text')
226+
.attr('x',this.w/2)
227+
.attr('y',this.h/1.5)
228+
.text(str);
229+
}
230+
}
231+
232+
removeDomain() {
233+
this.domainWrapper.selectAll('*').remove();
234+
}
235+
}
236+
237+
function init() {
238+
var puzzle = [
239+
[0,0,3,0,2,0,6,0,0],
240+
[9,0,0,3,0,5,0,0,1],
241+
[0,0,1,8,0,6,4,0,0],
242+
[0,0,8,1,0,2,9,0,0],
243+
[7,0,0,0,0,0,0,0,8],
244+
[0,0,6,7,0,8,2,0,0],
245+
[0,0,2,6,0,9,5,0,0],
246+
[8,0,0,2,0,3,0,0,9],
247+
[0,0,5,0,1,0,3,0,0]
248+
];
249+
var sudokuPuzzle = new SudokuPuzzle(puzzle,9,9,3,[1,2,3,4,5,6,7,8,9]);
250+
var cellDetails = new CellDetails(d3.select('#sudoku').select('.cellDetails'),500,500);
251+
cellDetails.init(sudokuPuzzle);
252+
var sudokuDiagram = new SudokuDiagram(d3.select('#sudoku').select('.canvas'),500,500);
253+
sudokuDiagram.init(sudokuPuzzle,cellDetails);
254+
}
255+
256+
$(document).ready(function(){
257+
init();
258+
$('#sudoku .restart-button').click(init);
259+
});

6-Constraint-Satisfaction-Problems/index.html

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,12 +15,14 @@
1515
<script type="text/javascript" src="./minConflicts.js"></script>
1616
<script type="text/javascript" src="./treeCSP.js"></script>
1717
<script type="text/javascript" src="./mapColoring.js"></script>
18+
<script type="text/javascript" src="./sudoku.js"></script>
1819

1920
<script type="text/javascript" src="./c_AC3.js"></script>
2021
<script type="text/javascript" src="./c_backtracking.js"></script>
2122
<script type="text/javascript" src="./c_minConflicts.js"></script>
2223
<script type="text/javascript" src="./c_treeCSP.js"></script>
2324
<script type="text/javascript" src="./c_mapColoring.js"></script>
25+
<script type="text/javascript" src="./c_sudoku.js"></script>
2426
</head>
2527

2628
<body>
@@ -65,6 +67,24 @@ <h2>Arc consistency</h2>
6567
</div>
6668
<pre id="AC3Code"></pre>
6769

70+
<div id='sudoku'>
71+
<div class="row">
72+
<div class='btn btn-primary restart-button'>Restart</div>
73+
</div>
74+
<div class="row">
75+
<div class="col-md-6">
76+
<div class="canvas">
77+
78+
</div>
79+
</div>
80+
<div class="col-md-6">
81+
<div class="cellDetails">
82+
83+
</div>
84+
</div>
85+
</div>
86+
</div>
87+
6888
<h2>Backtracking</h2>
6989
<p>Map colouring using backtracking. Click to restart the simulation.</p>
7090
<div class="canvas" id="backtrackCanvas" height="300px">

6-Constraint-Satisfaction-Problems/main.css

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,3 +33,60 @@ svg .b {
3333
fill: black;
3434
stroke: none;
3535
}
36+
svg .cell {
37+
fill: hsl(0, 0%, 95%);
38+
stroke : black;
39+
stroke-width: 1;
40+
}
41+
42+
svg .cell.grey {
43+
fill: hsl(0, 0%, 83%);
44+
}
45+
46+
svg .cell-number {
47+
font-size: 200%;
48+
alignment-baseline: middle;
49+
text-anchor: middle;
50+
stroke : none;
51+
fill : black;
52+
}
53+
54+
svg .cell-dots {
55+
font-size: 100%;
56+
alignment-baseline: middle;
57+
text-anchor: middle;
58+
stroke : none;
59+
fill : black;
60+
}
61+
62+
svg .domain-text {
63+
font-size: 200%;
64+
alignment-baseline: middle;
65+
text-anchor: middle;
66+
stroke : none;
67+
fill : black;
68+
}
69+
70+
svg .cell.highlight{
71+
fill : hsl(31, 92%, 74%)
72+
}
73+
74+
svg .cell.active-cell {
75+
fill : hsl(31, 92%, 60%)
76+
}
77+
78+
svg .highlight-border {
79+
fill : none;
80+
stroke-width:3;
81+
}
82+
83+
svg .original-domain {
84+
text-anchor: middle;
85+
alignment-baseline: middle;
86+
stroke : none;
87+
fill : black;
88+
}
89+
90+
svg .invisible {
91+
display: block;
92+
}

0 commit comments

Comments
 (0)