HTMLcopy
1
<div id="container"></div>
CSScopy
6
1
html, body, #container {
2
width: 100%;
3
height: 100%;
4
margin: 0;
5
padding: 0;
6
}
JavaScriptcopy
x
1
// create stage
2
var stage = acgraph.create('container');
3
4
// get bounds of stage
5
var bounds = stage.getBounds();
6
7
// calculate chip width/height
8
var CHIP_WIDTH = bounds.width / 4;
9
var CHIP_HEIGHT = bounds.height / 4;
10
11
// fill for chip
12
var FILL = {
13
angle: -45,
14
keys: [
15
'0 #fff',
16
'0.2 #aaa',
17
'1 #000'
18
]
19
};
20
21
/**
22
* Chip class.
23
* @param {Array} board Game board.
24
* @param {number} position Chip position.
25
* @constructor
26
*/
27
function Chip(board, position) {
28
this.board = board;
29
// chip shape
30
this.rect = stage.rect().stroke('black').fill(FILL);
31
var textStyle = {
32
fontSize: 40,
33
hAlign: 'center',
34
vAlign: 'center',
35
color: 'white',
36
width: CHIP_WIDTH,
37
height: CHIP_HEIGHT
38
};
39
// chip text
40
this.text = stage.text(0, 0, board[position], textStyle);
41
this.text.disablePointerEvents(true);
42
43
this.setPosition(position);
44
this.rect.listen(acgraph.events.EventType.CLICK, this.handleClick, false, this);
45
}
46
47
48
/**
49
* Sets position to chip.
50
* @param {number} newPosition New position.
51
*/
52
Chip.prototype.setPosition = function (newPosition) {
53
var rowColumn, newBounds;
54
this.position = newPosition;
55
rowColumn = getRowColumnByIndex(newPosition);
56
newBounds = getBoundsByRowColumn.apply(null, rowColumn);
57
this.rect.setBounds(newBounds);
58
this.text.x(newBounds.left).y(newBounds.top);
59
};
60
61
62
/**
63
* Handles click of mouse.
64
*/
65
Chip.prototype.handleClick = function () {
66
this.moveUp() || this.moveRight() || this.moveDown() || this.moveLeft();
67
};
68
69
70
/**
71
* Move up action.
72
* @return {boolean} Whether action performed.
73
*/
74
Chip.prototype.moveUp = function () {
75
var newPosition = this.position - 4;
76
if (this.board[newPosition] == 0) {
77
this.board[this.position] = 0;
78
this.setPosition(newPosition);
79
this.board[newPosition] = this;
80
if (this.checkBoard())
81
alert('Congrats! You have won the game!');
82
return true;
83
}
84
return false;
85
};
86
87
88
/**
89
* Move down action.
90
* @return {boolean} Whether action performed.
91
*/
92
Chip.prototype.moveDown = function () {
93
var newPosition = this.position + 4;
94
if (this.board[newPosition] == 0) {
95
this.board[this.position] = 0;
96
this.setPosition(newPosition);
97
this.board[newPosition] = this;
98
if (this.checkBoard())
99
alert('Congrats! You have won the game!');
100
return true;
101
}
102
return false;
103
};
104
105
106
/**
107
* Move left action.
108
* @return {boolean} Whether action performed.
109
*/
110
Chip.prototype.moveLeft = function () {
111
var newPosition = this.position - 1;
112
if (this.position % 4 > 0 && this.board[newPosition] == 0) {
113
this.board[this.position] = 0;
114
this.setPosition(newPosition);
115
this.board[newPosition] = this;
116
if (this.checkBoard())
117
alert('Congrats! You have won the game!');
118
return true;
119
}
120
return false;
121
};
122
123
124
/**
125
* Move right action.
126
* @return {boolean} Whether action performed.
127
*/
128
Chip.prototype.moveRight = function () {
129
var newPosition = this.position + 1;
130
if (this.position % 4 < 3 && this.board[newPosition] == 0) {
131
this.board[this.position] = 0;
132
this.setPosition(newPosition);
133
this.board[newPosition] = this;
134
if (this.checkBoard())
135
alert('Congrats! You have won the game!');
136
return true;
137
}
138
return false;
139
};
140
141
142
/**
143
* Checks board.
144
* @return {boolean} Whether game has been won.
145
*/
146
Chip.prototype.checkBoard = function () {
147
// last element should be empty
148
if (this.board[15] !== 0) return false;
149
var win = true;
150
for (var i = 0; i < 14; i++) {
151
win = win && (+this.board[i].text.text() == (i + 1));
152
if (!win) return false;
153
}
154
return win;
155
};
156
157
// helpers
158
159
/**
160
* "Randomly" shuffles array.
161
* @param {Array} arr Array to shuffle.
162
*/
163
function shuffle(arr) {
164
var n = arr.length;
165
for (var i = n - 1; i > 1; i--) {
166
var j = Math.floor(Math.random() * (i + 1)); // take a random 0 <= j <= i
167
var tmp = arr[j];
168
arr[j] = arr[i];
169
arr[i] = tmp;
170
}
171
}
172
173
174
/**
175
* Starts new game.
176
*/
177
function newGame() {
178
shuffle(board);
179
for (var i = 0; i < 16; i++) {
180
var boardItem = board[i];
181
if (boardItem) {
182
if (boardItem instanceof Chip)
183
boardItem.setPosition(i);
184
else
185
board[i] = new Chip(board, i);
186
}
187
}
188
}
189
190
191
/**
192
* Get chip bounds by row and column.
193
* @param {number} row Row.
194
* @param {number} column Column.
195
* @returns {graphics.math.Rect} Bounds.
196
*/
197
function getBoundsByRowColumn(row, column) {
198
var left = column * CHIP_WIDTH;
199
var top = row * CHIP_HEIGHT;
200
var wShift = column == 3 ? 1 : 0;
201
var hShift = row == 3 ? 1 : 0;
202
return new acgraph.math.Rect(left + 0.5, top + 0.5, CHIP_WIDTH - wShift, CHIP_HEIGHT - hShift);
203
}
204
205
206
/**
207
* Get row/column pair by index in array.
208
* @param {number} index
209
* @return {Array.<number, number>}
210
*/
211
function getRowColumnByIndex(index) {
212
var column = index % 4;
213
var row = (index - column) / 4;
214
return [row, column]
215
}
216
217
// just for game generation
218
var board = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15];
219
220
// starts new game
221
newGame();
222
223
// finds index of zero chip
224
function findZero() {
225
return board.indexOf(0);
226
}
227
228
// listener for keyboard
229
document.onkeyup = function (e) {
230
//l37 u38 r39 d40
231
if (e.keyCode > 36 && e.keyCode < 41) {
232
var index = findZero();
233
switch (e.keyCode) {
234
case 37:
235
if ((index % 4 < 3) && board[index + 1])
236
board[index + 1].moveLeft();
237
break;
238
case 38:
239
if (board[index + 4])
240
board[index + 4].moveUp();
241
break;
242
case 39:
243
if ((index % 4 > 0) && board[index - 1])
244
board[index - 1].moveRight();
245
break;
246
case 40:
247
if (board[index - 4])
248
board[index - 4].moveDown();
249
break;
250
}
251
}
252
};