Skip to content

Commit a962c81

Browse files
Merge pull request #9 from LucvandenBrand/develop
Version 0.2.0
2 parents 8a2a34d + 4421cd2 commit a962c81

14 files changed

+872
-296
lines changed

docs/index.html

+7-9
Original file line numberDiff line numberDiff line change
@@ -5,17 +5,15 @@
55
<title>M-TTT</title>
66
<link href="style.css" rel="stylesheet"></head>
77
<body>
8-
<h1>Meta Tic-Tac-Toe</h1>
9-
<blockquote>"A recursive solution to the simplicity of Tic-Tac-Toe."</blockquote>
8+
<header>Meta Tic-Tac-Toe</header>
109

11-
<div id="grid-container"></div>
10+
<div id="grid-container"></div>
1211

13-
<div id="grid-control">
14-
<input title="Meta Level" type="range" min="1" max="4" value="2" class="slider" id="meta-level">
15-
<button id="new-game">New Game of Meta <span id="level-value"></span></button>
16-
</div>
17-
18-
<footer>Brand - 2018</footer>
12+
<div id="grid-control">
13+
<input title="Meta Level" type="range" min="1" max="4" value="2" class="slider" id="meta-level">
14+
<button id="new-game">New Game of Meta <span id="level-value"></span></button>
15+
</div>
1916

17+
<footer><a href="https://github.com/LucvandenBrand/MetaTTT">Brand - 2018</a></footer>
2018
<script type="text/javascript" src="metaTTT.js"></script></body>
2119
</html>

docs/metaTTT.js

+380-25
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

docs/metaTTT.js.map

+1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

docs/style.css

+67-59
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

docs/style.css.map

+1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

pack/package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"//":"This Manifest file describes the NW.js app.",
33
"name":"MetaTTT",
4-
"version":"1.0.0",
4+
"version":"0.2.0",
55
"main":"index.html",
66
"window": {
77
"min_width": 1280,

src/app/control.js

+155-11
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,162 @@
1-
import $ from 'jquery';
1+
/**
2+
* Handles game-play logic and player control.
3+
*/
4+
export class Control {
5+
/**
6+
* Construct a control object and attach it to the root grid.
7+
* @param {MetaGrid} rootGrid The root of a MetaGrid.
8+
*/
9+
constructor(rootGrid) {
10+
let _previousPlayer = 0;
211

3-
const ATTR_PLAYER_MARK = 'player-mark';
12+
const currentPlayer = () => {
13+
return _previousPlayer ^= 1;
14+
};
415

5-
export class Control {
6-
constructor(metaGrid) {
7-
let _currentPlayer = 0;
16+
const applyToLeafs = (grid, method) => {
17+
if (grid.isLeaf()) {
18+
method(grid);
19+
return;
20+
}
21+
22+
for (let row = 0; row < grid.getSize(); row++) {
23+
for (let col = 0; col < grid.getSize(); col++) {
24+
applyToLeafs(grid.getChild(row, col), method);
25+
}
26+
}
27+
};
28+
29+
const checkRows = grid => {
30+
for (let row = 0; row < grid.getSize(); row++) {
31+
const firstCell = grid.getChild(row, 0).getMark();
32+
if (firstCell == null)
33+
continue;
34+
35+
let col;
36+
for (col = 0; col < grid.getSize(); col++) {
37+
if (grid.getChild(row, col).getMark() !== firstCell)
38+
break;
39+
}
40+
41+
if (col === grid.getSize())
42+
return true;
43+
}
44+
45+
return false;
46+
};
47+
48+
const checkColumns = grid => {
49+
for (let col = 0; col < grid.getSize(); col++) {
50+
const firstCell = grid.getChild(0, col).getMark();
51+
if (firstCell == null)
52+
continue;
53+
54+
let row;
55+
for (row = 0; row < grid.getSize(); row++) {
56+
if (grid.getChild(row, col).getMark() !== firstCell)
57+
break;
58+
}
59+
60+
if (row === grid.getSize())
61+
return true;
62+
}
63+
64+
return false;
65+
};
66+
67+
const checkDiagonals = grid => {
68+
const firstLeftCell = grid.getChild(0, 0).getMark();
69+
const firstRightCell = grid.getChild(0, grid.getSize()-1).getMark();
70+
71+
let leftDiagonal = true, rightDiagonal = true;
72+
for (let index = 0; index < grid.getSize(); index++) {
73+
if (grid.getChild(index, index).getMark() !== firstLeftCell) {
74+
leftDiagonal = false;
75+
}
76+
77+
let mirrorIndex = grid.getSize() - index - 1;
78+
if (grid.getChild(index, mirrorIndex).getMark() !== firstRightCell) {
79+
rightDiagonal = false;
80+
}
81+
}
82+
return firstLeftCell != null && leftDiagonal ||
83+
firstRightCell != null && rightDiagonal;
84+
};
85+
86+
const checkWin = (grid, checkMark) => {
87+
if (grid.isMarked())
88+
return;
89+
90+
if (checkRows(grid) || checkColumns(grid) || checkDiagonals(grid)) {
91+
grid.setMark(checkMark);
92+
93+
if (!grid.isRoot())
94+
checkWin(grid.getParent(), checkMark);
95+
}
96+
};
97+
98+
const countMarked = grid => {
99+
let numMarked = 0;
100+
for (let row = 0; row < grid.getSize(); row++)
101+
for (let col = 0; col < grid.getSize(); col++)
102+
if (grid.getChild(row, col).isMarked())
103+
numMarked++;
104+
return numMarked;
105+
};
106+
107+
const isFilled = grid => {
108+
const numChildren = grid.getSize() * grid.getSize();
109+
return countMarked(grid) === numChildren;
110+
};
111+
112+
const findEmpty = grid => {
113+
for (let row = 0; row < grid.getSize(); row++) {
114+
for (let col = 0; col < grid.getSize(); col++) {
115+
const child = grid.getChild(row, col);
116+
if (!isFilled(child)) {
117+
return child;
118+
}
119+
}
120+
}
121+
};
122+
123+
const enableReverse = (grid, metaIndex) => {
124+
if (metaIndex.length === 1) {
125+
if (isFilled(grid) && !grid.isRoot())
126+
grid = findEmpty(grid.getParent());
127+
128+
if (grid == null)
129+
return;
130+
131+
applyToLeafs(grid, (leaf) => {
132+
leaf.enable(true);
133+
});
134+
135+
return;
136+
}
137+
138+
const childIndex = metaIndex.pop();
139+
let child = grid.getChild(childIndex.row, childIndex.col);
140+
enableReverse(child, metaIndex);
141+
};
142+
143+
const handleClick = gridLeaf => {
144+
const player = currentPlayer();
145+
if (gridLeaf.isEnabled() && !gridLeaf.isMarked()) {
146+
gridLeaf.setMark(player);
147+
checkWin(gridLeaf.getParent(), player);
148+
149+
applyToLeafs(rootGrid, (leaf) => {
150+
leaf.enable(false);
151+
});
8152

9-
function nextPlayer() {
10-
_currentPlayer = 1 - _currentPlayer;
11-
}
153+
enableReverse(rootGrid, gridLeaf.getMetaIndex());
154+
}
155+
};
12156

13-
metaGrid.onCellClick(function (cell) {
14-
$(cell).attr(ATTR_PLAYER_MARK, _currentPlayer);
15-
nextPlayer();
157+
applyToLeafs(rootGrid, (leaf) => {
158+
leaf.getElement().onclick = () => {handleClick(leaf)};
159+
leaf.enable(true);
16160
});
17161
}
18162
}

0 commit comments

Comments
 (0)