-
Notifications
You must be signed in to change notification settings - Fork 0
/
Kanoodle.js
139 lines (123 loc) · 4.24 KB
/
Kanoodle.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
// Tweakables
var ShowWork = true;
var FPSTarget = 30;
// End of tweakables
var LastUpdateTime = 0;
Object.prototype.clone = function() {
var newObj = (this instanceof Array) ? [] : {};
for (i in this) {
if (i == 'clone') continue;
if (this[i] && typeof this[i] == "object") {
newObj[i] = this[i].clone();
} else newObj[i] = this[i]
} return newObj;
};
Array.prototype.remove = function(from, to) {
var rest = this.slice((to || from) + 1 || this.length);
this.length = from < 0 ? this.length + from : from;
return this.push.apply(this, rest);
};
self.addEventListener('message', MsgHandler);
function MsgHandler(Event)
{
var Data = Event.data;
switch(Data.MsgType){
case "start":
StartFit(JSON.parse(Data.Shapes), JSON.parse(Data.Board));
break;
default:
Debug("Unrecognised command " + Data.MsgType);
break;
}
}
function StartFit(Shapes, Board)
{
var ShapeList = [];
for(i=0; i<Shapes.length; i++){
ShapeList.push(i);
}
FitShapes(Shapes, Board, 0, 0, ShapeList);
self.postMessage({'MsgType': "finished"});
}
function FitShapes(Shapes, Board, BoardX, BoardY, ShapeList)
{
var BoardLayout = Board.Layout;
var Pt;
var DateNow;
var TimeNow;
// Find free square
do{
if(BoardLayout[BoardX][BoardY] == -1){
// Fit shape here
break;
}
else{
if(++BoardX >= Board.Width){
BoardX=0;
if(++BoardY >= Board.Height){
Debug("OUT OF SPACES!?");
return;
}
}
}
} while(1);
for(var ListItem=0; ListItem<ShapeList.length; ListItem++){
var ShapeNo = ShapeList[ListItem];
var Shape = Shapes[ShapeNo];
var Layouts = Shape.Layout;
for(var LayoutNo=0; LayoutNo<Layouts.length; LayoutNo++){
var Layout = Layouts[LayoutNo];
for(var PtNo=0; PtNo<Layout.length; PtNo++){
OffX = BoardX - Layout[PtNo][0];
OffY = BoardY - Layout[PtNo][1];
Fit = true;
for(Pt=0; Pt<Layout.length; Pt++){
PtX = OffX + Layout[Pt][0];
PtY = OffY + Layout[Pt][1];
if(PtX<0 || PtX>=Board.Width || PtY<0 || PtY>=Board.Height){
Fit = false;
break;
}
if(BoardLayout[PtX][PtY] != -1){
Fit = false;
break;
}
}
if(Fit){
// The shape fits here
var NewBoard = Board.clone();
// Update the board
for(Pt=0; Pt<Layout.length; Pt++){
PtX = OffX + Layout[Pt][0];
PtY = OffY + Layout[Pt][1];
NewBoard.Layout[PtX][PtY] = ShapeNo;
}
// Update the shape list
var NewShapeList = ShapeList.clone();
NewShapeList.remove(ListItem);
// Debug("Fit shape " + Shape.Name + "(" + ShapeNo + ") layout " + LayoutNo + " point " + PtNo + " at " + BoardX + ","+BoardY);
if(NewShapeList.length == 0){
// Got a solution!
self.postMessage({'MsgType': "solution", 'Board': JSON.stringify(NewBoard)});
}
else{
// Recurse
if(ShowWork){
DateNow = new Date();
TimeNow = DateNow.getTime();
if((TimeNow - LastUpdateTime) > (1000 / FPSTarget)){
self.postMessage({'MsgType': "workupdate", 'Board': JSON.stringify(NewBoard)});
LastUpdateTime = TimeNow;
}
}
FitShapes(Shapes, NewBoard, BoardX, BoardY, NewShapeList);
}
}
}
}
}
}
function Debug(Msg)
{
self.postMessage({'MsgType': "debug", 'Msg': Msg});
}