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