-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathfifteen.js
263 lines (214 loc) · 7.23 KB
/
fifteen.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
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
(function(){
"use strict";
//Module-Global variables
//Sets default puzzle size and default selected puzzle size option
//To change puzzle size, only change here, everything else is relative.
var puzzleSize = 4;
var emptyRow = puzzleSize -1;
var emptyCol = puzzleSize -1;
var tileSize = parseInt(400 / puzzleSize);
//Creates a puzzle size control, attaches event handler to shuffle button and calls functions that create the initial board on load.
window.onload = function() {
//Assign event handlers and initialize
var shuffleBtn = document.getElementById("shufflebutton");
shuffleBtn.onclick = shuffle;
var size = document.getElementById("size");
size.onchange = changeSize;
makeTiles();
enableImageChange();
numberControl();
};
//Assigns IDs to the tiles based on their positions
function assignIds() {
var tiles = document.querySelectorAll(".tile");
for(var i = 0; i < tiles.length; i++) {
var row = parseInt(tiles[i].style.top) / tileSize;
var col = parseInt(tiles[i].style.left) / tileSize;
tiles[i].id = "tile_" + row + "_" + col;
}
}
//Changes the size of the puzzle
function changeSize() {
puzzleSize = this.value;
tileSize = parseInt(400 / puzzleSize);
makeTiles();
}
//Checks win condition by checking if current position equal to initial position
function checkWin() {
var tiles = document.querySelectorAll(".tile");
for(var i = 0; i < tiles.length; i++) {
if(tiles[i].id != tiles[i].dataset.initial) {
return false;
}
}
return true;
}
//Assigns event handler for alternate puzzle images
function enableImageChange() {
var alts = document.querySelectorAll('.alt-img');
for(var i = 0; i < alts.length; i++) {
alts[i].onclick = function() {
document.querySelector('.current').classList.remove('current');
this.classList.add('current');
getPuzzleImage();
};
}
}
//Scales font size for smaller tiles, for readability
function fontSize() {
if(puzzleSize < 6) {
return "normal";
} else {
return "small";
}
}
//Returns an array of tiles that neighbor the empty space, clearing out old neighbors each time.
function getNeighbors() {
assignIds();
//Clears out old neighbors
var oldNeighbors = document.querySelectorAll(".neighbor");
for(var i = 0; i < oldNeighbors.length; i++) {
oldNeighbors[i].classList.remove("neighbor");
oldNeighbors[i].onclick = null;
}
//Creates array of current neighbors
var neighbors = [];
//list of possible neighbor ids
var west = "tile_" + emptyRow + "_" + (emptyCol - 1);
var north = "tile_" + (emptyRow - 1) + "_" + emptyCol;
var east = "tile_" + emptyRow + "_" + (emptyCol + 1);
var south = "tile_" + (emptyRow + 1) + "_" + emptyCol;
var possibleNeighbors = [west, north, east, south];
//check that possible neighbors are actually existing tiles
for(var i = 0; i < possibleNeighbors.length; i++) {
if(document.getElementById(possibleNeighbors[i])) {
neighbors.push(document.getElementById(possibleNeighbors[i]));
}
}
return neighbors;
}
//Sets puzzle background image to the currently selected puzzle image
function getPuzzleImage() {
var img = document.querySelector('.current').getElementsByTagName('img')[0];
var tiles = document.querySelectorAll('.tile');
for(var i = 0; i < tiles.length; i++) {
tiles[i].style.backgroundImage = "url('"+ img.src + "')";
}
}
//Creates the initial board
function makeTiles() {
emptyRow = emptyCol = puzzleSize -1;
var row = 0;
var col = 0;
var fontClass = fontSize();
//Fits image to custom puzzle board size.
//Board size can change by a few pixels due to rounding tileSize.
var imageSize = tileSize * puzzleSize;
var area = document.getElementById("puzzlearea");
area.innerHTML = "";
//Creates the puzzle tiles
for(var i = 0; i < (puzzleSize * puzzleSize) -1; i++) {
//Increases row and resets column based on puzzle size.
if(i > 0 && i % puzzleSize == 0) {
row++;
col = 0;
}
//Styles and positions each tile, depending on puzzle size
var tile = document.createElement("div");
tile.classList.add("tile");
tile.classList.add(fontClass);
//Account for border(x2 for each side) - set in fifteen.css
tile.style.width = tile.style.height = tileSize - 6 + "px";
tile.style.backgroundSize = imageSize + "px " + imageSize + "px";
tilePosition(tile, row, col);
//Give tiles a class detailing their initial position, in order to check win
var initialPos = "tile_" + row + "_" + col;
tile.dataset.initial = initialPos;
//Give numbers to tiles
var num = document.createElement("p");
num.innerHTML = i + 1;
tile.appendChild(num);
area.appendChild(tile);
col++;
}
styleNeighbors(getNeighbors());
numbersDisplay(numberCheck());
getPuzzleImage();
}
//Moves a neighboring tile to the empty space
function move(neighbor) {
var left = emptyCol * tileSize + "px";
var top = emptyRow * tileSize + "px";
emptyRow = parseInt(neighbor.style.top) / tileSize;
emptyCol = parseInt(neighbor.style.left) / tileSize;
neighbor.style.top = top;
neighbor.style.left = left;
}
//Assigns click event to number on/off radio buttons
function numberControl() {
var numbersBtn = document.getElementsByName('numbers');
for(var i = 0; i < numbersBtn.length; i++) {
numbersBtn[i].onchange = function() {
numbersDisplay(numberCheck());
};
}
}
//Returns the value of the checked numbers on/off radio button. Returns either 'block' or 'none'
function numberCheck() {
var numbersBtn = document.getElementsByName('numbers');
for(var i = 0; i < numbersBtn.length; i ++) {
if(numbersBtn[i].checked) {
return numbersBtn[i].value;
}
}
}
//Displays tile numbes based on value of checked numbers on/off radio
function numbersDisplay(val) {
var numbers = document.querySelectorAll('.tile p');
for(var i = 0; i < numbers.length; i++) {
numbers[i].style.display = val;
}
}
//Shuffles the board by finding neighboring tiles and randomly selecting one to move. Once finished, finds and styles neighboring tiles.
function shuffle() {
winShow(false);
for(var i = 0; i < 1000; i++) {
var neighbors = getNeighbors();
var rand = parseInt(Math.random() * neighbors.length);
var neighbor = neighbors[rand];
move(neighbor);
}
styleNeighbors(getNeighbors());
}
//Gives class of .neighbor to neighboring tiles and attaches an onclick event. When clicked, the tile moves and the neighbors are refreshed.
function styleNeighbors(neighbors) {
for(var i = 0; i < neighbors.length; i++) {
neighbors[i].classList.add("neighbor");
//assign handlers
neighbors[i].onclick = function() {
move(this);
styleNeighbors(getNeighbors());
if(checkWin()) {
winShow(true);
}
};
}
}
//Gives initial tiles positions and background sections to display
function tilePosition(tile, row, col) {
var xCoord = col * tileSize;
var yCoord = row * tileSize;
tile.style.top = yCoord + "px";
tile.style.left = xCoord + "px";
tile.style.backgroundPosition = (xCoord * -1) + "px " + (yCoord * -1) + "px";
}
//Shows/hides win notice
function winShow(bool) {
var win = document.getElementById("win");
if(bool) {
win.style.display = "block";
} else {
win.style.display = "none";
}
}
})();