├── README.md
├── examples
├── chessgame.js
├── chessknight.js
├── connectfour.js
├── gameoflife.js
├── quoridorwalls.js
├── simplecheckers.js
└── tictactoe.js
├── images
├── bknight.png
├── black.png
├── chess
│ ├── bishop.png
│ ├── king.png
│ ├── knight.png
│ ├── pawn.png
│ ├── queen.png
│ └── rook.png
├── red.png
└── white.png
├── index.html
├── jsboard.js
└── jsboard.min.js
/README.md:
--------------------------------------------------------------------------------
1 | # jsboard
2 | JavaScript library that allows you to easily create board games like [Chess](http://danielborowski.com/jsboard/demo/demo8/) and Conway's [Game of Life](http://danielborowski.com/jsboard/demo/demo9/).
3 |
4 | `jsboard` allows you to focus on your game logic, game AI, and game algorithms rather than focusing on creating and styling your game using HTML and CSS. `jsboard` allows you to create and play 2D board games very easily using its functions so you don't have to worry about how to represent your game in JavaScript or how to display it in the HTML.
5 |
6 | `jsboard` doesn't require jQuery or any other libraries. Simply include the library in your HTML file like in the example below.
7 |
8 | # Contents
9 |
10 | * [Setting Up](#setting-up)
11 | * [Introduction](#introduction)
12 | * [Documentation](#documentation)
13 | * [Examples](#examples)
14 |
15 | # Setting Up
16 | All you need to get started is a simple HTML file and a JS file where your game code will go. Here's how your `index.html` file should look:
17 |
18 | ```html
19 |
20 |
21 |
22 | Title
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 | ```
31 | Then create a blank `index.js` file where the game code will go.
32 |
33 | # Introduction
34 |
35 | You have access to the following objects using jsboard.
36 |
37 | ```javascript
38 | jsboard.board({ attach: tableID, size: NxM [,style: "checkerboard"] [,stylePattern: [color1, color2]] });
39 | jsboard.piece({ text: pieceName [,cssProperties] });
40 | ```
41 |
42 | Here is an example board and piece created with the following properties.
43 |
44 | ```javascript
45 | var b = jsboard.board({ attach: "game", size: "3x3" });
46 | var x = jsboard.piece({ text: "X", fontSize: "40px", textAlign: "center" });
47 | ```
48 | If you open `index.html` you should see the following:
49 |
50 | ![alt text][logo]
51 |
52 | [logo]: http://i.imgur.com/ioWoK5O.png "pic"
53 |
54 | Let's add some functionality to our board. We'll make it so that when we click on an empty space, one of our pieces will be placed down. We'll do this using the `cell` function from `jsboard` which can modify and get properties from spaces within the game board.
55 |
56 | ```javascript
57 | b.cell("each").on("click", function() {
58 | if (b.cell(this).get()===null) {
59 | b.cell(this).place(x.clone());
60 | }
61 | });
62 | ```
63 | You should now be able to place X's on the board. [Check it out here](http://danielborowski.com/jsboard/demo/demo1/)
64 |
65 | Let's actually turn this into a tic-tac-toe game. All we need to do is alternate the placing of pieces X and O. Here's how the final `index.js` should look.
66 |
67 | ```javascript
68 | var b = jsboard.board({ attach: "game", size: "3x3" });
69 | var x = jsboard.piece({ text: "X", fontSize: "40px", textAlign: "center" });
70 | var o = jsboard.piece({ text: "O", fontSize: "40px", textAlign: "center"});
71 |
72 | var turn = true;
73 | b.cell("each").on("click", function() {
74 | if (b.cell(this).get()===null) {
75 | if (turn) { b.cell(this).place(x.clone()); }
76 | else { b.cell(this).place(o.clone()); }
77 | turn = !turn;
78 | }
79 | });
80 | ```
81 |
82 | That's it! We just created a functioning tic-tac-toe game using these simple commands. [Check out the tic-tac-toe game here](http://danielborowski.com/jsboard/demo/demo2/)
83 |
84 | What if we want to change the styling of our board? We actually have `jsboard` functions to modify each cell or modify the whole board. We'll make changes to both.
85 |
86 | ```javascript
87 | b.style({ borderSpacing: "8px" });
88 | b.cell("each").style({
89 | width: "75px",
90 | height: "75px",
91 | background: "lightblue",
92 | borderRadius: "15px"
93 | });
94 | ```
95 | Here's what you should see now.
96 |
97 | ![alt text][logo2]
98 |
99 | [logo2]: http://i.imgur.com/berlbMg.png "pic"
100 |
101 | # Documentation
102 |
103 | Create a board.
104 | ```javascript
105 | jsboard.board({ attach: tableID, size: NxM [,style: "checkerboard"] [,stylePattern: [color1, color2]] });
106 | // var b = jsboard.board({ attach: "game", size: "3x3" });
107 | // var c = jsboard.board({ attach: "game", size: "8x8", style: "checkerboard" });
108 | // var d = jsboard.board({ attach: "game", size: "8x8", style: "checkerboard", stylePattern: ["blue","green"] });
109 | ```
110 |
111 | Board properties, methods, and styling.
112 | ```javascript
113 | var b = jsboard.board({ attach: "game", size: "5x8", style: "checkerboard" });
114 | b.matrix(); // matrix representation containing values from piece.text or null
115 | b.rows(); // 5
116 | b.cols(); // 8
117 | b.removeEvents(event, func); // removes event listeners from all board spaces (see chessknight example)
118 | b.style({ cssProperties });
119 | ```
120 |
121 | Create pieces.
122 | ```javascript
123 | jsboard.piece({ text: pieceName [,cssProperties] });
124 | // var x = jsboard.piece({ text: "X", fontSize: "40px", textAlign: "center" });
125 | // var k = jsboard.piece({ text: "WK", textIndent: "-9999px", background: "url('images/white.png') no-repeat", width: "50px", height: "50px", margin: "0 auto" });
126 | ```
127 | Piece methods and styling.
128 | ```javascript
129 | var p = jsboard.piece({ text: "X", fontSize: "40px", textAlign: "center" });
130 | p.style({ cssProperties });
131 | var x = p.clone(); // you must clone a piece before placing it on the board because jsboard.piece only serves as a piece schema and clone() gets it ready for the DOM
132 | ```
133 |
134 | Cell methods.
135 | ```javascript
136 | var b = jsboard.board({ attach: "game", size: "5x8", style: "checkerboard" });
137 | var p = jsboard.piece({ text: "X", fontSize: "40px", textAlign: "center" });
138 |
139 | // styling cells
140 | b.cell("each").style({ cssProperties });
141 | b.cell([N,M]).style({ cssProperties }); // [N,M] = position on the game board using matrix notation
142 | b.cell(this).style({ cssProperties }); // this = current cell
143 | b.cell(this,K).style({ cssProperties }); // (this,K) = some position K spaces from this cell. Example: b.cell(this,3) represents the cell 3 spaces to the right of this cell (see quoridorwalls example)
144 |
145 | // placing pieces in cells
146 | b.cell("each").place(p.clone());
147 | b.cell([N,M]).place(p.clone());
148 | b.cell(this).place(p.clone());
149 | b.cell(this,K).place(p.clone());
150 |
151 | // removing pieces from cells
152 | b.cell("each").rid();
153 | b.cell([N,M]).rid();
154 | b.cell(this).rid();
155 | b.cell(this,K).rid();
156 |
157 | // adding event listeners to cells
158 | b.cell("each").on(event, function);
159 | b.cell([N,M]).on(event, function); // Example: b.cell([0,0]).on("click", function() { alert("clicked!"); } );
160 | b.cell(this).on(event, function);
161 | b.cell(this,K).on(event, function);
162 |
163 | // removing event listeners from cells
164 | b.cell("each").removeOn(event, function);
165 | b.cell([N,M]).removeOn(event, function); // Example: b.cell([0,0]).removeOn("click", myFunc } );
166 | b.cell(this).removeOn(event, function);
167 | b.cell(this,K).removeOn(event, function);
168 |
169 | // get content of cell to see if a piece is within some cell
170 | // either null or piece.text is returned
171 | b.cell([N,M]).get();
172 | b.cell(this).get();
173 | b.cell(this,K).get();
174 |
175 | // check where a specific cell is within the game board
176 | // returns matrix notation [N,M] of cell within game board
177 | b.cell(this).where();
178 | b.cell(this,K).where();
179 |
180 | // return the DOM node for given cell in order to manipulate using
181 | // standard JS functions. Example: b.cell([0,0]).DOM().classList.add("myclass");
182 | b.cell([N,M]).DOM();
183 | b.cell(this).DOM();
184 | b.cell(this,K).DOM();
185 | ```
186 | # Examples
187 |
188 | Basic
189 | * [Tic-tac-toe game](http://danielborowski.com/jsboard/demo/demo3/) simple tic-tac-toe game
190 | * [Connect Four](http://danielborowski.com/jsboard/demo/demo7/) click the top of each column to drop a piece
191 |
192 | Checkerboard style
193 | * [Checkers pieces](http://danielborowski.com/jsboard/demo/demo4/) click the red piece to move around
194 | * [Chessboard knights](http://danielborowski.com/jsboard/demo/demo5/) click the knights to move around
195 | * [One-sided Chess game](http://danielborowski.com/jsboard/demo/demo8/) complete movements for white chess pieces
196 |
197 | Other games and simulations
198 | * [Conway's Game of Life](http://danielborowski.com/jsboard/demo/demo9/) place some life cells down and watch your simulation create and destroy life (here's a list of [interesting patterns](http://www.conwaylife.com/wiki/Category:Patterns) you can try out)
199 | * [Quoridor(ish) wall placement](http://danielborowski.com/jsboard/demo/demo6/) click the piece to move it to the right and click between the spaces to create a wall that prevents the piece from moving past it
200 |
--------------------------------------------------------------------------------
/examples/chessgame.js:
--------------------------------------------------------------------------------
1 | // create board
2 | var b = jsboard.board({attach:"game", size:"8x8", style:"checkerboard"});
3 | b.cell("each").style({width:"60px", height:"60px"});
4 |
5 | // setup pieces
6 | var knight = jsboard.piece({text:"WK", textIndent:"-9999px", background:"url('images/chess/knight.png') no-repeat", width:"50px", height:"50px", margin:"0 auto" });
7 | var bishop = jsboard.piece({text:"WB", textIndent:"-9999px", background:"url('images/chess/bishop.png') no-repeat", width:"50px", height:"50px", margin:"0 auto" });
8 | var rook = jsboard.piece({text:"WR", textIndent:"-9999px", background:"url('images/chess/rook.png') no-repeat", width:"50px", height:"50px", margin:"0 auto" });
9 | var queen = jsboard.piece({text:"WQ", textIndent:"-9999px", background:"url('images/chess/queen.png') no-repeat", width:"50px", height:"50px", margin:"0 auto" });
10 | var king = jsboard.piece({text:"WG", textIndent:"-9999px", background:"url('images/chess/king.png') no-repeat", width:"50px", height:"50px", margin:"0 auto" });
11 | var pawn = jsboard.piece({text:"WP", textIndent:"-9999px", background:"url('images/chess/pawn.png') no-repeat", width:"50px", height:"50px", margin:"0 auto" });
12 |
13 | // create pieces to place in DOM
14 | var whitePieces = [
15 | knight.clone(),
16 | knight.clone(),
17 | bishop.clone(),
18 | bishop.clone(),
19 | rook.clone(),
20 | rook.clone(),
21 | queen.clone(),
22 | king.clone()
23 | ];
24 | for (var i=0; i<8; i++)
25 | whitePieces.push(pawn.clone());
26 |
27 | // place pieces on board
28 | b.cell([7,1]).place(whitePieces[0]); b.cell([7,6]).place(whitePieces[1]);
29 | b.cell([7,2]).place(whitePieces[2]); b.cell([7,5]).place(whitePieces[3]);
30 | b.cell([7,0]).place(whitePieces[4]); b.cell([7,7]).place(whitePieces[5]);
31 | b.cell([7,3]).place(whitePieces[6]);
32 | b.cell([7,4]).place(whitePieces[7]);
33 | for (var i=8; i0) {
82 | if (b.cell(ULD).get()==null) { newLocs.push(ULD); ULD = [ULD[0]-1,ULD[1]-1]; }
83 | check--;
84 | }
85 | check = 7;
86 | // up right diagonal
87 | var URD = [loc[0]-1,loc[1]+1];
88 | while (check>0) {
89 | if (b.cell(URD).get()==null) { newLocs.push(URD); URD = [URD[0]-1,URD[1]+1]; }
90 | check--;
91 | }
92 | check = 7;
93 | // down left diagonal
94 | var DLD = [loc[0]+1,loc[1]-1];
95 | while (check>0) {
96 | if (b.cell(DLD).get()==null) { newLocs.push(DLD); DLD = [DLD[0]+1,DLD[1]-1]; }
97 | check--;
98 | }
99 | check = 7;
100 | // down right diagonal
101 | var DRD = [loc[0]+1,loc[1]+1];
102 | while (check>0) {
103 | if (b.cell(DRD).get()==null) { newLocs.push(DRD); DRD = [DRD[0]+1,DRD[1]+1]; }
104 | check--;
105 | }
106 | }
107 |
108 | // movement for rooks
109 | // queen also moves like a rook
110 | if (thisPiece=="WR"||thisPiece=="WQ") {
111 | var check = 7;
112 | var U = [loc[0]-1,loc[1]];
113 | while (check>0) {
114 | if (b.cell(U).get()==null) { newLocs.push(U); U = [U[0]-1,U[1]]; }
115 | check--;
116 | }
117 | check = 7;
118 | // up right diagonal
119 | var L = [loc[0],loc[1]-1];
120 | while (check>0) {
121 | if (b.cell(L).get()==null) { newLocs.push(L); L = [L[0],L[1]-1]; }
122 | check--;
123 | }
124 | check = 7;
125 | // down left diagonal
126 | var R = [loc[0],loc[1]+1];
127 | while (check>0) {
128 | if (b.cell(R).get()==null) { newLocs.push(R); R = [R[0],R[1]+1]; }
129 | check--;
130 | }
131 | check = 7;
132 | // down right diagonal
133 | var D = [loc[0]+1,loc[1]];
134 | while (check>0) {
135 | if (b.cell(D).get()==null) { newLocs.push(D); D = [D[0]+1,D[1]]; }
136 | check--;
137 | }
138 | }
139 |
140 | // movement for king
141 | if (thisPiece=="WG") {
142 | newLocs.push(
143 | [loc[0]-1,loc[1]], [loc[0]+1,loc[1]],
144 | [loc[0],loc[1]-1], [loc[0],loc[1]+1],
145 | [loc[0]-1,loc[1]-1], [loc[0]-1,loc[1]+1],
146 | [loc[0]+1,loc[1]-1], [loc[0]+1,loc[1]+1]
147 | );
148 | }
149 |
150 | // remove illegal moves by checking
151 | // content of b.cell().get()
152 | (function removeIllegalMoves(arr) {
153 | var fixedLocs = [];
154 | for (var i=0; i1 && !stopped)
107 | setTimeout(function() { startSim(); }, 150);
108 | }
109 |
110 | // stop simulation
111 | function stopSim() { stopped = true; }
112 |
--------------------------------------------------------------------------------
/examples/quoridorwalls.js:
--------------------------------------------------------------------------------
1 | // create board
2 | var b = jsboard.board({attach:"game", size:"2x15"});
3 | b.cell("each").style({width:"65px", height:"65px"});
4 |
5 | // setup pieces
6 | var player = jsboard.piece({text:"P", textIndent:"-9999px", background:"url('images/black.png') no-repeat", width:"50px", height:"50px", margin:"0 auto" });
7 | var piece_wall = jsboard.piece({text:"wall", fontSize:"0px"});
8 |
9 | // create piece to place in DOM
10 | var p1 = player.clone();
11 | b.cell([0,0]).place(p1);
12 |
13 | // give functionality to your piece
14 | p1.addEventListener("click", function() {
15 | var w = b.cell(this.parentNode,1).get();
16 | // if next space is not a wall then you can move past it
17 | if (w!="wall") {
18 | // allow board overlapping but modify movement
19 | var nextSpace = b.cell(this.parentNode,2).where();
20 | var curRow = b.cell(this.parentNode).where();
21 | if (nextSpace[0]!=curRow[0]) b.cell(this.parentNode,1).place(p1);
22 | else b.cell(this.parentNode,2).place(p1);
23 | }
24 | });
25 |
26 | // add functionality for placing red walls
27 | for (var r=0; r
2 |
3 |
4 |
5 | Test
6 |
9 |
10 |
11 |
16 |
17 |
18 |
19 |
27 |
28 |
29 |
--------------------------------------------------------------------------------
/jsboard.js:
--------------------------------------------------------------------------------
1 | /*
2 | The MIT License (MIT)
3 |
4 | Copyright (c) 2015 Daniel Borowski
5 |
6 | Permission is hereby granted, free of charge, to any person obtaining a copy
7 | of this software and associated documentation files (the "Software"), to deal
8 | in the Software without restriction, including without limitation the rights
9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | copies of the Software, and to permit persons to whom the Software is
11 | furnished to do so, subject to the following conditions:
12 |
13 | The above copyright notice and this permission notice shall be included in
14 | all copies or substantial portions of the Software.
15 |
16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 | THE SOFTWARE.
23 | */
24 |
25 | window.jsboard = (function(){
26 |
27 | 'use strict';
28 |
29 | // constr
30 | function Board(props,size,attached) {
31 |
32 | var matrixForm = [];
33 |
34 | var methods = {
35 |
36 | // return matrix form of game board
37 | matrix: function() {
38 | while (matrixForm.length>0) { matrixForm.pop(); }
39 | for (var r=0; r0) { wh[1] -= 1; }
88 | else { wh[1] = size[1]-1; wh[0] -= 1; }
89 | keepDec++;
90 | }
91 | }
92 | else {
93 | while (keepDec>0) {
94 | if (wh[1]size[0]-1||arr[1]>size[1]-1) { return document.createElement("div"); }
105 | return document.getElementById(attached).getElementsByClassName("boardRow_"+arr[0])[0].childNodes[arr[1]];
106 | }
107 | else {
108 | var wh = getObjFromDataAtr(arr.attributes["data-matrixval"].value);
109 | if (wh[0]<0||wh[1]<0||wh[0]>size[0]-1||wh[1]>size[1]-1) { return document.createElement("div"); }
110 | var th = getBoardCell(wh[0],wh[1]);
111 | if (typeof th.childNodes[0] == "undefined") { return document.createElement("div"); }
112 | return getBoardCell(wh[0],wh[1]);
113 | }
114 | },
115 | // styling for cells
116 | style: function(props) {
117 | if (arr=="each") {
118 | for (var st in props) {
119 | for (var r=0; rsize[0]-1||arr[1]>size[1]-1) { return "OOB"; }
128 | for (var st in props) {
129 | getBoardCell(arr[0],arr[1]).style[st] = props[st];
130 | }
131 | }
132 | else {
133 | var wh = getObjFromDataAtr(arr.attributes["data-matrixval"].value);
134 | if (wh[0]<0||wh[1]<0||wh[0]>size[0]-1||wh[1]>size[1]-1) { return "OOB"; }
135 | var th = getBoardCell(wh[0],wh[1]);
136 | for (var st in props) {
137 | th.style[st] = props[st];
138 | }
139 | }
140 | },
141 | // place cloned piece in cell
142 | place: function(piece) {
143 | if (arr=="each") {
144 | for (var r=0; rsize[0]-1||wh[1]>size[1]-1) { return "OOB"; }
163 | var th = getBoardCell(wh[0],wh[1]);
164 | while (th.firstChild) { th.removeChild(th.firstChild); }
165 | getBoardCell(wh[0],wh[1]).appendChild(piece);
166 | }
167 | },
168 | // remove all pieces from cell
169 | rid: function(piece) {
170 | if (arr=="each") {
171 | for (var r=0; rsize[0]-1||wh[1]>size[1]-1) { return "OOB"; }
185 | var th = getBoardCell(wh[0],wh[1]);
186 | while (th.firstChild) { th.removeChild(th.firstChild); }
187 | }
188 | },
189 | // event listener for cells
190 | on: function(ev,func) {
191 | if (arr=="each") {
192 | for (var r=0; rsize[0]-1||arr[1]>size[1]-1) { return "OOB"; }
200 | getBoardCell(arr[0],arr[1]).addEventListener(ev, func);
201 | }
202 | else {
203 | var wh = getObjFromDataAtr(arr.attributes["data-matrixval"].value);
204 | if (wh[0]<0||wh[1]<0||wh[0]>size[0]-1||wh[1]>size[1]-1) { return "OOB"; }
205 | var th = getBoardCell(wh[0],wh[1]);
206 | th.addEventListener(ev, func);
207 | }
208 | },
209 | // remove event listener for cells
210 | removeOn: function(ev,func) {
211 | if (arr=="each") {
212 | for (var r=0; rsize[0]-1||arr[1]>size[1]-1) { return "OOB"; }
220 | getBoardCell(arr[0],arr[1]).removeEventListener(ev, func);
221 | }
222 | else {
223 | var wh = getObjFromDataAtr(arr.attributes["data-matrixval"].value);
224 | if (wh[0]<0||wh[1]<0||wh[0]>size[0]-1||wh[1]>size[1]-1) { return "OOB"; }
225 | var th = getBoardCell(wh[0],wh[1]);
226 | th.removeEventListener(ev, func);
227 | }
228 | },
229 | // get content of given cell
230 | // this is why text property of a piece is required
231 | // otherwise it would return null
232 | get: function() {
233 | if (typeof arr[0] == "number") {
234 | if (arr[0]<0||arr[1]<0||arr[0]>size[0]-1||arr[1]>size[1]-1) { return "OOB"; }
235 | var th = getBoardCell(arr[0],arr[1]);
236 | if (typeof th.childNodes[0] == "undefined") { return null; }
237 | // need data because it returns object
238 | else { return th.childNodes[0].childNodes[0].data; }
239 | }
240 | else {
241 | var wh = getObjFromDataAtr(arr.attributes["data-matrixval"].value);
242 | if (wh[0]<0||wh[1]<0||wh[0]>size[0]-1||wh[1]>size[1]-1) { return "OOB"; }
243 | var th = getBoardCell(wh[0],wh[1]);
244 | if (typeof th.childNodes[0] == "undefined") { return null; }
245 | else { return th.childNodes[0].childNodes[0].data; }
246 | }
247 | },
248 | // get where in matrix current cell is
249 | where: function() {
250 | var wh = getObjFromDataAtr(arr.attributes["data-matrixval"].value);
251 | if (wh[0]<0||wh[1]<0||wh[0]>size[0]-1||wh[1]>size[1]-1) { return "OOB"; }
252 | return [wh[0],wh[1]];
253 | }
254 | };
255 | return cellMethods;
256 | }
257 |
258 | };
259 |
260 | return methods;
261 |
262 | }
263 |
264 | function Piece(node) {
265 |
266 | var node = node;
267 |
268 | var methods = {
269 | clone: function() {
270 | var nn = node.cloneNode(true);
271 | var ra = Math.floor((Math.random() * 3000) + 1);
272 | nn.className = "pieceID_"+ra;
273 | return nn;
274 | },
275 | style: function(props) {
276 | for (var st in props) {
277 | node.style[st] = props[st];
278 | }
279 | }
280 | };
281 |
282 | return methods;
283 |
284 | }
285 |
286 | // methods to create new game board and pieces
287 | var methods = {
288 |
289 | // create new game board
290 | board: function(props) {
291 | var size = [];
292 | for (var el in props) {
293 | if (el=="size") {
294 | if (!props.attach) { console.log("Need attachment for game board"); }
295 | else {
296 | var s = props[el].split("x");
297 | var attachedBoard = document.getElementById(props.attach);
298 |
299 | size.push(parseInt(s[0]),parseInt(s[1]));
300 | // create table data to represent game board in DOM
301 | for (var i=0; i0;)a.pop();for(var t=0;te)for(;0>e;)r[1]>0?r[1]-=1:(r[1]=t[1]-1,r[0]-=1),e++;else for(;e>0;)r[1]t[0]-1||e[1]>t[1]-1?document.createElement("div"):document.getElementsByClassName("boardRow_"+e[0])[0].childNodes[e[1]];var r=n(e.attributes["data-matrixval"].value);if(r[0]<0||r[1]<0||r[0]>t[0]-1||r[1]>t[1]-1)return document.createElement("div");var i=a(r[0],r[1]);return"undefined"==typeof i.childNodes[0]?document.createElement("div"):a(r[0],r[1])},style:function(r){if("each"==e)for(var i in r)for(var o=0;ot[0]-1||e[1]>t[1]-1)return"OOB";for(var i in r)a(e[0],e[1]).style[i]=r[i]}else{var l=n(e.attributes["data-matrixval"].value);if(l[0]<0||l[1]<0||l[0]>t[0]-1||l[1]>t[1]-1)return"OOB";var s=a(l[0],l[1]);for(var i in r)s.style[i]=r[i]}},place:function(r){if("each"==e)for(var i=0;it[0]-1||f[1]>t[1]-1)return"OOB";for(var d=a(f[0],f[1]);d.firstChild;)d.removeChild(d.firstChild);a(f[0],f[1]).appendChild(r)}},rid:function(){if("each"==e)for(var r=0;rt[0]-1||d[1]>t[1]-1)return"OOB";for(var o=a(d[0],d[1]);o.firstChild;)o.removeChild(o.firstChild)}},on:function(r,i){if("each"==e)for(var o=0;ot[0]-1||e[1]>t[1]-1)return"OOB";a(e[0],e[1]).addEventListener(r,i)}else{var l=n(e.attributes["data-matrixval"].value);if(l[0]<0||l[1]<0||l[0]>t[0]-1||l[1]>t[1]-1)return"OOB";var s=a(l[0],l[1]);s.addEventListener(r,i)}},removeOn:function(r,i){if("each"==e)for(var o=0;ot[0]-1||e[1]>t[1]-1)return"OOB";a(e[0],e[1]).removeEventListener(r,i)}else{var l=n(e.attributes["data-matrixval"].value);if(l[0]<0||l[1]<0||l[0]>t[0]-1||l[1]>t[1]-1)return"OOB";var s=a(l[0],l[1]);s.removeEventListener(r,i)}},get:function(){if("number"==typeof e[0]){if(e[0]<0||e[1]<0||e[0]>t[0]-1||e[1]>t[1]-1)return"OOB";var r=a(e[0],e[1]);return"undefined"==typeof r.childNodes[0]?null:r.childNodes[0].childNodes[0].data}var i=n(e.attributes["data-matrixval"].value);if(i[0]<0||i[1]<0||i[0]>t[0]-1||i[1]>t[1]-1)return"OOB";var r=a(i[0],i[1]);return"undefined"==typeof r.childNodes[0]?null:r.childNodes[0].childNodes[0].data},where:function(){var r=n(e.attributes["data-matrixval"].value);return r[0]<0||r[1]<0||r[0]>t[0]-1||r[1]>t[1]-1?"OOB":[r[0],r[1]]}};return o}};return n}function t(e){var e=e,t={clone:function(){var t=e.cloneNode(!0),r=Math.floor(3e3*Math.random()+1);return t.className="pieceID_"+r,t},style:function(t){for(var r in t)e.style[r]=t[r]}};return t}var r={board:function(t){var r=[];for(var a in t)if("size"==a)if(t.attach){var n=t[a].split("x");r.push(parseInt(n[0]),parseInt(n[1]));for(var i=0;i