@windward/games 0.0.3 → 0.0.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (34) hide show
  1. package/components/content/DatableEditor.vue +0 -3
  2. package/components/content/blocks/crosswordPuzzle/Crossword.ts +553 -0
  3. package/components/content/blocks/crosswordPuzzle/CrosswordClues.vue +91 -0
  4. package/components/content/blocks/crosswordPuzzle/CrosswordElements.ts +38 -0
  5. package/components/content/blocks/crosswordPuzzle/CrosswordPuzzle.vue +673 -0
  6. package/components/content/blocks/multipleChoice/MultipleChoice.vue +187 -127
  7. package/components/content/blocks/multipleChoice/QuestionDialog.vue +37 -13
  8. package/components/content/blocks/sevenStrikes/SevenStikes.vue +368 -0
  9. package/components/content/blocks/sevenStrikes/keyboard.vue +71 -0
  10. package/components/content/blocks/wordJumble/Jumble.vue +2 -10
  11. package/components/content/blocks/wordJumble/WordJumble.vue +22 -10
  12. package/components/settings/CrosswordPuzzleSettingsManager.vue +271 -0
  13. package/components/settings/MultipleChoiceSettingsManager.vue +21 -7
  14. package/components/settings/SevenStrikesSettingsManager.vue +288 -0
  15. package/components/settings/WordJumbleSettingsManager.vue +4 -1
  16. package/i18n/en-US/components/content/blocks/crossword.ts +22 -0
  17. package/i18n/en-US/components/content/blocks/index.ts +4 -0
  18. package/i18n/en-US/components/content/blocks/multiple_choice.ts +2 -4
  19. package/i18n/en-US/components/content/blocks/seven_strikes.ts +6 -0
  20. package/i18n/en-US/components/settings/crossword.ts +7 -0
  21. package/i18n/en-US/components/settings/index.ts +4 -0
  22. package/i18n/en-US/components/settings/multiple_choice.ts +1 -1
  23. package/i18n/en-US/components/settings/seven_strikes.ts +8 -0
  24. package/i18n/en-US/components/settings/word_jumble.ts +1 -1
  25. package/i18n/en-US/shared/content_blocks.ts +2 -0
  26. package/i18n/en-US/shared/settings.ts +2 -0
  27. package/package.json +2 -1
  28. package/plugin.js +43 -1
  29. package/test/blocks/crossword/CrosswordPuzzle.spec.js +49 -0
  30. package/test/blocks/sevenStrikes/sevenStrikes.spec.js +24 -0
  31. package/test/settings/BucketGameManager.spec.js +1 -1
  32. package/test/settings/CrosswordPuzzleManager.spec.js +103 -0
  33. package/test/settings/SevenStrikesManager.spec.js +53 -0
  34. package/test/settings/WordJumbleManager.spec.js +2 -2
@@ -170,8 +170,6 @@ export default {
170
170
  const item = evt.draggedContext.element
171
171
  const itemIdx = evt.draggedContext.futureIndex
172
172
 
173
- console.log('onMoveCallback', evt)
174
-
175
173
  if (item.locked) {
176
174
  return false
177
175
  }
@@ -179,7 +177,6 @@ export default {
179
177
  return true
180
178
  },
181
179
  onDropCallback(evt, originalEvent) {
182
- console.log('onDropCallback')
183
180
  this.$emit('input', this.items)
184
181
  },
185
182
  editItem(item) {
@@ -0,0 +1,553 @@
1
+ import {
2
+ CrosswordCell,
3
+ CrosswordCellNode,
4
+ WordElement,
5
+ } from './CrosswordElements'
6
+ class Crossword {
7
+ public GRID_COLS: any = 50
8
+ public GRID_ROWS: any = 50
9
+ // This is an index of the positions of the char in the crossword (so we know where we can potentially place words)
10
+ // example {"a" : [{'row' : 10, 'col' : 5}, {'row' : 62, 'col' :17}], {'row' : 54, 'col' : 12}], "b" : [{'row' : 3, 'col' : 13}]}
11
+ // where the two item arrays are the row and column of where the letter occurs
12
+ public charIndex: any = {}
13
+ // these words are the words that can't be placed on the crossword
14
+ public badWords!: any
15
+ public wordsIn!: any
16
+ public cluesIn!: any
17
+ public grid: any = []
18
+ public wordElements: any = []
19
+
20
+ constructor(wordsIn: any, cluesIn: any) {
21
+ this.wordsIn = wordsIn
22
+ this.cluesIn = cluesIn
23
+ // constructor
24
+ if (this.wordsIn.length < 2)
25
+ throw 'A crossword must have at least 2 words'
26
+ if (this.wordsIn.length !== cluesIn.length)
27
+ throw 'The number of words must equal the number of clues'
28
+ // build the grid;
29
+ this.grid = new Array(this.GRID_ROWS)
30
+ for (let i = 0; i < this.GRID_ROWS; i++) {
31
+ this.grid[i] = new Array(this.GRID_COLS)
32
+ }
33
+
34
+ // build the element list (need to keep track of indexes in the originial input arrays)
35
+ for (let i = 0; i < wordsIn.length; i++) {
36
+ this.wordElements.push(new WordElement(wordsIn[i], i))
37
+ }
38
+
39
+ // I got this sorting idea from http://stackoverflow.com/questions/943113/algorithm-to-generate-a-crossword/1021800#1021800
40
+ // seems to work well
41
+ this.wordElements.sort(function (a: any, b: any) {
42
+ return b.word.length - a.word.length
43
+ })
44
+ }
45
+
46
+ // returns the crossword grid that has the ratio closest to 1 or null if it can't build one
47
+ public getSquareGrid(maxTries: number) {
48
+ let bestGrid: any = null
49
+ let bestRatio = 0
50
+ for (let i = 0; i < maxTries; i++) {
51
+ let aGrid: any = this.getGrid(1)
52
+ if (aGrid === null) {
53
+ continue
54
+ }
55
+ let ratio =
56
+ (Math.min(aGrid.length, aGrid[0].length) * 1.0) /
57
+ Math.max(aGrid.length, aGrid[0].length)
58
+ if (ratio > bestRatio) {
59
+ bestGrid = aGrid
60
+ bestRatio = ratio
61
+ }
62
+
63
+ if (bestRatio === 1) break
64
+ }
65
+ return bestGrid
66
+ }
67
+
68
+ // returns an abitrary grid, or null if it can't build one
69
+ public getGrid(maxTries: number) {
70
+ const groups: any = []
71
+ let wordHasBeenAddedToGrid: boolean = false
72
+
73
+ for (let tries = 0; tries < maxTries; tries++) {
74
+ this.clear() // always start with a fresh grid and charIndex
75
+ // place the first word in the middle of the grid
76
+ let start_dir = this.randomDirection()
77
+ let r = Math.floor(this.grid.length / 2)
78
+ let c = Math.floor(this.grid[0].length / 2)
79
+
80
+ let wordElement = this.wordElements[0]
81
+ if (start_dir === 'across') {
82
+ c -= Math.floor(wordElement.word.length / 2)
83
+ } else {
84
+ r -= Math.floor(wordElement.word.length / 2)
85
+ }
86
+
87
+ if (
88
+ this.canPlaceWordAt(wordElement.word, r, c, start_dir) !== false
89
+ ) {
90
+ this.placeWordAt(
91
+ wordElement.word,
92
+ wordElement.index,
93
+ r,
94
+ c,
95
+ start_dir
96
+ )
97
+ } else {
98
+ this.badWords = [wordElement]
99
+ return null
100
+ }
101
+
102
+ // start with a group containing all the words (except the first)
103
+ // as we go, we try to place each word in the group onto the grid
104
+ // if the word can't go on the grid, we add that word to the next group
105
+
106
+ groups.push(this.wordElements.slice(1))
107
+ for (let g = 0; g < groups.length; g++) {
108
+ wordHasBeenAddedToGrid = false
109
+ // try to add all the words in this group to the grid
110
+ for (let i = 0; i < groups[g].length; i++) {
111
+ wordElement = groups[g][i]
112
+ const bestPosition: any = this.findPositionForWord(
113
+ wordElement.word
114
+ )
115
+ if (!bestPosition) {
116
+ // make the new group (if needed)
117
+ if (groups.length - 1 === g) groups.push([])
118
+ // place the word in the next group
119
+ groups[g + 1].push(wordElement)
120
+ } else {
121
+ r = bestPosition['row']
122
+ c = bestPosition['col']
123
+
124
+ this.placeWordAt(
125
+ wordElement.word,
126
+ wordElement.index,
127
+ r,
128
+ c,
129
+ bestPosition['direction']
130
+ )
131
+ wordHasBeenAddedToGrid = true
132
+ }
133
+ }
134
+ // if we haven't made any progress, there is no point in going on to the next group
135
+ if (!wordHasBeenAddedToGrid) break
136
+ }
137
+ // no need to try again
138
+ if (wordHasBeenAddedToGrid) return this.minimizeGrid()
139
+ }
140
+
141
+ this.badWords = groups[groups.length - 1]
142
+ return null
143
+ }
144
+
145
+ // returns the list of WordElements that can't fit on the crossword
146
+ public getBadWords() {
147
+ return this.badWords
148
+ }
149
+
150
+ // get two arrays ("across" and "down") that contain objects describing the
151
+ // topological position of the word (e.g. 1 is the first word starting from
152
+ // the top left, going to the bottom right), the index of the word (in the
153
+ // original input list), the clue, and the word itself
154
+ public getLegend(grid: any) {
155
+ let groups: any = { across: [], down: [] }
156
+ let position = 1
157
+ for (let row = 0; row < grid.length; row++) {
158
+ for (let col = 0; col < grid[row].length; col++) {
159
+ let cell = grid[row][col]
160
+ let increment_position = false
161
+ // check across and down
162
+ for (let direction in groups) {
163
+ // does a word start here? (make sure the cell isn't null, first)
164
+ if (
165
+ cell &&
166
+ cell[direction] &&
167
+ cell[direction].isStartOfWord
168
+ ) {
169
+ const index = cell[direction].index
170
+ groups[direction].push({
171
+ position: position,
172
+ index: index,
173
+ clue: this.cluesIn[index],
174
+ word: this.wordsIn[index],
175
+ })
176
+ // Set the cell position now that we've generated a legend
177
+ cell[direction].position = position
178
+ increment_position = true
179
+ }
180
+ }
181
+
182
+ if (increment_position) position++
183
+ }
184
+ }
185
+ return groups
186
+ }
187
+
188
+ // move the grid onto the smallest grid that will fit it
189
+ public minimizeGrid() {
190
+ // find bounds
191
+ let r_min = this.GRID_ROWS - 1
192
+ let r_max = 0
193
+ let c_min = this.GRID_COLS - 1
194
+ let c_max = 0
195
+
196
+ for (let r = 0; r < this.GRID_ROWS; r++) {
197
+ for (let c = 0; c < this.GRID_COLS; c++) {
198
+ let cell = this.grid[r][c]
199
+ if (cell !== null) {
200
+ if (r < r_min) r_min = r
201
+ if (r > r_max) r_max = r
202
+ if (c < c_min) c_min = c
203
+ if (c > c_max) c_max = c
204
+ }
205
+ }
206
+ }
207
+ // initialize new grid
208
+ let rows = r_max - r_min + 1
209
+ let cols = c_max - c_min + 1
210
+ let new_grid = new Array(rows)
211
+ for (let r = 0; r < rows; r++) {
212
+ for (let c = 0; c < cols; c++) {
213
+ new_grid[r] = new Array(cols)
214
+ }
215
+ }
216
+
217
+ // copy the grid onto the smaller grid
218
+ for (let r = r_min, r2 = 0; r2 < rows; r++, r2++) {
219
+ for (let c = c_min, c2 = 0; c2 < cols; c++, c2++) {
220
+ new_grid[r2][c2] = this.grid[r][c]
221
+ }
222
+ }
223
+
224
+ return new_grid
225
+ }
226
+
227
+ // helper for placeWordAt();
228
+ public addCellToGrid(
229
+ word: any,
230
+ indexOfWordInInputList: any,
231
+ indexOfChar: any,
232
+ row: any,
233
+ col: any,
234
+ direction: any
235
+ ) {
236
+ const char = word.charAt(indexOfChar)
237
+ if (this.grid[row][col] === null) {
238
+ this.grid[row][col] = new CrosswordCell(char)
239
+
240
+ // init the charIndex for that character if needed
241
+ if (!this.charIndex[char]) this.charIndex[char] = []
242
+
243
+ // add to index
244
+ this.charIndex[char].push({ row, col })
245
+ }
246
+
247
+ this.grid[row][col][direction] = new CrosswordCellNode(
248
+ indexOfChar === 0,
249
+ indexOfWordInInputList
250
+ )
251
+ }
252
+
253
+ // place the word at the row and col indicated (the first char goes there)
254
+ // the next chars go to the right (across) or below (down), depending on the direction
255
+ public placeWordAt(
256
+ word: any,
257
+ indexOfWordInInputList: any,
258
+ row: any,
259
+ col: any,
260
+ direction: any
261
+ ) {
262
+ if (direction === 'across') {
263
+ for (let c = col, i = 0; c < col + word.length; c++, i++) {
264
+ this.addCellToGrid(
265
+ word,
266
+ indexOfWordInInputList,
267
+ i,
268
+ row,
269
+ c,
270
+ direction
271
+ )
272
+ }
273
+ } else if (direction === 'down') {
274
+ for (let r = row, i = 0; r < row + word.length; r++, i++) {
275
+ this.addCellToGrid(
276
+ word,
277
+ indexOfWordInInputList,
278
+ i,
279
+ r,
280
+ col,
281
+ direction
282
+ )
283
+ }
284
+ } else {
285
+ throw 'Invalid Direction'
286
+ }
287
+ }
288
+
289
+ // you can only place a char where the space is blank, or when the same
290
+ // character exists there already
291
+ // returns false, if you can't place the char
292
+ // 0 if you can place the char, but there is no intersection
293
+ // 1 if you can place the char, and there is an intersection
294
+ public canPlaceCharAt(char: any, row: any, col: any) {
295
+ // no intersection
296
+ if (this.grid[row][col] === null) return 0
297
+ // intersection!
298
+ if (this.grid[row][col]['char'] === char) return 1
299
+
300
+ return false
301
+ }
302
+
303
+ // determines if you can place a word at the row, column in the direction
304
+ public canPlaceWordAt(word: any, row: any, col: any, direction: any): any {
305
+ // out of bounds
306
+ if (
307
+ row < 0 ||
308
+ row >= this.grid.length ||
309
+ col < 0 ||
310
+ col >= this.grid[row].length
311
+ )
312
+ return false
313
+
314
+ let intersections
315
+
316
+ if (direction === 'across') {
317
+ // out of bounds (word too long)
318
+ if (col + word.length > this.grid[row].length) return false
319
+ // can't have a word directly to the left
320
+ if (col - 1 >= 0 && this.grid[row][col - 1] !== null) return false
321
+ // can't have word directly to the right
322
+ if (
323
+ col + word.length < this.grid[row].length &&
324
+ this.grid[row][col + word.length] !== null
325
+ )
326
+ return false
327
+
328
+ // check the row above to make sure there isn't another word
329
+ // running parallel. It is ok if there is a character above, only if
330
+ // the character below it intersects with the current word
331
+ for (
332
+ let r = row - 1, c = col, i = 0;
333
+ r >= 0 && c < col + word.length;
334
+ c++, i++
335
+ ) {
336
+ let is_empty = this.grid[r][c] === null
337
+ let is_intersection =
338
+ this.grid[row][c] !== null &&
339
+ this.grid[row][c]['char'] === word.charAt(i)
340
+ let can_place_here = is_empty || is_intersection
341
+ if (!can_place_here) return false
342
+ }
343
+
344
+ // same deal as above, we just search in the row below the word
345
+ for (
346
+ let r = row + 1, c = col, i = 0;
347
+ r < this.grid.length && c < col + word.length;
348
+ c++, i++
349
+ ) {
350
+ let is_empty = this.grid[r][c] === null
351
+ let is_intersection =
352
+ this.grid[row][c] !== null &&
353
+ this.grid[row][c]['char'] === word.charAt(i)
354
+ let can_place_here = is_empty || is_intersection
355
+ if (!can_place_here) return false
356
+ }
357
+
358
+ // check to make sure we aren't overlapping a char (that doesn't match)
359
+ // and get the count of intersections
360
+ intersections = 0
361
+ for (let c = col, i = 0; c < col + word.length; c++, i++) {
362
+ let result = this.canPlaceCharAt(word.charAt(i), row, c)
363
+ if (result === false) return false
364
+ intersections += result
365
+ }
366
+ } else if (direction === 'down') {
367
+ // out of bounds
368
+ if (row + word.length > this.grid.length) return false
369
+ // can't have a word directly above
370
+ if (row - 1 >= 0 && this.grid[row - 1][col] !== null) return false
371
+ // can't have a word directly below
372
+ if (
373
+ row + word.length < this.grid.length &&
374
+ this.grid[row + word.length][col] !== null
375
+ )
376
+ return false
377
+
378
+ // check the column to the left to make sure there isn't another
379
+ // word running parallel. It is ok if there is a character to the
380
+ // left, only if the character to the right intersects with the
381
+ // current word
382
+ for (
383
+ let c = col - 1, r = row, i = 0;
384
+ c >= 0 && r < row + word.length;
385
+ r++, i++
386
+ ) {
387
+ let is_empty = this.grid[r][c] === null
388
+ let is_intersection =
389
+ this.grid[r][col] !== null &&
390
+ this.grid[r][col]['char'] === word.charAt(i)
391
+ let can_place_here = is_empty || is_intersection
392
+ if (!can_place_here) return false
393
+ }
394
+
395
+ // same deal, but look at the column to the right
396
+ for (
397
+ let c = col + 1, r = row, i = 0;
398
+ r < row + word.length && c < this.grid[r].length;
399
+ r++, i++
400
+ ) {
401
+ let is_empty = this.grid[r][c] === null
402
+ let is_intersection =
403
+ this.grid[r][col] !== null &&
404
+ this.grid[r][col]['char'] === word.charAt(i)
405
+ let can_place_here = is_empty || is_intersection
406
+ if (!can_place_here) return false
407
+ }
408
+
409
+ // check to make sure we aren't overlapping a char (that doesn't match)
410
+ // and get the count of intersections
411
+ intersections = 0
412
+ for (let r = row, i = 0; r < row + word.length; r++, i++) {
413
+ let result = this.canPlaceCharAt(word.charAt(i, 1), r, col)
414
+ if (result === false) return false
415
+ intersections += result
416
+ }
417
+ } else {
418
+ throw 'Invalid Direction'
419
+ }
420
+ return intersections
421
+ }
422
+
423
+ public randomDirection() {
424
+ return Math.floor(Math.random() * 2) ? 'across' : 'down'
425
+ }
426
+
427
+ public findPositionForWord(word: any) {
428
+ // check the charIndex for every letter, and see if we can put it there in a direction
429
+ let bests: object[] = []
430
+ for (let i = 0; i < word.length; i++) {
431
+ const possible_locations_on_grid = this.charIndex[word.charAt(i)]
432
+ if (!possible_locations_on_grid) continue
433
+ for (let j = 0; j < possible_locations_on_grid.length; j++) {
434
+ const point = possible_locations_on_grid[j]
435
+ const r = point['row']
436
+ const c = point['col']
437
+ // the c - i, and r - i here compensate for the offset of character in the word
438
+ const intersections_across = this.canPlaceWordAt(
439
+ word,
440
+ r,
441
+ c - i,
442
+ 'across'
443
+ )
444
+ const intersections_down = this.canPlaceWordAt(
445
+ word,
446
+ r - i,
447
+ c,
448
+ 'down'
449
+ )
450
+
451
+ if (intersections_across !== false) {
452
+ const objectAcross = {
453
+ intersections: intersections_across,
454
+ row: r,
455
+ col: c - i,
456
+ direction: 'across',
457
+ }
458
+ bests.push(objectAcross)
459
+ }
460
+ if (intersections_down !== false) {
461
+ const objectDown = {
462
+ intersections: intersections_down,
463
+ row: r - i,
464
+ col: c,
465
+ direction: 'down',
466
+ }
467
+ bests.push(objectDown)
468
+ }
469
+ }
470
+ }
471
+
472
+ if (bests.length === 0) return false
473
+
474
+ // find a good random position
475
+ return bests[Math.floor(Math.random() * bests.length)]
476
+ }
477
+
478
+ public clear() {
479
+ for (let r = 0; r < this.grid.length; r++) {
480
+ for (let c = 0; c < this.grid[r].length; c++) {
481
+ this.grid[r][c] = null
482
+ }
483
+ }
484
+ this.charIndex = {}
485
+ }
486
+ }
487
+
488
+ class CrosswordUtils {
489
+ public static PATH_TO_PNGS_OF_NUMBERS: string = 'numbers/'
490
+
491
+ public static toHtml(grid: any, show_answers: any) {
492
+ if (grid === null) return
493
+ const html: Array<string> = []
494
+ html.push("<table class='crossword'>")
495
+ let label = 1
496
+ for (let r = 0; r < grid.length; r++) {
497
+ html.push('<tr>')
498
+ for (let c = 0; c < grid[r].length; c++) {
499
+ const cell = grid[r][c]
500
+ let isStartOfWord = false
501
+ let css_class, char
502
+ if (cell === null) {
503
+ char = '&nbsp;'
504
+ css_class = 'no-border'
505
+ } else {
506
+ char = cell['char']
507
+ css_class = ''
508
+ isStartOfWord =
509
+ (cell.across && cell.across.isStartOfWord) ||
510
+ (cell.down && cell.down.isStartOfWord)
511
+ }
512
+
513
+ if (isStartOfWord) {
514
+ const img_url =
515
+ this.PATH_TO_PNGS_OF_NUMBERS + label.toString() + '.png'
516
+ html.push(
517
+ "<td class='" +
518
+ css_class +
519
+ "' title='" +
520
+ r +
521
+ ', ' +
522
+ c +
523
+ "' style=\"background-image:url('" +
524
+ img_url +
525
+ '\')">'
526
+ )
527
+ label++
528
+ } else {
529
+ html.push(
530
+ "<td class='" +
531
+ css_class +
532
+ "' title='" +
533
+ r +
534
+ ', ' +
535
+ c +
536
+ "'>"
537
+ )
538
+ }
539
+
540
+ if (show_answers) {
541
+ html.push(char)
542
+ } else {
543
+ html.push('&nbsp;')
544
+ }
545
+ }
546
+ html.push('</tr>')
547
+ }
548
+ html.push('</table>')
549
+ return html.join('\n')
550
+ }
551
+ }
552
+
553
+ export { Crossword, CrosswordUtils }
@@ -0,0 +1,91 @@
1
+ <template>
2
+ <v-row>
3
+ <v-col
4
+ cols="6"
5
+ v-if="down.length > 0"
6
+ :class="`crossword-clues__list crossword-clues__list--down`"
7
+ >
8
+ <h3 class="crossword-clues__list-title">
9
+ {{
10
+ $t(`plugin.games.components.content.blocks.crossword.down`)
11
+ }}
12
+ </h3>
13
+ <v-list dense>
14
+ <v-list-item-group v-model="selectedItem">
15
+ <v-list-item
16
+ class="crossword-clues__list-item"
17
+ v-for="word in down"
18
+ :key="word.index"
19
+ :value="word.index"
20
+ @click="onClick(word)"
21
+ >
22
+ {{ word.position }}.
23
+ {{ word.clue }}
24
+ </v-list-item>
25
+ </v-list-item-group>
26
+ </v-list>
27
+ </v-col>
28
+ <v-col
29
+ cols="6"
30
+ v-if="across.length > 0"
31
+ :class="`crossword-clues__list crossword-clues__list--across`"
32
+ >
33
+ <h3 class="crossword-clues__list-title">
34
+ {{
35
+ $t(
36
+ `plugin.games.components.content.blocks.crossword.across`
37
+ )
38
+ }}
39
+ </h3>
40
+ <v-list dense>
41
+ <v-list-item-group v-model="selectedItem">
42
+ <v-list-item
43
+ class="crossword-clues__list-item"
44
+ v-for="word in across"
45
+ :key="word.index"
46
+ :value="word.index"
47
+ @click="onClick(word)"
48
+ >
49
+ {{ word.position }}.
50
+ {{ word.clue }}
51
+ </v-list-item>
52
+ </v-list-item-group>
53
+ </v-list>
54
+ </v-col>
55
+ </v-row>
56
+ </template>
57
+
58
+ <script>
59
+ export default {
60
+ name: 'CrosswordClues',
61
+ components: {},
62
+ props: {
63
+ down: {
64
+ type: Array,
65
+ required: false,
66
+ default: () => [],
67
+ },
68
+ across: {
69
+ type: Array,
70
+ required: false,
71
+ default: () => [],
72
+ },
73
+ },
74
+ data() {
75
+ return {
76
+ selectedItem: null,
77
+ }
78
+ },
79
+ methods: {
80
+ onClick(word) {
81
+ this.$emit('click', word)
82
+ },
83
+ },
84
+ }
85
+ </script>
86
+
87
+ <style scoped>
88
+ .crossword-clues__list-item {
89
+ padding: 4px;
90
+ }
91
+ </style>
@@ -0,0 +1,38 @@
1
+ class CrosswordCell {
2
+ public char!: string
3
+ public across!: any
4
+ public down!: any
5
+ constructor(letter: string) {
6
+ this.char = letter // the actual letter for the cell on the crossword
7
+ // If a word hits this cell going in the "across" direction, this will be a CrosswordCellNode
8
+ this.across = null
9
+ // If a word hits this cell going in the "down" direction, this will be a CrosswordCellNode
10
+ this.down = null
11
+ }
12
+ }
13
+
14
+ // You can tell if the Node is the start of a word (which is needed if you want to number the cells)
15
+ // and what word and clue it corresponds to (using the index)
16
+ class CrosswordCellNode {
17
+ public isStartOfWord!: any
18
+ public index!: any
19
+ public position = -1
20
+
21
+ constructor(isStartOfWord: any, index: any) {
22
+ this.isStartOfWord = isStartOfWord
23
+ this.index = index // use to map this node to its word or clue
24
+ }
25
+
26
+ // public functionName
27
+ }
28
+
29
+ class WordElement {
30
+ public word!: any
31
+ public index!: any
32
+ constructor(word: any, index: any) {
33
+ this.word = word // the actual word
34
+ this.index = index // use to map this node to its word or clue
35
+ }
36
+ }
37
+
38
+ export { CrosswordCell, CrosswordCellNode, WordElement }