1
- import $ from 'jquery' ;
2
-
3
- import '../styles/table.css' ;
4
-
5
- const GRID_SIZE = 3 ,
6
- NODE_DIV = '<div>' ,
7
- CLASS_TABLE = 'table' ,
8
- CLASS_ROW = 'row' ,
9
- CLASS_CELL = 'cell' ,
10
- CLASS_DISABLED = 'disabled' ,
11
- CLASS_CLICKED = 'played' ,
12
- ATTR_LOCATION = 'location' ;
13
-
14
- /**
15
- * Recursively generates a grid in the container.
16
- * @param container The container to add the grid to.
17
- * @param depth The number of recursions.
18
- */
19
- function generateTable ( container , depth ) {
20
- if ( depth < 1 ) {
21
- $ ( container ) . addClass ( CLASS_CELL ) ;
22
- } else {
23
- $ ( container ) . addClass ( CLASS_TABLE ) ;
24
- for ( let y = 0 ; y < GRID_SIZE ; y ++ ) {
25
- let row = $ ( NODE_DIV ) ;
26
- $ ( row ) . addClass ( CLASS_ROW ) ;
27
- for ( let x = 0 ; x < GRID_SIZE ; x ++ ) {
28
- let cell = $ ( NODE_DIV ) ;
29
- $ ( cell ) . attr ( ATTR_LOCATION , y * GRID_SIZE + x ) ;
30
- generateTable ( cell , depth - 1 ) ;
31
- row . append ( cell ) ;
1
+ import '../styles/grid.css' ;
2
+
3
+ export class MetaGrid {
4
+ constructor ( size , depth , onLeafClick , parent ) {
5
+ const ATTR_MARK = 'mark' ,
6
+ ELEM_GRID = 'div' ;
7
+
8
+ const _cells = [ ] ;
9
+ const _element = document . createElement ( ELEM_GRID ) ;
10
+ let _mark ;
11
+
12
+ const updateElement = ( ) => {
13
+ _element . setAttribute ( ATTR_MARK , _mark ) ;
14
+ } ;
15
+
16
+ const makeChildren = ( ) => {
17
+ _cells . length = 0 ;
18
+ _element . innerHTML = '' ;
19
+ for ( let row = 0 ; row < size ; row ++ ) {
20
+ _cells [ row ] = [ ] ;
21
+ for ( let col = 0 ; col < size ; col ++ ) {
22
+ const cell = new MetaGrid ( size , depth - 1 , onLeafClick , this ) ;
23
+ _cells [ row ] . push ( cell ) ;
24
+ _element . appendChild ( cell . getElement ( ) ) ;
25
+ }
32
26
}
33
- $ ( container ) . append ( row ) ;
34
- }
35
- }
36
- }
27
+ } ;
37
28
38
- function getClickStack ( cell ) {
39
- let locations = [ $ ( cell ) . attr ( ATTR_LOCATION ) ] ;
40
- $ ( cell ) . parents ( '.' + CLASS_TABLE ) . each ( function ( ) {
41
- let location = $ ( this ) . attr ( ATTR_LOCATION ) ;
42
- if ( location != null )
43
- locations . push ( $ ( this ) . attr ( ATTR_LOCATION ) ) ;
44
- } ) ;
45
- return locations ;
46
- }
29
+ const checkRows = ( ) => {
30
+ for ( let row = 0 ; row < size ; row ++ ) {
31
+ const firstCell = _cells [ row ] [ 0 ] . getMark ( ) ;
32
+ if ( firstCell == null )
33
+ continue ;
47
34
48
- function enableTable ( table ) {
49
- table . find ( '.' + CLASS_DISABLED ) . removeClass ( CLASS_DISABLED ) ;
50
- }
35
+ let col ;
36
+ for ( col = 0 ; col < size ; col ++ ) {
37
+ if ( _cells [ row ] [ col ] . getMark ( ) !== firstCell )
38
+ break ;
39
+ }
51
40
52
- function disableWithStack ( currentTable , locations ) {
53
- let root = currentTable ;
54
- enableTable ( root ) ;
55
-
56
- while ( locations . length > 1 ) {
57
- let location = locations . shift ( ) ;
58
- currentTable . children ( ) . closest ( '.' + CLASS_ROW ) . children ( ) . each ( function ( ) {
59
- if ( $ ( this ) . attr ( ATTR_LOCATION ) === location )
60
- currentTable = $ ( this ) ;
61
- else
62
- $ ( this ) . addClass ( CLASS_DISABLED ) ;
63
- } ) ;
64
- }
41
+ if ( col === size )
42
+ return true ;
43
+ }
65
44
66
- if ( isTableFull ( currentTable ) ) {
67
- let freeCell = root . find ( '.' + CLASS_CELL ) . not ( '.' + CLASS_CLICKED ) [ 0 ] ;
68
- disableWithStack ( root , getClickStack ( freeCell ) ) ;
69
- }
70
- }
45
+ return false ;
46
+ } ;
71
47
72
- function isTableFull ( table ) {
73
- let numPlayed = $ ( table ) . children ( ) . children ( '.' + CLASS_CLICKED ) . length ;
74
- return numPlayed === GRID_SIZE * GRID_SIZE ;
75
- }
48
+ const checkColumns = ( ) => {
49
+ for ( let col = 0 ; col < size ; col ++ ) {
50
+ const firstCell = _cells [ 0 ] [ col ] . getMark ( ) ;
51
+ if ( firstCell == null )
52
+ continue ;
76
53
54
+ let row ;
55
+ for ( row = 0 ; row < size ; row ++ ) {
56
+ if ( _cells [ row ] [ col ] . getMark ( ) !== firstCell )
57
+ break ;
58
+ }
77
59
78
- function isCellDisabled ( cell ) {
79
- let containingTable = $ ( cell ) . parents ( '.' + CLASS_TABLE ) ;
80
- return containingTable . hasClass ( CLASS_DISABLED ) || $ ( cell ) . hasClass ( CLASS_CLICKED ) ;
81
- }
60
+ if ( row === size )
61
+ return true ;
62
+ }
82
63
83
- /**
84
- * Generates a grid with multiple grids inside itself.
85
- */
86
- export class MetaGrid {
87
- constructor ( metaLevel ) {
88
- let _rootTable = $ ( NODE_DIV ) ;
89
- generateTable ( _rootTable , metaLevel ) ;
90
-
91
- this . getContainer = function ( ) {
92
- return _rootTable ;
93
- } ;
94
-
95
- this . onCellClick = function ( onClick ) {
96
- _rootTable . find ( '.' + CLASS_CELL ) . click ( function ( ) {
97
- if ( ! isCellDisabled ( this ) ) {
98
- onClick ( this ) ;
99
- disableWithStack ( _rootTable , getClickStack ( this ) ) ;
100
- $ ( this ) . addClass ( CLASS_CLICKED ) ;
101
- }
102
- } ) ;
103
- } ;
104
- }
105
- } ;
64
+ return false ;
65
+ } ;
66
+
67
+ const checkDiagonals = ( ) => {
68
+ const firstLeftCell = _cells [ 0 ] [ 0 ] . getMark ( ) ;
69
+ const firstRightCell = _cells [ 0 ] [ size - 1 ] . getMark ( ) ;
70
+
71
+ let leftDiagonal = true , rightDiagonal = true ;
72
+ for ( let index = 0 ; index < size ; index ++ ) {
73
+ if ( _cells [ index ] [ index ] . getMark ( ) !== firstLeftCell ) {
74
+ leftDiagonal = false ;
75
+ }
76
+
77
+ let mirrorIndex = size - index - 1 ;
78
+ if ( _cells [ index ] [ mirrorIndex ] . getMark ( ) !== firstRightCell ) {
79
+ rightDiagonal = false ;
80
+ }
81
+ }
82
+ return firstLeftCell != null && leftDiagonal ||
83
+ firstRightCell != null && rightDiagonal ;
84
+ } ;
85
+
86
+ this . checkWin = ( checkMark ) => {
87
+ if ( _mark )
88
+ return ;
89
+
90
+ if ( checkRows ( ) || checkColumns ( ) || checkDiagonals ( ) )
91
+ this . setMark ( checkMark ) ;
92
+ } ;
93
+
94
+ this . setMark = mark => {
95
+ _mark = mark ;
96
+ if ( parent )
97
+ parent . checkWin ( mark ) ;
98
+ updateElement ( ) ;
99
+ } ;
100
+
101
+ this . getMark = ( ) => {
102
+ return _mark ;
103
+ } ;
104
+
105
+ this . getElement = ( ) => _element ;
106
+
107
+ if ( depth > 0 )
108
+ makeChildren ( ) ;
109
+ else
110
+ _element . onclick = ( ) => onLeafClick ( this ) ;
111
+ }
112
+ }
0 commit comments