├── LICENSE.txt
├── css
└── crossword-puzzle.css
├── README.md
├── crossword-puzzle-demo.html
└── javascript
└── crossword-puzzle.js
/LICENSE.txt:
--------------------------------------------------------------------------------
1 | BSD 3-Clause License
2 |
3 | Copyright (c) 2017, Benjamin Tepolt
4 | All rights reserved.
5 |
6 | Redistribution and use in source and binary forms, with or without
7 | modification, are permitted provided that the following conditions are met:
8 |
9 | * Redistributions of source code must retain the above copyright notice, this
10 | list of conditions and the following disclaimer.
11 |
12 | * Redistributions in binary form must reproduce the above copyright notice,
13 | this list of conditions and the following disclaimer in the documentation
14 | and/or other materials provided with the distribution.
15 |
16 | * Neither the name of the copyright holder nor the names of its
17 | contributors may be used to endorse or promote products derived from
18 | this software without specific prior written permission.
19 |
20 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
23 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
24 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
26 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
27 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
28 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 |
--------------------------------------------------------------------------------
/css/crossword-puzzle.css:
--------------------------------------------------------------------------------
1 | .puzzle {
2 | border-collapse: collapse;
3 | border-color:#000000;
4 | }
5 |
6 | .letter-cell {
7 | text-align:center;
8 | height:40px;
9 | width:40px;
10 | }
11 |
12 | .letter-text {
13 | font-family:helvetica;
14 | font-weight:bold;
15 | }
16 |
17 | .list-text {
18 | font-family:helvetica;
19 | }
20 |
21 | .blank-cell {
22 | background-color:#000000;
23 | }
24 |
25 | .clickable {
26 | cursor:pointer;
27 | }
28 |
29 | .linkable {
30 | cursor:pointer;
31 | color:blue;
32 | text-decoration:underline;
33 | }
34 | .background-text {
35 | position: absolute;
36 | top: 0;
37 | left: 0;
38 | bottom: 0;
39 | right: 0;
40 | z-index: -1;
41 | overflow: hidden;
42 | }
43 |
44 | .strikeout {
45 | position: relative;
46 | }
47 |
48 | .strikeout::after {
49 | border-bottom: 0.250em solid blue;
50 | content: "";
51 | left: 0;
52 | margin-top: calc(0.125em / 2 * -1);
53 | position: absolute;
54 | right: 0;
55 | top: 50%;
56 | }
57 |
58 | .red-strikeout {
59 | position: relative;
60 | }
61 |
62 | .red-strikeout::after {
63 | border-bottom: 0.250em solid red;
64 | content: "";
65 | left: 0;
66 | margin-top: calc(0.250em / 2 * -1);
67 | position: absolute;
68 | right: 0;
69 | top: 50%;
70 | }
71 |
72 | .crossword-grid-cell-number {
73 | float: left;
74 | font-family: tahoma;
75 | font-size: 0.6em;
76 | }
77 |
78 | .relative-position {
79 | position: relative;
80 | }
81 |
82 | #answer-form {
83 | display: none;
84 | border: 2px solid black;
85 | font-family: tahoma;
86 | position: fixed;
87 | top: 50%;
88 | left: 50%;
89 | width: 30em;
90 | height: 12em;
91 | margin-top: -9em;
92 | margin-left: -15em;
93 | border: 1px solid #CCCCCC;
94 | background-color: #F3F3F3;
95 | }
96 |
97 | .short-margin {
98 | margin: 20px;
99 | }
100 |
101 | .hidden {
102 | display: none;
103 | }
104 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | 100% JQuery Crossword Puzzle Generator and Game
2 |
3 | Demo:
4 |
5 | http://www.earthfluent.com/crossword-puzzle-demo.html
6 |
7 | Example Usage:
8 |
9 | $(document).ready(function(event) {
10 | var puzzlewords = [
11 | // word, clue
12 | ['Incomplete', 'Some of us are always meant to be this.'],
13 | ['Ecosystem', 'Any system where life can grow and thrive.'],
14 | // ... etc..
15 | ];
16 | crosswordPuzzle(puzzlewords);
17 | });
18 |
19 | Fully supports internationalization. Examples in twelve different languages :
20 |
21 | * Spanish : https://www.earthfluent.com/spanish/nouns-concepts-part-35/play.php?action=CrosswordPuzzle&previousquizzes=10
22 | * French : https://www.earthfluent.com/french/nouns-concepts-part-35/play.php?action=CrosswordPuzzle&previousquizzes=10
23 | * Italian : https://www.earthfluent.com/italian/nouns-concepts-part-35/play.php?action=CrosswordPuzzle&previousquizzes=10
24 | * German : https://www.earthfluent.com/german/nouns-concepts-part-35/play.php?action=CrosswordPuzzle&previousquizzes=10
25 | * Japanese : https://www.earthfluent.com/japanese/nouns-concepts-part-35/play.php?action=CrosswordPuzzle&previousquizzes=10
26 | * Chinese : https://www.earthfluent.com/chinese/nouns-concepts-part-35/play.php?action=CrosswordPuzzle&previousquizzes=10
27 | * Hindi : https://www.earthfluent.com/hindi/nouns-concepts-part-35/play.php?action=CrosswordPuzzle&previousquizzes=10
28 | * Indonesian : https://www.earthfluent.com/indonesian/nouns-concepts-part-35/play.php?action=CrosswordPuzzle&previousquizzes=10
29 | * Dutch : https://www.earthfluent.com/dutch/nouns-concepts-part-35/play.php?action=CrosswordPuzzle&previousquizzes=10
30 | * Polish : https://www.earthfluent.com/polish/nouns-concepts-part-35/play.php?action=CrosswordPuzzle&previousquizzes=10
31 | * Portuguese : https://www.earthfluent.com/portuguese/nouns-concepts-part-35/play.php?action=CrosswordPuzzle&previousquizzes=10
32 | * Russian : https://www.earthfluent.com/russian/nouns-concepts-part-35/play.php?action=CrosswordPuzzle&previousquizzes=10
33 | * Korean : https://www.earthfluent.com/korean/nouns-concepts-part-35/play.php?action=CrosswordPuzzle&previousquizzes=10
34 |
--------------------------------------------------------------------------------
/crossword-puzzle-demo.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | 100% JQuery, Open-Source Crossword Puzzle Generator and Game
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 | Across
54 |
55 | |
56 |
57 |
58 | Down
59 |
60 | |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
82 |
83 |
84 |
85 |
86 |
--------------------------------------------------------------------------------
/javascript/crossword-puzzle.js:
--------------------------------------------------------------------------------
1 | // Set Globals
2 | // --------------------------------------------
3 |
4 | var crosswordclues = [];
5 |
6 | // Set Randomization Configs
7 | // --------------------------------------------
8 |
9 | function areWeInGodMode() {
10 | return false;
11 | return true;
12 | }
13 |
14 | function areWeRandomizingPuzzleWords() {
15 | return true;
16 | }
17 |
18 | function areWeRandomizingPuzzlePieces() {
19 | return true;
20 | }
21 |
22 | function areWeRandomizingAcrossDownChoices() {
23 | return true;
24 | }
25 |
26 | function areWeRandomizingAcrossDownLists() {
27 | return true;
28 | }
29 |
30 | // Main()
31 | // --------------------------------------------
32 |
33 | function crosswordPuzzle(puzzlewords) {
34 | var wordcount = puzzlewords.length;
35 |
36 | if(!puzzlewords || !wordcount) {
37 | console.log("Developer Error : Did you forget to load words?");
38 | return false;
39 | }
40 |
41 | if(areWeRandomizingPuzzleWords()) {
42 | puzzlewords = shuffle(puzzlewords);
43 | }
44 |
45 | var crosswords = generateCrosswordBlockSources(puzzlewords);
46 |
47 | var crosswordblocks = crosswords['blocks'];
48 | var crosswordclues = crosswords['clues'];
49 |
50 | var graphs = buildCrosswordBlocks(crosswordblocks);
51 | graphs = compactCrosswordBlockSources(graphs);
52 |
53 | if(areWeRandomizingPuzzlePieces()) {
54 | graphs = shuffle(graphs);
55 | }
56 |
57 | if(!graphs || !graphs.length) {
58 | console.log("Developer Error : Your words could not be made into graphs.");
59 | return false;
60 | }
61 |
62 | var fullgraph = buildCrosswordBlockGraphs(graphs);
63 | var wordlists = buildCrosswordLists(fullgraph['matrixpositions']);
64 |
65 | showCrossWordPuzzle(fullgraph['matrix']);
66 | showCrossWordLists(wordlists, crosswordclues);
67 | showCrossWordOptions();
68 |
69 | return true;
70 | }
71 |
72 | // User Form Actions
73 | // --------------------------------------------
74 |
75 | function showCrossWordOptions() {
76 | var solvefunction = function() {
77 | $('#solution-answer').val('');
78 | $('#answer-results').hide();
79 | $('#answer-results').html('');
80 |
81 | var word = $(this).attr('data-word');
82 | var acrosstext = $(this).attr('data-across') == 'false' ? 'Down' : 'Across';
83 | $('#position-and-clue').html('' + acrosstext + ' : ' + $(this).attr('data-clue'));
84 | $('#answer-form').show();
85 |
86 | if($(this).children('span').attr('data-solved')) {
87 | $('#answer-button').attr('disabled', true);
88 | $('#reveal-answer-button').attr('disabled', true);
89 |
90 | $('#answer-results').show();
91 | $('#answer-results').html('You have already solved this problem.');
92 |
93 | $('#solution-answer').val(word);
94 | } else {
95 | $('#solution-answer').attr('maxlength', word.length);
96 |
97 | $('#answer-button').attr('data-word', word);
98 | $('#reveal-answer-button').attr('data-word', word);
99 |
100 | var datax = $(this).attr('data-x');
101 |
102 | $('#answer-button').attr('data-x', datax);
103 | $('#reveal-answer-button').attr('data-x', datax);
104 |
105 | var datay = $(this).attr('data-y');
106 |
107 | $('#answer-button').attr('data-y', datay);
108 | $('#reveal-answer-button').attr('data-y', datay);
109 |
110 | var across = $(this).attr('data-across');
111 |
112 | $('#answer-button').attr('data-across', across);
113 | $('#reveal-answer-button').attr('data-across', across);
114 |
115 | $('#solution-answer').focus();
116 |
117 | $('#answer-button').attr('disabled', false);
118 | $('#reveal-answer-button').attr('disabled', false);
119 | }
120 |
121 | return false;
122 | }
123 |
124 | var closesolvefunction = function() {
125 | $('#answer-results').hide();
126 | $('#answer-form').hide();
127 | return false;
128 | }
129 |
130 | var answerfunction = function() {
131 | var word = $(this).attr('data-word');
132 | var answer = $('#solution-answer').val().toLowerCase();
133 |
134 | if(answer == word) {
135 | var across = $(this).attr('data-across');
136 |
137 | var x = parseInt($(this).attr('data-x'), 10);
138 | var y = parseInt($(this).attr('data-y'), 10);
139 |
140 | if(across && across != 'false') {
141 | for(var i = 0; i < answer.length; i++) {
142 | var newheight = y + i ;
143 | var letterposition = 'letter-position-' + x + '-' + newheight;
144 | $('#' + letterposition).text(answer[i]);
145 | }
146 | } else {
147 | for(var i = 0; i < answer.length; i++) {
148 | var newwidth = x + i ;
149 | var letterposition = 'letter-position-' + newwidth + '-' + y;
150 | $('#' + letterposition).text(answer[i]);
151 | }
152 | }
153 |
154 | $('#' + word + '-listing').addClass('strikeout');
155 | $('#' + word + '-listing').attr('data-solved', true);
156 |
157 | $('#answer-form').hide();
158 | } else {
159 | if(!$('#answer-results').is(':visible')) {
160 | $('#answer-results').show();
161 | $('#answer-results').html('Incorrect Answer, Please Try Again');
162 | }
163 | }
164 |
165 | return false;
166 | }
167 |
168 | var revealanswerfunction = function() {
169 | var word = $(this).attr('data-word');
170 | var across = $(this).attr('data-across');
171 |
172 | var x = parseInt($(this).attr('data-x'), 10);
173 | var y = parseInt($(this).attr('data-y'), 10);
174 |
175 | if(across && across != 'false') {
176 | for(var i = 0; i < word.length; i++) {
177 | var newheight = y + i ;
178 | var letterposition = 'letter-position-' + x + '-' + newheight;
179 | $('#' + letterposition).text(word[i]);
180 | }
181 | } else {
182 | for(var i = 0; i < word.length; i++) {
183 | var newwidth = x + i ;
184 | var letterposition = 'letter-position-' + newwidth + '-' + y;
185 | $('#' + letterposition).text(word[i]);
186 | }
187 | }
188 |
189 | $('#' + word + '-listing').addClass('red-strikeout');
190 | $('#' + word + '-listing').attr('data-solved', true);
191 |
192 | $('#answer-form').hide();
193 | }
194 |
195 | $('.word-clue').click(solvefunction);
196 | $('#cancel-button').click(closesolvefunction);
197 | $('#answer-button').click(answerfunction);
198 | $('#reveal-answer-button').click(revealanswerfunction);
199 | }
200 |
201 | // Show Crossword Lists
202 | // --------------------------------------------
203 |
204 | function showCrossWordLists(wordlists, clues) {
205 | var acrosslist = wordlists['across'];
206 | var downlist = wordlists['down'];
207 |
208 | if(areWeRandomizingAcrossDownLists()) {
209 | acrosslist = shuffle(acrosslist);
210 | downlist = shuffle(downlist);
211 | }
212 |
213 | var acrosslistordered = fillInCrossWordNumbers(acrosslist);
214 | var downlistordered = fillInCrossWordNumbers(downlist, acrosslist, acrosslistordered);
215 |
216 | var acrosslistorderedelement = getViewableCrossWordList(acrosslistordered, clues, true);
217 | var downlistorderedelement = getViewableCrossWordList(downlistordered, clues, false);
218 |
219 | $('#left-list').append(acrosslistorderedelement);
220 | $('#right-list').append(downlistorderedelement);
221 | }
222 |
223 | function getViewableCrossWordList(listitems, clues, across) {
224 | var numbers = Object.keys(listitems);
225 |
226 | var element = '';
227 |
228 | for(var i = 0; i < numbers.length; i++) {
229 | var number = numbers[i];
230 | var wordinfo = listitems[number];
231 | var word = wordinfo['word'];
232 | var coordinates = wordinfo['coordinates'];
233 | var clue = clues[word];
234 |
235 | element += '- ';
243 | element += number + ' : ' ;
244 | element += '';
248 | element += clue;
249 | element += '';
250 | element += '
';
251 | }
252 |
253 | element += '
';
254 |
255 | return element;
256 | }
257 |
258 | function fillInCrossWordNumbers(listitems, blockitems, blockitemsordered) {
259 | var orderedlist = [];
260 | var listnumber = 0;
261 | for(var i = 0; i < listitems.length; i++) {
262 | listnumber++;
263 |
264 | var listitem = listitems[i];
265 | var word = listitem['word'];
266 | var coordinates = listitem['position'];
267 |
268 | var blockingitemnumber = getBlockingItemNumber(coordinates, blockitems, blockitemsordered);
269 |
270 | fillnumber = listnumber;
271 | if(blockingitemnumber) {
272 | fillnumber = blockingitemnumber;
273 | }
274 |
275 | var element = '' + fillnumber + '
';
276 |
277 | var parentelement;
278 |
279 | parentelement = $('#cell-position-' + coordinates[0] + '-' + coordinates[1]);
280 |
281 | if(parentelement && $(parentelement).attr('id')) {
282 | $(parentelement).prepend(element);
283 | }
284 |
285 | orderedlist[listnumber] = {
286 | 'word':word,
287 | 'coordinates':coordinates,
288 | };
289 | }
290 |
291 | return orderedlist;
292 | }
293 |
294 | function getBlockingItemNumber(coordinates, blockitems, blockitemsordered) {
295 | if(!blockitems || !blockitems.length || !blockitemsordered || !blockitemsordered.length) {
296 | return false;
297 | }
298 | for (var i = 0; i < blockitems.length; i++) {
299 | var blockitem = blockitems[i];
300 |
301 | var blockcoordinates = blockitem['position'];
302 |
303 | if(blockcoordinates[0] == coordinates[0] && blockcoordinates[1] == coordinates[1]) {
304 | return getBlockItemNumberPosition(blockitem['word'], blockitemsordered);
305 | }
306 | }
307 |
308 | return false;
309 | }
310 |
311 | function getBlockItemNumberPosition(word, items) {
312 | var itemkeys = Object.keys(items);
313 |
314 | for(var i = 0; i < itemkeys.length; i++) {
315 | var itemkey = itemkeys[i];
316 |
317 | var itemword = items[itemkey];
318 |
319 | if(itemword.word == word) {
320 | return itemkey;
321 | }
322 | }
323 | }
324 |
325 | // Show Crossword Puzzle
326 | // --------------------------------------------
327 |
328 | function showCrossWordPuzzle(matrix) {
329 | var widestline = getWidestLine(matrix);
330 | var tallestline = getTallestLine(matrix);
331 |
332 | var table = $('');
333 |
334 | for(var i = 0; i < tallestline; i++) {
335 | var tablerow = '';
336 |
337 | for(var j = 0; j < widestline; j++) {
338 | var cellclass = 'letter-cell';
339 |
340 | if(!matrix[i][j] || matrix[i][j] == ' ') {
341 | cellclass += ' blank-cell';
342 |
343 | }
344 | tablerow += '| ';
345 |
346 | tablerow += '';
347 |
348 | if(areWeInGodMode() && matrix[i][j] && matrix[i][j] != ' ') {
349 | tablerow += matrix[i][j];
350 | }
351 |
352 | tablerow += '';
353 |
354 | tablerow += ' | ';
355 | }
356 |
357 | tablerow += '
';
358 |
359 | $(table).append(tablerow);
360 | }
361 |
362 | $('#root').append(table);
363 |
364 | return true;
365 | }
366 |
367 | function buildCrosswordLists(matrixpositions) {
368 | var acrosslist = [];
369 | var downlist = [];
370 |
371 | for(var i = 0; i < matrixpositions.length; i++) {
372 | var matrixposition = matrixpositions[i];
373 |
374 | var across = matrixposition['across'];
375 | var word = matrixposition['word'];
376 | var positions = matrixposition['matrixpositions'];
377 |
378 | var primaryelement = {
379 | 'word':word,
380 | 'position':positions[word],
381 | }
382 |
383 | delete positions[word];
384 | if(across) {
385 | if(word != '(unmatched)') {
386 | acrosslist.push(primaryelement);
387 | }
388 | downlist = buildCrosswordList(downlist, positions);
389 | } else {
390 | if(word != '(unmatched)') {
391 | downlist.push(primaryelement);
392 | }
393 | acrosslist = buildCrosswordList(acrosslist, positions);
394 | }
395 | }
396 |
397 | return {
398 | 'across':acrosslist,
399 | 'down':downlist,
400 | };
401 | }
402 |
403 | function buildCrosswordList(list, positions) {
404 | var matrixpositionwords = Object.keys(positions);
405 |
406 | for(var i = 0; i < matrixpositionwords.length; i++) {
407 | var matrixpositionword = matrixpositionwords[i];
408 |
409 | var coordinates = positions[matrixpositionword];
410 |
411 | list.push({
412 | 'word':matrixpositionword,
413 | 'position':coordinates,
414 | });
415 | }
416 |
417 | return list;
418 | }
419 |
420 | // Build Crossword
421 | // --------------------------------------------
422 |
423 | function buildCrosswordBlockGraphs(graphs) {
424 | var firstgraph = graphs.shift();
425 |
426 | var fullmatrix = firstgraph['matrix'];
427 | var fullmatrixpositions = [{
428 | 'matrixpositions':firstgraph['matrixpositions'],
429 | 'across':firstgraph['across'],
430 | 'word':firstgraph['word'],
431 | }];
432 |
433 | for(var i = 0; i < graphs.length; i++) {
434 | var graph = graphs[i];
435 |
436 | var matrix = graph['matrix'];
437 | var matrixpositions = graph['matrixpositions'];
438 | var across = graph['across'];
439 | var word = graph['word'];
440 |
441 | console.log("BT: BUILD BLOCK GRAPH...|" + i + "|" + word + "|");
442 | console.info(matrixpositions);
443 |
444 | var widestline = getWidestLine(fullmatrix);
445 | var tallestline = getTallestLine(fullmatrix);
446 |
447 | var buildvertically = checkToBuildVertically(fullmatrix, matrix, widestline, tallestline);
448 | var built = false;
449 |
450 | if(!buildvertically) {
451 | // I AM LEAF!!!
452 | var possiblefullmatrixsolution = false;
453 | var possiblefullmatrixcoordinates = [];
454 | var shortestlinelength = 99999999;
455 |
456 | for(var j = 0; j < fullmatrix.length; j++) {
457 | var trimmedfullmatrixline = rtrim(fullmatrix[j]);
458 | if(trimmedfullmatrixline.length > 0 && trimmedfullmatrixline.length < shortestlinelength) {
459 | var solutioncoordinates = [trimmedfullmatrixline.length,j + i];
460 | var newerpossiblefullmatrixsolution = joinHorizontalMatrices(fullmatrix, matrix, solutioncoordinates);
461 | if(newerpossiblefullmatrixsolution) {
462 | shortestlinelength = getThinnestLine(newerpossiblefullmatrixsolution);
463 | possiblefullmatrixsolution = newerpossiblefullmatrixsolution;
464 | possiblefullmatrixcoordinates = solutioncoordinates;
465 |
466 | canmutate = true;
467 | var leftpushback = 1;
468 |
469 | while(canmutate && (trimmedfullmatrixline.length - leftpushback) >= 0) {
470 | console.log("BT: Across ALPHA.");
471 | solutioncoordinates = [trimmedfullmatrixline.length - leftpushback,j + i];
472 | var newestpossiblefullmatrixsolution = joinHorizontalMatrices(fullmatrix, matrix, solutioncoordinates);
473 | if(newestpossiblefullmatrixsolution) {
474 | shortestlinelength = getThinnestLine(newestpossiblefullmatrixsolution);
475 | possiblefullmatrixsolution = newestpossiblefullmatrixsolution;
476 | possiblefullmatrixcoordinates = solutioncoordinates;
477 | leftpushback++;
478 | } else {
479 | canmutate = false;
480 | leftpushback--;
481 | }
482 | }
483 |
484 | var toppushback = 1;
485 |
486 | while((j + i) - toppushback > 0) {
487 | solutioncoordinates = [trimmedfullmatrixline.length - leftpushback,(j + i) - toppushback];
488 | var newestpossiblefullmatrixsolution = joinHorizontalMatrices(fullmatrix, matrix, solutioncoordinates);
489 | if(newestpossiblefullmatrixsolution) {
490 | shortestlinelength = getThinnestLine(newestpossiblefullmatrixsolution);
491 | possiblefullmatrixsolution = newestpossiblefullmatrixsolution;
492 | possiblefullmatrixcoordinates = solutioncoordinates;
493 | }
494 |
495 | toppushback++;
496 | }
497 |
498 | toppushback--;
499 |
500 | canmutate = true;
501 | var leftpushback = 1;
502 |
503 | while(canmutate && (trimmedfullmatrixline.length - leftpushback) >= 0) {
504 | solutioncoordinates = [trimmedfullmatrixline.length - leftpushback,j + i - toppushback];
505 | var newestpossiblefullmatrixsolution = joinHorizontalMatrices(fullmatrix, matrix, solutioncoordinates);
506 | if(newestpossiblefullmatrixsolution) {
507 | shortestlinelength = getThinnestLine(newestpossiblefullmatrixsolution);
508 | possiblefullmatrixsolution = newestpossiblefullmatrixsolution;
509 | possiblefullmatrixcoordinates = solutioncoordinates;
510 | leftpushback++;
511 | } else {
512 | canmutate = false;
513 | leftpushback--;
514 | }
515 | }
516 | }
517 | }
518 | }
519 |
520 | if(possiblefullmatrixsolution) {
521 | fullmatrix = possiblefullmatrixsolution;
522 | console.info(matrixpositions);
523 | matrixpositions = interpolateMatrixPositions(matrixpositions, [possiblefullmatrixcoordinates[1], possiblefullmatrixcoordinates[0]]);
524 | fullmatrixpositions.push({
525 | 'matrixpositions':matrixpositions,
526 | 'across':across,
527 | 'word':word,
528 | });
529 | built = true;
530 | }
531 | }
532 |
533 | if(buildvertically || !built) {
534 | console.log("BT: Vertical ALPHA.");
535 | // AND I AM TWIG!!!
536 | var oldlength = fullmatrix.length;
537 | fullmatrixbottom = fullmatrix[fullmatrix.length - 1];
538 | for(var j = 0; j < widestline; j++) {
539 | var smallmatrixtop = matrix[0];
540 | if(nonConflictingRows(fullmatrixbottom, smallmatrixtop)) {
541 | fullmatrix = joinVerticalMatrices(fullmatrix, matrix);
542 | solutioncoordinates = [oldlength, j];
543 | matrixpositions = interpolateMatrixPositions(matrixpositions, solutioncoordinates);
544 | fullmatrixpositions.push({
545 | 'matrixpositions':matrixpositions,
546 | 'across':across,
547 | 'word':word,
548 | });
549 | j = widestline;
550 | built = true;
551 | } else {
552 | matrix = incrementMatrixHorizontally(matrix);
553 | }
554 | }
555 |
556 | if(!built) {
557 | viewPuzzle(matrix);
558 |
559 | solutioncoordinates = [fullmatrix.length + 1, 0];
560 | matrix = compactCrosswordBlockSource({'matrix':matrix})['matrix'];
561 | fullmatrix.push('');
562 | fullmatrix = joinVerticalMatrices(fullmatrix, matrix);
563 |
564 | matrixpositions = interpolateMatrixPositions(matrixpositions, solutioncoordinates);
565 |
566 | console.info(matrixpositions);
567 | fullmatrixpositions.push({
568 | 'matrixpositions':matrixpositions,
569 | 'across':across,
570 | 'word':word,
571 | });
572 | }
573 | }
574 |
575 | fullmatrix = compactCrosswordBlockSource({'matrix':fullmatrix})['matrix'];
576 | }
577 |
578 | var fullgraph = {
579 | 'matrix':fullmatrix,
580 | 'matrixpositions':fullmatrixpositions,
581 | };
582 |
583 | return fullgraph;
584 | }
585 |
586 | function interpolateMatrixPositions(matrixpositions, coordinates, word) {
587 | var matrixpositionwords = Object.keys(matrixpositions);
588 |
589 | for(var i = 0; i < matrixpositionwords.length; i++) {
590 | var matrixpositionword = matrixpositionwords[i];
591 | var matrixpositioncoordinates = matrixpositions[matrixpositionword];
592 | matrixpositioncoordinates[0] += coordinates[0];
593 | matrixpositioncoordinates[1] += coordinates[1];
594 | }
595 |
596 | return matrixpositions;
597 | }
598 |
599 | function viewPuzzle(puzzle) {
600 | console.log("Viewing puzzle from...|" + arguments.callee.caller.name + "|");
601 | console.info(JSON.stringify(puzzle).replace(/,/g, ",\n"));
602 | }
603 |
604 | function rtrim(string){
605 | if(!string) {
606 | return "";
607 | }
608 | return string.replace(/\s+$/, '');
609 | }
610 |
611 | function joinHorizontalMatrices(fullmatrix, matrix, coordinates) {
612 | if(coordinates[0] == 0 || coordinates[1] == 0) {
613 | return false;
614 | }
615 | originalfullmatrix = fullmatrix;
616 | var maxheight = fullmatrix.length + matrix.length;
617 | fullmatrix = fullmatrix.slice();
618 | for(var i = 0; i < matrix.length; i++) {
619 | var line = matrix[i];
620 |
621 | for(var j = 0; j < line.length; j++) {
622 | var x = coordinates[0];
623 | var y = coordinates[1];
624 |
625 | x += j;
626 | y += i;
627 |
628 | if(!fullmatrix[y]) {
629 | fullmatrix[y] = "";
630 | }
631 |
632 | if(fullmatrix[y] && fullmatrix[y][x] && fullmatrix[y][x] != ' ' && matrix[i][j] != ' ') {
633 | return false;
634 | } else {
635 | if(matrix[i][j] != ' ') {
636 | if(originalfullmatrix[y - 1] && originalfullmatrix[y - 1][x] && originalfullmatrix[y - 1][x] != ' ') {
637 | return false;
638 | }
639 |
640 | if(originalfullmatrix[y + 1] && originalfullmatrix[y + 1][x] && originalfullmatrix[y + 1][x] != ' ') {
641 | return false;
642 | }
643 |
644 | if(originalfullmatrix[y] && originalfullmatrix[y][x - 1] && originalfullmatrix[y][x - 1] != ' ') {
645 | return false;
646 | }
647 |
648 | if(originalfullmatrix[y] && originalfullmatrix[y][x + 1] && originalfullmatrix[y][x + 1] != ' ') {
649 | return false;
650 | }
651 | }
652 | }
653 |
654 | while(!fullmatrix[y][x]) {
655 | fullmatrix[y] += ' ';
656 | }
657 | if(matrix[i][j] != ' ') {
658 | fullmatrix[y] = insertLetterAtStringPosition(matrix[i][j], fullmatrix[y], x);
659 | }
660 | }
661 | }
662 |
663 | return fullmatrix;
664 | }
665 |
666 | function joinVerticalMatrices(bigmatrix, smallmatrix) {
667 | var height = bigmatrix.length;
668 |
669 | for(var i = 0; i < smallmatrix.length; i++) {
670 | bigmatrix[height + i] = smallmatrix[i];
671 | }
672 |
673 | return bigmatrix;
674 | }
675 |
676 | function nonConflictingRows(toprow, bottomrow) {
677 | var rowtocheck;
678 |
679 | if(toprow[bottomrow.length] && toprow[bottomrow.length] == ' ') {
680 | return false;
681 | }
682 |
683 | if(toprow.length > bottomrow.length) {
684 | rowtocheck = bottomrow;
685 | altrowtocheck = toprow;
686 | } else {
687 | rowtocheck = toprow;
688 | altrowtocheck = bottomrow;
689 | }
690 |
691 | for(var i = 0; i < rowtocheck.length; i++) {
692 | if(rowtocheck[i] && altrowtocheck[i]) {
693 | if(rowtocheck[i] != ' ' && altrowtocheck[i] != ' ') {
694 | return false;
695 | }
696 | }
697 | }
698 |
699 | return true;
700 | }
701 |
702 | function incrementMatrixHorizontally(matrix) {
703 | for(var i = 0; i < matrix.length; i++) {
704 | matrix[i] = ' ' + matrix[i];
705 | }
706 |
707 | return matrix;
708 | }
709 |
710 | function checkToBuildVertically(matrix, smallmatrix, widestline, tallestline) {
711 | if(matrix.length <= smallmatrix.length) {
712 | return true;
713 | } else if(tallestline < widestline) {
714 | return true;
715 | } else if(widestline < tallestline) {
716 | return false;
717 | }
718 |
719 | return randomTrueFalse();
720 | }
721 |
722 | function randomTrueFalse() {
723 | return Math.random() > 0.5 ? true : false;
724 | }
725 |
726 | function getWidestLine(matrix) {
727 | var widestlength = 0;
728 |
729 | for(var i = 0; i < matrix.length; i++) {
730 | var row = matrix[i];
731 | if(row && row.length && row.length > widestlength) {
732 | widestlength = row.length;
733 | }
734 | }
735 |
736 | return widestlength;
737 | }
738 |
739 | function getThinnestLine(matrix) {
740 | var thinnestlength = 999999;
741 |
742 | for(var i = 0; i < matrix.length; i++) {
743 | var row = matrix[i];
744 | if(row && row.length < thinnestlength) {
745 | thinnestlength = row.length;
746 | }
747 | }
748 |
749 | return thinnestlength;
750 | }
751 |
752 | function getTallestLine(matrix) {
753 | return matrix.length;
754 | }
755 |
756 | function buildCrosswordBlocks(crosswordblocks) {
757 | var graphs = [];
758 | var lastacross = false;
759 |
760 | for (var word in crosswordblocks) {
761 | if (!crosswordblocks.hasOwnProperty(word) || word == '(unmatched)') continue;
762 |
763 | var subwords = crosswordblocks[word];
764 | var longestwordlength = getLongestWordLength(subwords);
765 |
766 | var across = true;
767 |
768 | if(areWeRandomizingAcrossDownChoices()) {
769 | across = randomTrueFalse();
770 | }
771 |
772 | var matrix = [];
773 | var matrixpositions = [];
774 |
775 | if(across) {
776 | matrix[longestwordlength - 1] = word;
777 | matrixpositions[word] = [longestwordlength - 1, 0];
778 |
779 | for(var i = 0; i < subwords.length; i++) {
780 | var subwordentry = subwords[i];
781 |
782 | var subword = subwordentry[0];
783 | var subletter = subwordentry[1];
784 |
785 | var matchingposition = findMatchingLetterMatrixPosition(matrix, word, subletter, longestwordlength - 2);
786 | var matchingoffset = findMatchingOffset(subword, subletter);
787 | matrixpositions[subword] = [longestwordlength - matchingoffset - 1, matchingposition];
788 | matrix = setLetterMatrixVertically(matrix, subword, longestwordlength - matchingoffset - 1, matchingposition);
789 | }
790 | } else {
791 | matrix = fillLetterMatrixVertically(matrix, word, longestwordlength + 1, 0);
792 | matrixpositions[word] = [0, longestwordlength];
793 |
794 | for(var i = 0; i < subwords.length; i++) {
795 | var subwordentry = subwords[i];
796 |
797 | var subword = subwordentry[0];
798 | var subletter = subwordentry[1];
799 | var matchingposition = findMatchingLetterMatrixPositionVertical(matrix, word, subletter, longestwordlength - 1);
800 | var matchingoffset = findMatchingOffset(subword, subletter);
801 | matrixpositions[subword] = [matchingposition, longestwordlength - matchingoffset];
802 | matrix = setLetterMatrixHorizontally(matrix, subword, matchingposition, longestwordlength - matchingoffset);
803 | }
804 | }
805 | var graph = {
806 | 'matrix':matrix,
807 | 'matrixpositions':matrixpositions,
808 | 'across':across,
809 | 'word':word,
810 | };
811 |
812 | graphs.push(graph);
813 | }
814 |
815 | if(crosswordblocks['(unmatched)']) {
816 | var graph = buildUnassignedCrosswordBlock(crosswordblocks['(unmatched)']);
817 | graphs.push(graph);
818 | }
819 |
820 | return graphs;
821 | }
822 |
823 | function buildUnassignedCrosswordBlock(unmatchedcrosswords) {
824 | var across = true;
825 |
826 | if(areWeRandomizingAcrossDownChoices()) {
827 | across = randomTrueFalse();
828 | }
829 |
830 | var longestwordlength = getLongestWordLength(unmatchedcrosswords);
831 |
832 | var matrix = [];
833 | var matrixpositions = [];
834 |
835 | if(across) {
836 | for(var i = 0; i < unmatchedcrosswords.length; i++) {
837 | var unmatchedcrossword = unmatchedcrosswords[i];
838 | matrix[i] = unmatchedcrossword;
839 | matrixpositions[unmatchedcrossword] = [0,i];
840 | }
841 | } else {
842 | for(var i = 0; i < unmatchedcrosswords.length; i++) {
843 | var unmatchedcrossword = unmatchedcrosswords[i];
844 | matrix = setLetterMatrixVertically(matrix, unmatchedcrossword, 0, i);
845 | matrixpositions[unmatchedcrossword] = [i,0];
846 | }
847 | }
848 |
849 | var graph = {
850 | 'matrix':matrix,
851 | 'matrixpositions':matrixpositions,
852 | 'across':!across,
853 | 'word':'(unmatched)',
854 | };
855 |
856 | return graph;
857 | }
858 |
859 | function insertLetterAtStringPosition(letter, string, position) {
860 | if(!letter) {
861 | letter = ' ';
862 | }
863 | return string.substr(0, position) + letter + string.substr(position + 1);
864 | }
865 |
866 | function setLetterMatrixHorizontally(matrix, word, y, x) {
867 | for(var i = 0; i < word.length; i++) {
868 | var position = i + x;
869 | if(!matrix[y]) {
870 | matrix[y] = '';
871 | }
872 | letters = matrix[y];
873 |
874 | if(letters.length < position) {
875 | while(letters.length < position) {
876 | letters += ' ';
877 | }
878 | letters += word[i];
879 | } else {
880 | letters = insertLetterAtStringPosition(word[i], letters, position);
881 | }
882 |
883 | matrix[y] = letters;
884 | }
885 | return matrix;
886 | }
887 |
888 | function setLetterMatrixVertically(matrix, word, y, x) {
889 | for(var i = 0; i < word.length; i++) {
890 | var position = i + y;
891 | if(!matrix[position]) {
892 | matrix[position] = '';
893 | }
894 | letters = matrix[position];
895 |
896 | if(letters.length < x) {
897 | while(letters.length < x) {
898 | letters += ' ';
899 | }
900 |
901 | letters += word[i];
902 | } else {
903 | letters = insertLetterAtStringPosition(word[i], letters, x);
904 | }
905 |
906 | matrix[position] = letters;
907 | }
908 | return matrix;
909 | }
910 |
911 | function findMatchingOffset(word, letter) {
912 | for(var i = 0; i < word.length; i++) {
913 | if(word[i] == letter) {
914 | return i;
915 | }
916 | }
917 | return false;
918 | }
919 |
920 | function findMatchingLetterMatrixPositionVertical(matrix, word, subletter, index) {
921 | for(var i = 0; i < word.length; i++) {
922 | var letter = word[i];
923 | if(!matrix[i]) {
924 | matrix[i] = '';
925 | }
926 |
927 | if(subletter == letter && (!matrix[i][index] || matrix[i][index] == ' ') && (!matrix[i][index + 2] || matrix[i][index + 2] == ' ')) {
928 | return i;
929 | }
930 | }
931 | return false;
932 | }
933 |
934 | function findMatchingLetterMatrixPosition(matrix, word, subletter, index) {
935 | for(var i = 0; i < word.length; i++) {
936 | var letter = word[i];
937 | if(!matrix[index]) {
938 | matrix[index] = '';
939 | }
940 | if(subletter == letter && (!matrix[index][i] || matrix[index][i] == ' ') && (!matrix[index + 2] || !matrix[index + 2][i] || matrix[index + 2][i] == ' ')) {
941 | return i;
942 | }
943 | }
944 | return false;
945 | }
946 |
947 | function fillLetterMatrixVertically(matrix, word, index) {
948 | var spacing = Array(index).join(" ");
949 | for(var i = 0; i < word.length; i++) {
950 | matrix[i] = spacing + word[i];
951 | }
952 | return matrix;
953 | }
954 |
955 | function buildUnmatchedBlock(unmatchedblock) {
956 | return unmatchedblock;
957 | }
958 |
959 | function getLongestWordLength(words) {
960 | var length = 0;
961 |
962 | for(var i = 0; i < words.length; i++) {
963 | var word = words[i];
964 | var wordlength = word[0].length;
965 | if(wordlength > length) {
966 | length = wordlength;
967 | }
968 | }
969 |
970 | return length;
971 | }
972 |
973 | function compactCrosswordBlockSources(graphs) {
974 | for(var i = 0; i < graphs.length; i++) {
975 | var graph = graphs[i];
976 |
977 | var matrix = graph['matrix'];
978 |
979 | graph = compactCrosswordBlockSource(graph);
980 |
981 | graphs[i] = graph;
982 | }
983 | return graphs;
984 | }
985 |
986 | function compactCrosswordBlockSource(graph) {
987 | graph = compactCrosswordBlockBottom(graph);
988 | graph = compactCrosswordBlockTop(graph);
989 | graph = compactCrosswordBlockLeft(graph);
990 | graph = compactCrosswordBlockRight(graph);
991 | return graph;
992 | }
993 |
994 | function compactCrosswordBlockTop(graph) {
995 | var crosswordblock = graph['matrix'];
996 | var crosswordblocksolutions = graph['matrixpositions'];
997 | var crosswordblockacross = graph['across'];
998 |
999 | var crosswordblocklength = crosswordblock.length;
1000 |
1001 | for(var i = 0; i < crosswordblocklength; i++) {
1002 | var row = crosswordblock[i];
1003 | var trimmedrow = $.trim(row);
1004 | if(!row || !trimmedrow.length) {
1005 | crosswordblock.splice(i, 1);
1006 | crosswordblocksolutions = incrementCrossWordBlockHeights(crosswordblocksolutions);
1007 | i--;
1008 | crosswordblocklength--;
1009 | } else {
1010 | i = crosswordblocklength;
1011 | }
1012 | }
1013 |
1014 | graph['matrix'] = crosswordblock;
1015 | graph['matrixpositions'] = crosswordblocksolutions;
1016 |
1017 | return graph;
1018 | }
1019 |
1020 | function incrementCrossWordBlockHeights(crosswordblocksolutions) {
1021 | if(!crosswordblocksolutions) {
1022 | return crosswordblocksolutions;
1023 | }
1024 |
1025 | crosswordblockwords = Object.keys(crosswordblocksolutions);
1026 | for(var i = 0; i < crosswordblockwords.length; i++) {
1027 | var crosswordblockword = crosswordblockwords[i];
1028 |
1029 | crosswordblocksolutions[crosswordblockword][0]--;
1030 | }
1031 | return crosswordblocksolutions;
1032 | }
1033 |
1034 | function incrementCrossWordBlockLengths(crosswordblocksolutions) {
1035 | if(!crosswordblocksolutions) {
1036 | return crosswordblocksolutions;
1037 | }
1038 |
1039 | crosswordblockwords = Object.keys(crosswordblocksolutions);
1040 | for(var i = 0; i < crosswordblockwords.length; i++) {
1041 | var crosswordblockword = crosswordblockwords[i];
1042 |
1043 | crosswordblocksolutions[crosswordblockword][1]--;
1044 | }
1045 | return crosswordblocksolutions;
1046 | }
1047 |
1048 | function compactCrosswordBlockBottom(graph) {
1049 | var crosswordblock = graph['matrix'];
1050 | var crosswordblocksolutions = graph['matrixpositions'];
1051 | var crosswordblockacross = graph['across'];
1052 |
1053 | var crosswordblocklength = crosswordblock.length;
1054 | for(var i = crosswordblocklength - 1; i >= 0; i--) {
1055 | var row = crosswordblock[i];
1056 | var trimmedrow = $.trim(row);
1057 | if(!trimmedrow.length) {
1058 | crosswordblock.splice(i, 1);
1059 | } else {
1060 | i = -1;
1061 | }
1062 | }
1063 |
1064 | graph['matrix'] = crosswordblock;
1065 | graph['matrixpositions'] = crosswordblocksolutions;
1066 |
1067 | return graph;
1068 | }
1069 |
1070 | function compactCrosswordBlockLeft(graph) {
1071 | var crosswordblock = graph['matrix'];
1072 | var crosswordblocksolutions = graph['matrixpositions'];
1073 | var crosswordblockacross = graph['across'];
1074 |
1075 | var crosswordblocklength = crosswordblock.length;
1076 |
1077 | var shorten = true;
1078 |
1079 | while(shorten) {
1080 | if(crosswordblocklength) {
1081 | for(var i = 0; i < crosswordblocklength; i++) {
1082 | if(crosswordblock[i]) {
1083 | var crosswordrow = crosswordblock[i];
1084 | if(crosswordrow && crosswordrow[0] && crosswordrow[0] != ' ') {
1085 | shorten = false;
1086 | i = crosswordblocklength;
1087 | }
1088 | }
1089 | }
1090 | } else {
1091 | shorten = false;
1092 | }
1093 |
1094 | if(shorten) {
1095 | for(var i = 0; i < crosswordblocklength; i++) {
1096 | var crosswordrow = crosswordblock[i];
1097 | crosswordblock[i] = crosswordrow.substr(1, crosswordrow.length);
1098 | }
1099 |
1100 | crosswordblocksolutions = incrementCrossWordBlockLengths(crosswordblocksolutions);
1101 | }
1102 | }
1103 |
1104 | graph['matrix'] = crosswordblock;
1105 | graph['matrixpositions'] = crosswordblocksolutions;
1106 |
1107 | return graph;
1108 | }
1109 |
1110 | function compactCrosswordBlockRight(graph) {
1111 | var crosswordblock = graph['matrix'];
1112 | var crosswordblocksolutions = graph['matrixpositions'];
1113 | var crosswordblockacross = graph['across'];
1114 |
1115 | var longestpiece = getWidestLine(crosswordblock) - 1;
1116 | var crosswordblocklength = crosswordblock.length;
1117 |
1118 | var shorten = true;
1119 |
1120 | while(shorten) {
1121 | if(crosswordblocklength) {
1122 | for(var i = 0; i < crosswordblocklength; i++) {
1123 | if(crosswordblock[i]) {
1124 | var crosswordrow = crosswordblock[i];
1125 | if(crosswordrow[longestpiece] && crosswordrow[longestpiece] != ' ') {
1126 | shorten = false;
1127 | i = crosswordblocklength;
1128 | }
1129 | }
1130 | }
1131 | } else {
1132 | shorten = false;
1133 | }
1134 | if(shorten) {
1135 | longestpiece--;
1136 | for(var i = 0; i < crosswordblocklength; i++) {
1137 | var crosswordrow = crosswordblock[i];
1138 | crosswordblock[i] = crosswordrow.substr(0, crosswordrow.length - 1);
1139 | }
1140 | }
1141 | }
1142 |
1143 | graph['matrix'] = crosswordblock;
1144 | graph['matrixpositions'] = crosswordblocksolutions;
1145 |
1146 | return graph;
1147 | }
1148 |
1149 | function generateCrosswordBlockSources(shuffledwords) {
1150 | var crosswordblocks = [];
1151 | var checkedcrosswords = [];
1152 | var clues = [];
1153 | for(var i = 0; i < shuffledwords.length; i++) {
1154 | var shuffledword = shuffledwords[i];
1155 | var word = shuffledword[0].toLowerCase();
1156 | var clue = shuffledword[1];
1157 | clues[word] = clue;
1158 |
1159 | crosswordclues[word] = clue;
1160 |
1161 | var checkedcrosswordkey = word + '-' + clue;
1162 |
1163 | var unmatchedwords = [];
1164 |
1165 | if(!checkedcrosswords[checkedcrosswordkey]) {
1166 | var wordletters = getLettersHashCountForWord(word);
1167 | var crosswordblock = [];
1168 |
1169 | for(var j = i + 1; j < shuffledwords.length; j++) {
1170 | var nextshuffledword = shuffledwords[j];
1171 |
1172 | var nextword = nextshuffledword[0].toLowerCase();
1173 | var nextclue = nextshuffledword[1];
1174 | var nextcrosswordkey = nextword + '-' + nextclue;
1175 |
1176 | if(!checkedcrosswords[nextcrosswordkey]) {
1177 | var matchingletter = getMatchingLetter(wordletters, nextword);
1178 | if(matchingletter && matchingletter.length) {
1179 | wordletters[matchingletter]--;
1180 | checkedcrosswords[nextcrosswordkey] = true;
1181 | crosswordblock.push([nextword, matchingletter]);
1182 | }
1183 | }
1184 | }
1185 |
1186 | if(crosswordblock.length) {
1187 | crosswordblocks[word] = crosswordblock;
1188 | } else {
1189 | unmatchedwords.push(word);
1190 | }
1191 | checkedcrosswords[checkedcrosswordkey] = true;
1192 | }
1193 |
1194 | if(unmatchedwords.length) {
1195 | crosswordblocks['(unmatched)'] = unmatchedwords;
1196 | }
1197 | }
1198 |
1199 | return {
1200 | 'blocks':crosswordblocks,
1201 | 'clues':clues,
1202 | };
1203 | }
1204 |
1205 | function getLettersHashPositionsForWord(word) {
1206 | var lettershash = [];
1207 |
1208 | for(var i = 0; i < word.length; i++) {
1209 | var letter = word[i];
1210 | if(lettershash[letter]) {
1211 | lettershash[letter].push(i);
1212 | } else {
1213 | lettershash[letter] = [i];
1214 | }
1215 | }
1216 |
1217 | return lettershash;
1218 | }
1219 |
1220 | function getLettersHashCountForWord(word) {
1221 | var lettershash = [];
1222 |
1223 | for(var i = 0; i < word.length; i++) {
1224 | var letter = word[i];
1225 | if(lettershash[letter]) {
1226 | lettershash[letter]++;
1227 | } else {
1228 | lettershash[letter] = 1;
1229 | }
1230 | }
1231 |
1232 | return lettershash;
1233 | }
1234 |
1235 | function getMatchingLetter(letters, nextword) {
1236 | var matchingletter = '';
1237 |
1238 | for(var i = 0; i < nextword.length; i++) {
1239 | var letter = nextword[i];
1240 | if(letters[letter]) {
1241 | return letter;
1242 | }
1243 | }
1244 |
1245 | return matchingletter;
1246 | }
1247 |
1248 | function shuffle(array) {
1249 | var currentIndex = array.length, temporaryValue, randomIndex;
1250 |
1251 | while (0 !== currentIndex) {
1252 | randomIndex = Math.floor(Math.random() * currentIndex);
1253 | currentIndex -= 1;
1254 |
1255 | temporaryValue = array[currentIndex];
1256 | array[currentIndex] = array[randomIndex];
1257 | array[randomIndex] = temporaryValue;
1258 | }
1259 |
1260 | return array;
1261 | }
1262 |
--------------------------------------------------------------------------------