├── Chess
├── Board.js
├── MinimaxFunctions.js
├── Piece.js
├── assets
│ ├── 2000px-Chess_Pieces_Sprite_01.png
│ ├── 2000px-Chess_Pieces_Sprite_02.png
│ ├── 2000px-Chess_Pieces_Sprite_03.png
│ ├── 2000px-Chess_Pieces_Sprite_04.png
│ ├── 2000px-Chess_Pieces_Sprite_05.png
│ ├── 2000px-Chess_Pieces_Sprite_06.png
│ ├── 2000px-Chess_Pieces_Sprite_07.png
│ ├── 2000px-Chess_Pieces_Sprite_08.png
│ ├── 2000px-Chess_Pieces_Sprite_09.png
│ ├── 2000px-Chess_Pieces_Sprite_10.png
│ ├── 2000px-Chess_Pieces_Sprite_11.png
│ └── 2000px-Chess_Pieces_Sprite_12.png
├── index.html
├── libraries
│ ├── p5.dom.js
│ ├── p5.js
│ └── p5.sound.js
└── sketch.js
└── README.md
/Chess/Board.js:
--------------------------------------------------------------------------------
1 | class Board {
2 | constructor() {
3 | this.whitePieces = [];
4 | this.blackPieces = [];
5 | this.score = 0;
6 | this.setupPieces();
7 |
8 |
9 | }
10 |
11 | setupPieces() {
12 | this.whitePieces.push(new King(4, 7, true));
13 | this.whitePieces.push(new Queen(3, 7, true));
14 | this.whitePieces.push(new Bishop(2, 7, true));
15 | this.whitePieces.push(new Bishop(5, 7, true));
16 | this.whitePieces.push(new Knight(1, 7, true));
17 | this.whitePieces.push(new Rook(0, 7, true));
18 | this.whitePieces.push(new Knight(6, 7, true));
19 | this.whitePieces.push(new Rook(7, 7, true));
20 |
21 | this.whitePieces.push(new Pawn(4, 6, true));
22 | this.whitePieces.push(new Pawn(3, 6, true));
23 | this.whitePieces.push(new Pawn(2, 6, true));
24 | this.whitePieces.push(new Pawn(5, 6, true));
25 | this.whitePieces.push(new Pawn(1, 6, true));
26 | this.whitePieces.push(new Pawn(0, 6, true));
27 | this.whitePieces.push(new Pawn(6, 6, true));
28 | this.whitePieces.push(new Pawn(7, 6, true));
29 |
30 | //black pieces
31 | this.blackPieces.push(new King(4, 0, false));
32 | this.blackPieces.push(new Queen(3, 0, false));
33 | this.blackPieces.push(new Bishop(2, 0, false));
34 | this.blackPieces.push(new Bishop(5, 0, false));
35 | this.blackPieces.push(new Knight(1, 0, false));
36 | this.blackPieces.push(new Rook(0, 0, false));
37 | this.blackPieces.push(new Knight(6, 0, false));
38 | this.blackPieces.push(new Rook(7, 0, false));
39 |
40 | this.blackPieces.push(new Pawn(4, 1, false));
41 | this.blackPieces.push(new Pawn(3, 1, false));
42 | this.blackPieces.push(new Pawn(2, 1, false));
43 | this.blackPieces.push(new Pawn(5, 1, false));
44 | this.blackPieces.push(new Pawn(1, 1, false));
45 | this.blackPieces.push(new Pawn(0, 1, false));
46 | this.blackPieces.push(new Pawn(6, 1, false));
47 | this.blackPieces.push(new Pawn(7, 1, false));
48 |
49 |
50 | }
51 |
52 | show() {
53 | for (var i = 0; i < this.whitePieces.length; i++) {
54 | this.whitePieces[i].show();
55 | }
56 | for (var i = 0; i < this.blackPieces.length; i++) {
57 | this.blackPieces[i].show();
58 | }
59 | }
60 |
61 | isPieceAt(x, y) {
62 | for (var i = 0; i < this.whitePieces.length; i++) {
63 | if (!this.whitePieces[i].taken && this.whitePieces[i].matrixPosition.x ==
64 | x && this.whitePieces[i].matrixPosition.y == y) {
65 | return true;
66 | }
67 | }
68 | for (var i = 0; i < this.blackPieces.length; i++) {
69 | if (!this.blackPieces[i].taken && this.blackPieces[i].matrixPosition.x ==
70 | x && this.blackPieces[i].matrixPosition.y == y) {
71 | return true;
72 | }
73 | }
74 | return false;
75 | }
76 |
77 | getPieceAt(x, y) {
78 | for (var i = 0; i < this.whitePieces.length; i++) {
79 | if (!this.whitePieces[i].taken && this.whitePieces[i].matrixPosition.x ==
80 | x && this.whitePieces[i].matrixPosition.y == y) {
81 | return this.whitePieces[i];
82 | }
83 | }
84 | for (var i = 0; i < this.blackPieces.length; i++) {
85 | if (!this.blackPieces[i].taken && this.blackPieces[i].matrixPosition.x ==
86 | x && this.blackPieces[i].matrixPosition.y == y) {
87 | return this.blackPieces[i];
88 | }
89 | }
90 | return null;
91 | }
92 |
93 |
94 | generateNewBoardsWhitesTurn() {
95 | var boards = [];
96 | for (var i = 0; i < this.whitePieces.length; i++) {
97 | if (!this.whitePieces[i].taken) {
98 | var tempArr = this.whitePieces[i].generateNewBoards(this);
99 | for (var j = 0; j < tempArr.length; j++) {
100 | boards.push(tempArr[j]);
101 | }
102 | }
103 | }
104 | return boards;
105 | }
106 | generateNewBoardsBlacksTurn() {
107 | var boards = [];
108 | for (var i = 0; i < this.blackPieces.length; i++) {
109 | if (!this.blackPieces[i].taken) {
110 | var tempArr = this.blackPieces[i].generateNewBoards(this);
111 | for (var j = 0; j < tempArr.length; j++) {
112 | boards.push(tempArr[j]);
113 | }
114 | }
115 | }
116 | return boards;
117 | }
118 |
119 | setScore() {
120 | this.score = 0;
121 | for (var i = 0; i < this.whitePieces.length; i++) {
122 | if (!this.whitePieces[i].taken) {
123 | this.score -= this.whitePieces[i].value;
124 | } else {
125 | //print("something");
126 | }
127 | }
128 | for (var i = 0; i < this.blackPieces.length; i++) {
129 | if (!this.blackPieces[i].taken) {
130 | this.score += this.blackPieces[i].value;
131 | } else {
132 | //print("something");
133 | }
134 | }
135 |
136 | }
137 |
138 | move(from, to) {
139 | var pieceToMove = this.getPieceAt(from.x, from.y);
140 | if (pieceToMove == null) {
141 | //print("shit");
142 | return;
143 | }
144 | // if (pieceToMove.canMove(to.x, to.y, this)) {
145 | pieceToMove.move(to.x, to.y, this);
146 | // }
147 | }
148 |
149 |
150 | clone() {
151 | var clone = new Board();
152 | for (var i = 0; i < this.whitePieces.length; i++) {
153 | clone.whitePieces[i] = this.whitePieces[i].clone();
154 | }
155 | for (var i = 0; i < this.blackPieces.length; i++) {
156 | clone.blackPieces[i] = this.blackPieces[i].clone();
157 | }
158 | return clone;
159 | }
160 |
161 | isDone() {
162 | return this.whitePieces[0].taken || this.blackPieces[0].taken;
163 | }
164 | isDead() {
165 | if (whiteAI && whitesMove) {
166 | return this.whitePieces[0].taken;
167 | }
168 | if (blackAI && !whitesMove) {
169 | return this.blackPieces[0].taken;
170 | }
171 |
172 | return false;
173 | }
174 |
175 | hasWon() {
176 | if (whiteAI && whitesMove) {
177 | return this.blackPieces[0].taken;
178 | }
179 | if (blackAI && !whitesMove) {
180 | return this.whitePieces[0].taken;
181 | }
182 |
183 | return false;
184 | }
185 | }
186 |
--------------------------------------------------------------------------------
/Chess/MinimaxFunctions.js:
--------------------------------------------------------------------------------
1 | var maxDepth = 3;
2 |
3 |
4 | function minFun(board, depth) {
5 | if (depth >= maxDepth) {
6 | board.setScore();
7 | return board.score;
8 | }
9 |
10 | var boards = board.generateNewBoardsWhitesTurn();
11 | var lowestBoardNo = 0;
12 | var lowestScore = 100000;
13 | for (var i = 0; i < boards.length; i++) {
14 | if (!boards[i].isDead()) {
15 | var score = maxFun(boards[i], depth + 1);
16 | if (score < lowestScore) {
17 | lowestBoardNo = i;
18 | lowestScore = score;
19 | }
20 | }
21 | }
22 | return lowestScore;
23 | }
24 |
25 | function maxFun(board, depth) {
26 | if (depth >= maxDepth) {
27 | board.setScore();
28 | return board.score;
29 | }
30 |
31 |
32 | var boards = board.generateNewBoardsBlacksTurn();
33 | if (depth == 0) {
34 | //////print(boards);
35 | }
36 | var topBoardNo = 0;
37 | var topScore = -100000;
38 | for (var i = 0; i < boards.length; i++) {
39 | var score = minFun(boards[i], depth + 1);
40 | if (score > topScore) {
41 | topBoardNo = i;
42 | topScore = score;
43 | }
44 | }
45 |
46 | if (depth == 0) {
47 | ////print(topScore);
48 | return boards[topBoardNo];
49 | }
50 | return topScore;
51 | }
52 |
53 |
54 | function minFunAB(board, alpha, beta, depth) {
55 | if (depth >= maxDepth) {
56 | board.setScore();
57 | return board.score;
58 | }
59 |
60 |
61 | if (board.isDead()) {
62 | if (whiteAI && whitesMove) {
63 | return 200;
64 | }
65 | if (blackAI && !whitesMove) {
66 | return -200;
67 | }
68 | }
69 |
70 | if (board.hasWon()) {
71 |
72 | if (whiteAI && whitesMove) {
73 | return -200;
74 | }
75 | if (blackAI && !whitesMove) {
76 | return 200;
77 | }
78 | }
79 |
80 | var boards = board.generateNewBoardsWhitesTurn();
81 | var lowestBoardNo = 0;
82 | var lowestScore = 300;
83 | for (var i = 0; i < boards.length; i++) {
84 |
85 | var score = maxFunAB(boards[i], alpha, beta, depth + 1);
86 | if (depth == 0) {
87 | //print(score, i, boards[i]);
88 | }
89 | if (score < lowestScore) {
90 | lowestBoardNo = i;
91 | lowestScore = score;
92 | } else {
93 | if (depth == 0 && score == lowestScore) {
94 | //print("same as so i do what i want", i);
95 | if (random(1) < 0.3) {
96 | lowestBoardNo = i;
97 | }
98 | }
99 | }
100 | if (score < alpha) {
101 | return lowestScore;
102 | }
103 | if (score < beta) {
104 | beta = score;
105 | }
106 |
107 | }
108 |
109 | if (depth == 0) {
110 | ////print(lowestScore);
111 | ////print("i made it here");
112 | return boards[lowestBoardNo];
113 | }
114 | ////print("ohNo");
115 | ////print(lowestScore);
116 | return lowestScore;
117 | }
118 | //---------------------------------------------------------------------------------------
119 | function maxFunAB(board, alpha, beta, depth) {
120 | if (depth >= maxDepth) {
121 | board.setScore();
122 | return board.score;
123 | }
124 |
125 | if (board.isDead()) {
126 | if (whiteAI && whitesMove) {
127 | return 200;
128 | }
129 | if (blackAI && !whitesMove) {
130 | return -200;
131 | }
132 | }
133 |
134 | if (board.hasWon()) {
135 | if (whiteAI && whitesMove) {
136 | return -200;
137 | }
138 | if (blackAI && !whitesMove) {
139 | return 200;
140 | }
141 | }
142 |
143 | var boards = board.generateNewBoardsBlacksTurn();
144 | if (depth == 0) {
145 | //////print(boards);
146 | }
147 | var topBoardNo = 0;
148 | var topScore = -300;
149 | for (var i = 0; i < boards.length; i++) {
150 |
151 | var score = minFunAB(boards[i], alpha, beta, depth + 1);
152 | if (score > topScore) {
153 | topBoardNo = i;
154 | topScore = score;
155 | } else {
156 | if (depth == 0 && score == topScore) {
157 | if (random(1) < 0.3) {
158 | topBoardNo = i;
159 | }
160 | }
161 | }
162 | if (score > beta) {
163 | return topScore;
164 | }
165 | if (score > alpha) {
166 | alpha = score;
167 | }
168 |
169 | }
170 |
171 | if (depth == 0) {
172 | ////print(topScore);
173 | return boards[topBoardNo];
174 | }
175 | return topScore;
176 | }
177 |
--------------------------------------------------------------------------------
/Chess/Piece.js:
--------------------------------------------------------------------------------
1 | class Piece {
2 | constructor(x, y, isWhite, letter, pic) {
3 | this.matrixPosition = createVector(x, y);
4 | this.pixelPosition = createVector(x * tileSize + tileSize / 2, y *
5 | tileSize + tileSize / 2);
6 |
7 | this.taken = false;
8 | this.white = isWhite;
9 | this.letter = letter;
10 | this.pic = pic;
11 | this.movingThisPiece = false;
12 | this.value = 0;
13 | }
14 |
15 | //needs to extend these
16 | show() {
17 | if (!this.taken) {
18 |
19 | // textSize(40);
20 | // strokeWeight(5);
21 | // if(this.white){
22 | // fill(255);
23 | // stroke(0);
24 | // }else{
25 | // fill(30);
26 | // stroke(255);
27 | // }
28 | // textAlign(CENTER,CENTER);
29 | imageMode(CENTER);
30 | if (this.movingThisPiece) {
31 | // text(this.letter, mouseX,mouseY);
32 | image(this.pic, mouseX, mouseY, tileSize * 1.5, tileSize * 1.5);
33 |
34 | } else {
35 | // text(this.letter, this.pixelPosition.x,this.pixelPosition.y);
36 | image(this.pic, this.pixelPosition.x, this.pixelPosition.y, tileSize,
37 | tileSize);
38 |
39 | }
40 | }
41 | }
42 |
43 |
44 | generateNewBoards(currentBoard) {
45 | var boards = []; //all boards created from moving this piece
46 | var moves = this.generateMoves(currentBoard); //all the posible moves this piece can do ,as vectors
47 | for (var i = 0; i < moves.length; i++) { //for each move
48 | boards[i] = currentBoard.clone(); //create a new board
49 | boards[i].move(this.matrixPosition, moves[i]); //move this piece to the mvoe location
50 | }
51 |
52 | return boards;
53 | }
54 |
55 |
56 | withinBounds(x, y) {
57 |
58 | if (x >= 0 && y >= 0 && x < 8 && y < 8) {
59 | return true;
60 | }
61 | return false;
62 |
63 | }
64 |
65 |
66 |
67 | move(x, y, board) {
68 | var attacking = board.getPieceAt(x, y);
69 | if (attacking != null) {
70 | attacking.taken = true;
71 | }
72 | this.matrixPosition = createVector(x, y);
73 | this.pixelPosition = createVector(x * tileSize + tileSize / 2, y *
74 | tileSize + tileSize / 2);
75 |
76 | }
77 | attackingAllies(x, y, board) {
78 | var attacking = board.getPieceAt(x, y);
79 | if (attacking != null) {
80 | if (attacking.white == this.white) {
81 | //if they are of the same player
82 | return true;
83 | }
84 | }
85 | return false;
86 | }
87 | canMove(x, y, board) {
88 | if (!this.withinBounds(x, y)) {
89 | return false;
90 | }
91 | return true;
92 | }
93 |
94 | moveThroughPieces(x, y, board) {
95 | var stepDirectionX = x - this.matrixPosition.x;
96 | if (stepDirectionX > 0) {
97 | stepDirectionX = 1;
98 | } else if (stepDirectionX < 0) {
99 | stepDirectionX = -1;
100 | }
101 | var stepDirectionY = y - this.matrixPosition.y;
102 | if (stepDirectionY > 0) {
103 | stepDirectionY = 1;
104 | } else if (stepDirectionY < 0) {
105 | stepDirectionY = -1;
106 | }
107 | var tempPos = createVector(this.matrixPosition.x, this.matrixPosition.y);
108 | tempPos.x += stepDirectionX;
109 | tempPos.y += stepDirectionY;
110 | while (tempPos.x != x || tempPos.y != y) {
111 |
112 | if (board.getPieceAt(tempPos.x, tempPos.y) != null) {
113 | return true;
114 | }
115 | tempPos.x += stepDirectionX;
116 | tempPos.y += stepDirectionY;
117 | }
118 |
119 | return false;
120 | }
121 |
122 |
123 |
124 | }
125 |
126 | class King extends Piece {
127 | constructor(x, y, isWhite) {
128 | super(x, y, isWhite);
129 | this.letter = "K";
130 | if (isWhite) {
131 | this.pic = images[0];
132 |
133 | } else {
134 | this.pic = images[6];
135 | }
136 | this.value = 99;
137 | }
138 |
139 | clone() {
140 | var clone = new King(this.matrixPosition.x, this.matrixPosition.y, this.white);
141 | clone.taken = this.taken;
142 | return clone;
143 |
144 | }
145 |
146 |
147 |
148 | canMove(x, y, board) {
149 | if (!this.withinBounds(x, y)) {
150 | return false;
151 | }
152 | if (this.attackingAllies(x, y, board)) {
153 | return false;
154 | }
155 | if (abs(x - this.matrixPosition.x) <= 1 && abs(y - this.matrixPosition.y) <=
156 | 1) {
157 | return true;
158 | }
159 | return false;
160 | }
161 |
162 | generateMoves(board) {
163 | var moves = [];
164 | for (var i = -1; i < 2; i++) {
165 | for (var j = -1; j < 2; j++) {
166 | var x = this.matrixPosition.x + i;
167 | var y = this.matrixPosition.y + j;
168 | if (this.withinBounds(x, y)) {
169 | if (i != 0 || j != 0) {
170 | if (!this.attackingAllies(x, y, board)) {
171 | moves.push(createVector(x, y))
172 | }
173 | }
174 | }
175 | }
176 |
177 | }
178 | return moves;
179 |
180 | }
181 | }
182 |
183 | class Queen extends Piece {
184 | constructor(x, y, isWhite) {
185 | super(x, y, isWhite);
186 | this.letter = "Q";
187 | if (isWhite) {
188 | this.pic = images[1];
189 |
190 | } else {
191 | this.pic = images[7];
192 | }
193 | this.value = 9;
194 |
195 | }
196 | canMove(x, y, board) {
197 | if (!this.withinBounds(x, y)) {
198 | return false;
199 | }
200 | if (this.attackingAllies(x, y, board)) {
201 | return false;
202 | }
203 |
204 | if (x == this.matrixPosition.x || y == this.matrixPosition.y) {
205 | if (this.moveThroughPieces(x, y, board)) {
206 | return false;
207 | }
208 |
209 | return true;
210 | }
211 | //diagonal
212 | if (abs(x - this.matrixPosition.x) == abs(y - this.matrixPosition.y)) {
213 | if (this.moveThroughPieces(x, y, board)) {
214 | return false;
215 | }
216 |
217 | return true;
218 | }
219 | return false;
220 | }
221 | generateMoves(board) {
222 | var moves = [];
223 |
224 | //generateHorizontal moves
225 | for (var i = 0; i < 8; i++) {
226 | var x = i;
227 | var y = this.matrixPosition.y;
228 | if (x != this.matrixPosition.x) {
229 | if (!this.attackingAllies(x, y, board)) {
230 | if (!this.moveThroughPieces(x, y, board)) {
231 | moves.push(createVector(x, y));
232 | }
233 | }
234 | }
235 | }
236 | //generateVertical moves
237 | for (var i = 0; i < 8; i++) {
238 | var x = this.matrixPosition.x;;
239 | var y = i;
240 | if (i != this.matrixPosition.y) {
241 | if (!this.attackingAllies(x, y, board)) {
242 | if (!this.moveThroughPieces(x, y, board)) {
243 | moves.push(createVector(x, y));
244 | }
245 | }
246 | }
247 | }
248 |
249 | //generateDiagonal Moves
250 | for (var i = 0; i < 8; i++) {
251 | var x = i;
252 | var y = this.matrixPosition.y - (this.matrixPosition.x - i);
253 | if (x != this.matrixPosition.x) {
254 | if (this.withinBounds(x, y)) {
255 | if (!this.attackingAllies(x, y, board)) {
256 | if (!this.moveThroughPieces(x, y, board)) {
257 | moves.push(createVector(x, y));
258 | }
259 | }
260 | }
261 | }
262 | }
263 |
264 | for (var i = 0; i < 8; i++) {
265 | var x = this.matrixPosition.x + (this.matrixPosition.y - i);
266 | var y = i;
267 | if (x != this.matrixPosition.x) {
268 | if (this.withinBounds(x, y)) {
269 | if (!this.attackingAllies(x, y, board)) {
270 | if (!this.moveThroughPieces(x, y, board)) {
271 | moves.push(createVector(x, y));
272 | }
273 | }
274 | }
275 | }
276 | }
277 | //print("Queen", moves);
278 | return moves;
279 | }
280 | clone() {
281 | var clone = new Queen(this.matrixPosition.x, this.matrixPosition.y,
282 | this.white);
283 | clone.taken = this.taken;
284 | return clone;
285 |
286 | }
287 | }
288 | class Bishop extends Piece {
289 | constructor(x, y, isWhite) {
290 | super(x, y, isWhite);
291 | this.letter = "B";
292 | if (isWhite) {
293 | this.pic = images[2];
294 |
295 | } else {
296 | this.pic = images[8];
297 | }
298 | this.value = 3;
299 |
300 | }
301 | canMove(x, y, board) {
302 | if (!this.withinBounds(x, y)) {
303 | return false;
304 | }
305 | if (this.attackingAllies(x, y, board)) {
306 | return false;
307 | }
308 |
309 |
310 | //diagonal
311 | if (abs(x - this.matrixPosition.x) == abs(y - this.matrixPosition.y)) {
312 | if (this.moveThroughPieces(x, y, board)) {
313 | return false;
314 | }
315 |
316 | return true;
317 | }
318 | return false;
319 | }
320 |
321 | generateMoves(board) {
322 | var moves = [];
323 | //generateDiagonal Moves
324 | for (var i = 0; i < 8; i++) {
325 | var x = i;
326 | var y = this.matrixPosition.y - (this.matrixPosition.x - i);
327 | if (x != this.matrixPosition.x) {
328 | if (this.withinBounds(x, y)) {
329 | if (!this.attackingAllies(x, y, board)) {
330 | if (!this.moveThroughPieces(x, y, board)) {
331 | moves.push(createVector(x, y));
332 | }
333 | }
334 | }
335 | }
336 | }
337 |
338 | for (var i = 0; i < 8; i++) {
339 | var x = this.matrixPosition.x + (this.matrixPosition.y - i);
340 | var y = i;
341 | if (x != this.matrixPosition.x) {
342 | if (this.withinBounds(x, y)) {
343 | if (!this.attackingAllies(x, y, board)) {
344 | if (!this.moveThroughPieces(x, y, board)) {
345 | moves.push(createVector(x, y));
346 | }
347 | }
348 | }
349 | }
350 | }
351 | //print("Bishop", moves);
352 |
353 | return moves;
354 | }
355 | clone() {
356 | var clone = new Bishop(this.matrixPosition.x, this.matrixPosition.y,
357 | this.white);
358 | clone.taken = this.taken;
359 | return clone;
360 |
361 | }
362 | }
363 | class Rook extends Piece {
364 | constructor(x, y, isWhite) {
365 | super(x, y, isWhite);
366 | this.letter = "R";
367 | if (isWhite) {
368 | this.pic = images[4];
369 |
370 | } else {
371 | this.pic = images[10];
372 | }
373 | this.value = 5;
374 |
375 | }
376 | canMove(x, y, board) {
377 | if (!this.withinBounds(x, y)) {
378 | return false;
379 | }
380 | if (this.attackingAllies(x, y, board)) {
381 | return false;
382 | }
383 |
384 |
385 | if (x == this.matrixPosition.x || y == this.matrixPosition.y) {
386 | if (this.moveThroughPieces(x, y, board)) {
387 | return false;
388 | }
389 |
390 | return true;
391 | }
392 | return false;
393 | }
394 |
395 | generateMoves(board) {
396 | var moves = [];
397 |
398 | //generateHorizontal moves
399 | for (var i = 0; i < 8; i++) {
400 | var x = i;
401 | var y = this.matrixPosition.y;
402 | if (x != this.matrixPosition.x) {
403 | if (!this.attackingAllies(x, y, board)) {
404 | if (!this.moveThroughPieces(x, y, board)) {
405 | moves.push(createVector(x, y));
406 | }
407 | }
408 | }
409 | }
410 | //generateVertical moves
411 | for (var i = 0; i < 8; i++) {
412 | var x = this.matrixPosition.x;;
413 | var y = i;
414 | if (i != this.matrixPosition.y) {
415 | if (!this.attackingAllies(x, y, board)) {
416 | if (!this.moveThroughPieces(x, y, board)) {
417 | moves.push(createVector(x, y));
418 | }
419 | }
420 | }
421 | }
422 | //print("Rook", moves);
423 |
424 | return moves;
425 |
426 |
427 | }
428 |
429 | clone() {
430 | var clone = new Rook(this.matrixPosition.x, this.matrixPosition.y, this
431 | .white);
432 | clone.taken = this.taken;
433 | return clone;
434 |
435 | }
436 | }
437 | class Knight extends Piece {
438 | constructor(x, y, isWhite) {
439 | super(x, y, isWhite);
440 | this.letter = "Kn";
441 | if (isWhite) {
442 | this.pic = images[3];
443 |
444 | } else {
445 | this.pic = images[9];
446 | }
447 | this.value = 3;
448 |
449 | }
450 |
451 | canMove(x, y, board) {
452 | if (!this.withinBounds(x, y)) {
453 | return false;
454 | }
455 | if (this.attackingAllies(x, y, board)) {
456 | return false;
457 | }
458 |
459 |
460 | if ((abs(x - this.matrixPosition.x) == 2 && abs(y - this.matrixPosition
461 | .y) == 1) || (abs(x - this.matrixPosition.x) == 1 && abs(y - this.matrixPosition
462 | .y) == 2)) {
463 | return true;
464 | }
465 | return false;
466 | }
467 |
468 |
469 |
470 | generateMoves(board) {
471 | var moves = [];
472 | for (var i = -2; i < 3; i += 4) {
473 | for (var j = -1; j < 2; j += 2) {
474 |
475 | var x = i + this.matrixPosition.x;
476 | var y = j + this.matrixPosition.y;
477 | if (!this.attackingAllies(x, y, board)) {
478 | if (this.withinBounds(x, y)) {
479 | moves.push(createVector(x, y));
480 |
481 | }
482 | }
483 | }
484 | }
485 | for (var i = -1; i < 2; i += 2) {
486 | for (var j = -2; j < 3; j += 4) {
487 |
488 | var x = i + this.matrixPosition.x;
489 | var y = j + this.matrixPosition.y;
490 |
491 | if (this.withinBounds(x, y)) {
492 | if (!this.attackingAllies(x, y, board)) {
493 | moves.push(createVector(x, y));
494 |
495 | }
496 | }
497 | }
498 | }
499 | //print("Knight", moves);
500 |
501 | return moves;
502 |
503 | }
504 | clone() {
505 | var clone = new Knight(this.matrixPosition.x, this.matrixPosition.y,
506 | this.white);
507 | clone.taken = this.taken;
508 | return clone;
509 |
510 | }
511 | }
512 | class Pawn extends Piece {
513 | constructor(x, y, isWhite) {
514 | super(x, y, isWhite);
515 | this.letter = "p";
516 | this.firstTurn = true;
517 | if (isWhite) {
518 | this.pic = images[5];
519 |
520 | } else {
521 | this.pic = images[11];
522 | }
523 | this.value = 1;
524 |
525 | }
526 |
527 | canMove(x, y, board) {
528 | if (!this.withinBounds(x, y)) {
529 | return false;
530 | }
531 | if (this.attackingAllies(x, y, board)) {
532 | return false;
533 | }
534 | var attacking = board.isPieceAt(x, y);
535 | if (attacking) {
536 | //if attacking a player
537 | if (abs(x - this.matrixPosition.x) == abs(y - this.matrixPosition.y) &&
538 | ((this.white && (y - this.matrixPosition.y) == -1) || (!this.white &&
539 | (y - this.matrixPosition.y) == 1))) {
540 | this.firstTurn = false;
541 | return true;
542 | }
543 | return false;
544 | }
545 | if (x != this.matrixPosition.x) {
546 | return false;
547 | }
548 | if ((this.white && y - this.matrixPosition.y == -1) || (!this.white &&
549 | y - this.matrixPosition.y == 1)) {
550 | this.firstTurn = false;
551 | return true;
552 | }
553 | if (this.firstTurn && ((this.white && y - this.matrixPosition.y == -2) ||
554 | (!this.white && y - this.matrixPosition.y == 2))) {
555 | if (this.moveThroughPieces(x, y, board)) {
556 | return false;
557 | }
558 |
559 | this.firstTurn = false;
560 | return true;
561 | }
562 | return false;
563 | }
564 |
565 |
566 | generateMoves(board) {
567 | var moves = [];
568 |
569 | for (var i = -1; i < 2; i += 2) {
570 | var x = this.matrixPosition.x + i;
571 | if (this.white) {
572 | var y = this.matrixPosition.y - 1;
573 | } else {
574 | var y = this.matrixPosition.y + 1;
575 | }
576 | var attacking = board.getPieceAt(x, y);
577 | if (attacking) {
578 | if (!this.attackingAllies(x, y, board)) {
579 | moves.push(createVector(x, y));
580 | }
581 | }
582 | }
583 |
584 | var x = this.matrixPosition.x;
585 | if (this.white) {
586 | var y = this.matrixPosition.y - 1;
587 | } else {
588 | var y = this.matrixPosition.y + 1;
589 | }
590 | if (!board.isPieceAt(x, y) && this.withinBounds(x, y)) {
591 | moves.push(createVector(x, y));
592 | }
593 |
594 | if (this.firstTurn) {
595 |
596 | if (this.white) {
597 | var y = this.matrixPosition.y - 2;
598 | } else {
599 | var y = this.matrixPosition.y + 2;
600 | }
601 | if (!board.isPieceAt(x, y) && this.withinBounds(x, y)) {
602 | if (!this.moveThroughPieces(x, y, board)) {
603 | moves.push(createVector(x, y));
604 | }
605 | }
606 | }
607 | //print("pawn", moves);
608 | return moves;
609 | }
610 | clone() {
611 | var clone = new Pawn(this.matrixPosition.x, this.matrixPosition.y, this
612 | .white);
613 | clone.taken = this.taken;
614 | clone.firstTurn = this.firstTurn;
615 | return clone;
616 | }
617 |
618 | move(x, y, board) {
619 | var attacking = board.getPieceAt(x, y);
620 | if (attacking != null) {
621 | attacking.taken = true;
622 | }
623 | this.matrixPosition = createVector(x, y);
624 | this.pixelPosition = createVector(x * tileSize + tileSize / 2, y *
625 | tileSize + tileSize / 2);
626 | this.firstTurn = false;
627 | }
628 | }
629 |
--------------------------------------------------------------------------------
/Chess/assets/2000px-Chess_Pieces_Sprite_01.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Code-Bullet/Chess-AI/c5910012ab15126aca1a211e268fcb350d48df59/Chess/assets/2000px-Chess_Pieces_Sprite_01.png
--------------------------------------------------------------------------------
/Chess/assets/2000px-Chess_Pieces_Sprite_02.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Code-Bullet/Chess-AI/c5910012ab15126aca1a211e268fcb350d48df59/Chess/assets/2000px-Chess_Pieces_Sprite_02.png
--------------------------------------------------------------------------------
/Chess/assets/2000px-Chess_Pieces_Sprite_03.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Code-Bullet/Chess-AI/c5910012ab15126aca1a211e268fcb350d48df59/Chess/assets/2000px-Chess_Pieces_Sprite_03.png
--------------------------------------------------------------------------------
/Chess/assets/2000px-Chess_Pieces_Sprite_04.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Code-Bullet/Chess-AI/c5910012ab15126aca1a211e268fcb350d48df59/Chess/assets/2000px-Chess_Pieces_Sprite_04.png
--------------------------------------------------------------------------------
/Chess/assets/2000px-Chess_Pieces_Sprite_05.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Code-Bullet/Chess-AI/c5910012ab15126aca1a211e268fcb350d48df59/Chess/assets/2000px-Chess_Pieces_Sprite_05.png
--------------------------------------------------------------------------------
/Chess/assets/2000px-Chess_Pieces_Sprite_06.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Code-Bullet/Chess-AI/c5910012ab15126aca1a211e268fcb350d48df59/Chess/assets/2000px-Chess_Pieces_Sprite_06.png
--------------------------------------------------------------------------------
/Chess/assets/2000px-Chess_Pieces_Sprite_07.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Code-Bullet/Chess-AI/c5910012ab15126aca1a211e268fcb350d48df59/Chess/assets/2000px-Chess_Pieces_Sprite_07.png
--------------------------------------------------------------------------------
/Chess/assets/2000px-Chess_Pieces_Sprite_08.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Code-Bullet/Chess-AI/c5910012ab15126aca1a211e268fcb350d48df59/Chess/assets/2000px-Chess_Pieces_Sprite_08.png
--------------------------------------------------------------------------------
/Chess/assets/2000px-Chess_Pieces_Sprite_09.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Code-Bullet/Chess-AI/c5910012ab15126aca1a211e268fcb350d48df59/Chess/assets/2000px-Chess_Pieces_Sprite_09.png
--------------------------------------------------------------------------------
/Chess/assets/2000px-Chess_Pieces_Sprite_10.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Code-Bullet/Chess-AI/c5910012ab15126aca1a211e268fcb350d48df59/Chess/assets/2000px-Chess_Pieces_Sprite_10.png
--------------------------------------------------------------------------------
/Chess/assets/2000px-Chess_Pieces_Sprite_11.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Code-Bullet/Chess-AI/c5910012ab15126aca1a211e268fcb350d48df59/Chess/assets/2000px-Chess_Pieces_Sprite_11.png
--------------------------------------------------------------------------------
/Chess/assets/2000px-Chess_Pieces_Sprite_12.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Code-Bullet/Chess-AI/c5910012ab15126aca1a211e268fcb350d48df59/Chess/assets/2000px-Chess_Pieces_Sprite_12.png
--------------------------------------------------------------------------------
/Chess/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/Chess/libraries/p5.dom.js:
--------------------------------------------------------------------------------
1 | /*! p5.dom.js v0.3.2 March 25, 2017 */
2 | /**
3 | * The web is much more than just canvas and p5.dom makes it easy to interact
4 | * with other HTML5 objects, including text, hyperlink, image, input, video,
5 | * audio, and webcam.
6 | * There is a set of creation methods, DOM manipulation methods, and
7 | * an extended p5.Element that supports a range of HTML elements. See the
8 | *
9 | * beyond the canvas tutorial for a full overview of how this addon works.
10 | *
11 | *
Methods and properties shown in black are part of the p5.js core, items in
12 | * blue are part of the p5.dom library. You will need to include an extra file
13 | * in order to access the blue functions. See the
14 | * using a library
15 | * section for information on how to include this library. p5.dom comes with
16 | * p5 complete or you can download the single file
17 | *
18 | * here.
19 | * See tutorial: beyond the canvas
20 | * for more info on how to use this libary.
21 | *
22 | * @module p5.dom
23 | * @submodule p5.dom
24 | * @for p5.dom
25 | * @main
26 | */
27 |
28 | (function (root, factory) {
29 | if (typeof define === 'function' && define.amd)
30 | define('p5.dom', ['p5'], function (p5) { (factory(p5));});
31 | else if (typeof exports === 'object')
32 | factory(require('../p5'));
33 | else
34 | factory(root['p5']);
35 | }(this, function (p5) {
36 |
37 | // =============================================================================
38 | // p5 additions
39 | // =============================================================================
40 |
41 | /**
42 | * Searches the page for an element with the given ID, class, or tag name (using the '#' or '.'
43 | * prefixes to specify an ID or class respectively, and none for a tag) and returns it as
44 | * a p5.Element. If a class or tag name is given with more than 1 element,
45 | * only the first element will be returned.
46 | * The DOM node itself can be accessed with .elt.
47 | * Returns null if none found. You can also specify a container to search within.
48 | *
49 | * @method select
50 | * @param {String} name id, class, or tag name of element to search for
51 | * @param {String} [container] id, p5.Element, or HTML element to search within
52 | * @return {Object|p5.Element|Null} p5.Element containing node found
53 | * @example
54 | *
55 | * function setup() {
56 | * createCanvas(100,100);
57 | * //translates canvas 50px down
58 | * select('canvas').position(100, 100);
59 | * }
60 | *
61 | *
62 | * // these are all valid calls to select()
63 | * var a = select('#moo');
64 | * var b = select('#blah', '#myContainer');
65 | * var c = select('#foo', b);
66 | * var d = document.getElementById('beep');
67 | * var e = select('p', d);
68 | *
69 | *
70 | */
71 | p5.prototype.select = function (e, p) {
72 | var res = null;
73 | var container = getContainer(p);
74 | if (e[0] === '.'){
75 | e = e.slice(1);
76 | res = container.getElementsByClassName(e);
77 | if (res.length) {
78 | res = res[0];
79 | } else {
80 | res = null;
81 | }
82 | }else if (e[0] === '#'){
83 | e = e.slice(1);
84 | res = container.getElementById(e);
85 | }else {
86 | res = container.getElementsByTagName(e);
87 | if (res.length) {
88 | res = res[0];
89 | } else {
90 | res = null;
91 | }
92 | }
93 | if (res) {
94 | return wrapElement(res);
95 | } else {
96 | return null;
97 | }
98 | };
99 |
100 | /**
101 | * Searches the page for elements with the given class or tag name (using the '.' prefix
102 | * to specify a class and no prefix for a tag) and returns them as p5.Elements
103 | * in an array.
104 | * The DOM node itself can be accessed with .elt.
105 | * Returns an empty array if none found.
106 | * You can also specify a container to search within.
107 | *
108 | * @method selectAll
109 | * @param {String} name class or tag name of elements to search for
110 | * @param {String} [container] id, p5.Element, or HTML element to search within
111 | * @return {Array} Array of p5.Elements containing nodes found
112 | * @example
113 | *
114 | * function setup() {
115 | * createButton('btn');
116 | * createButton('2nd btn');
117 | * createButton('3rd btn');
118 | * var buttons = selectAll('button');
119 | *
120 | * for (var i = 0; i < buttons.length; i++){
121 | * buttons[i].size(100,100);
122 | * }
123 | * }
124 | *
125 | *
126 | * // these are all valid calls to selectAll()
127 | * var a = selectAll('.moo');
128 | * var b = selectAll('div');
129 | * var c = selectAll('button', '#myContainer');
130 | * var d = select('#container');
131 | * var e = selectAll('p', d);
132 | * var f = document.getElementById('beep');
133 | * var g = select('.blah', f);
134 | *
135 | *
136 | */
137 | p5.prototype.selectAll = function (e, p) {
138 | var arr = [];
139 | var res;
140 | var container = getContainer(p);
141 | if (e[0] === '.'){
142 | e = e.slice(1);
143 | res = container.getElementsByClassName(e);
144 | } else {
145 | res = container.getElementsByTagName(e);
146 | }
147 | if (res) {
148 | for (var j = 0; j < res.length; j++) {
149 | var obj = wrapElement(res[j]);
150 | arr.push(obj);
151 | }
152 | }
153 | return arr;
154 | };
155 |
156 | /**
157 | * Helper function for select and selectAll
158 | */
159 | function getContainer(p) {
160 | var container = document;
161 | if (typeof p === 'string' && p[0] === '#'){
162 | p = p.slice(1);
163 | container = document.getElementById(p) || document;
164 | } else if (p instanceof p5.Element){
165 | container = p.elt;
166 | } else if (p instanceof HTMLElement){
167 | container = p;
168 | }
169 | return container;
170 | }
171 |
172 | /**
173 | * Helper function for getElement and getElements.
174 | */
175 | function wrapElement(elt) {
176 | if(elt.tagName === "INPUT" && elt.type === "checkbox") {
177 | var converted = new p5.Element(elt);
178 | converted.checked = function(){
179 | if (arguments.length === 0){
180 | return this.elt.checked;
181 | } else if(arguments[0]) {
182 | this.elt.checked = true;
183 | } else {
184 | this.elt.checked = false;
185 | }
186 | return this;
187 | };
188 | return converted;
189 | } else if (elt.tagName === "VIDEO" || elt.tagName === "AUDIO") {
190 | return new p5.MediaElement(elt);
191 | } else {
192 | return new p5.Element(elt);
193 | }
194 | }
195 |
196 | /**
197 | * Removes all elements created by p5, except any canvas / graphics
198 | * elements created by createCanvas or createGraphics.
199 | * Event handlers are removed, and element is removed from the DOM.
200 | * @method removeElements
201 | * @example
202 | *
203 | * function setup() {
204 | * createCanvas(100, 100);
205 | * createDiv('this is some text');
206 | * createP('this is a paragraph');
207 | * }
208 | * function mousePressed() {
209 | * removeElements(); // this will remove the div and p, not canvas
210 | * }
211 | *
212 | *
213 | */
214 | p5.prototype.removeElements = function (e) {
215 | for (var i=0; i
243 | * var myDiv;
244 | * function setup() {
245 | * myDiv = createDiv('this is some text');
246 | * }
247 | *
248 | */
249 |
250 | /**
251 | * Creates a <p></p> element in the DOM with given inner HTML. Used
252 | * for paragraph length text.
253 | * Appends to the container node if one is specified, otherwise
254 | * appends to body.
255 | *
256 | * @method createP
257 | * @param {String} html inner HTML for element created
258 | * @return {Object|p5.Element} pointer to p5.Element holding created node
259 | * @example
260 | *
261 | * var myP;
262 | * function setup() {
263 | * myP = createP('this is some text');
264 | * }
265 | *
266 | */
267 |
268 | /**
269 | * Creates a <span></span> element in the DOM with given inner HTML.
270 | * Appends to the container node if one is specified, otherwise
271 | * appends to body.
272 | *
273 | * @method createSpan
274 | * @param {String} html inner HTML for element created
275 | * @return {Object|p5.Element} pointer to p5.Element holding created node
276 | * @example
277 | *
278 | * var mySpan;
279 | * function setup() {
280 | * mySpan = createSpan('this is some text');
281 | * }
282 | *
283 | */
284 | var tags = ['div', 'p', 'span'];
285 | tags.forEach(function(tag) {
286 | var method = 'create' + tag.charAt(0).toUpperCase() + tag.slice(1);
287 | p5.prototype[method] = function(html) {
288 | var elt = document.createElement(tag);
289 | elt.innerHTML = typeof html === undefined ? "" : html;
290 | return addElement(elt, this);
291 | }
292 | });
293 |
294 | /**
295 | * Creates an <img> element in the DOM with given src and
296 | * alternate text.
297 | * Appends to the container node if one is specified, otherwise
298 | * appends to body.
299 | *
300 | * @method createImg
301 | * @param {String} src src path or url for image
302 | * @param {String} [alt] alternate text to be used if image does not load
303 | * @param {Function} [successCallback] callback to be called once image data is loaded
304 | * @return {Object|p5.Element} pointer to p5.Element holding created node
305 | * @example
306 | *
307 | * var img;
308 | * function setup() {
309 | * img = createImg('http://p5js.org/img/asterisk-01.png');
310 | * }
311 | *
312 | */
313 | p5.prototype.createImg = function() {
314 | var elt = document.createElement('img');
315 | var args = arguments;
316 | var self;
317 | var setAttrs = function(){
318 | self.width = elt.offsetWidth || elt.width;
319 | self.height = elt.offsetHeight || elt.height;
320 | if (args.length > 1 && typeof args[1] === 'function'){
321 | self.fn = args[1];
322 | self.fn();
323 | }else if (args.length > 1 && typeof args[2] === 'function'){
324 | self.fn = args[2];
325 | self.fn();
326 | }
327 | };
328 | elt.src = args[0];
329 | if (args.length > 1 && typeof args[1] === 'string'){
330 | elt.alt = args[1];
331 | }
332 | elt.onload = function(){
333 | setAttrs();
334 | }
335 | self = addElement(elt, this);
336 | return self;
337 | };
338 |
339 | /**
340 | * Creates an <a></a> element in the DOM for including a hyperlink.
341 | * Appends to the container node if one is specified, otherwise
342 | * appends to body.
343 | *
344 | * @method createA
345 | * @param {String} href url of page to link to
346 | * @param {String} html inner html of link element to display
347 | * @param {String} [target] target where new link should open,
348 | * could be _blank, _self, _parent, _top.
349 | * @return {Object|p5.Element} pointer to p5.Element holding created node
350 | * @example
351 | *
352 | * var myLink;
353 | * function setup() {
354 | * myLink = createA('http://p5js.org/', 'this is a link');
355 | * }
356 | *
357 | */
358 | p5.prototype.createA = function(href, html, target) {
359 | var elt = document.createElement('a');
360 | elt.href = href;
361 | elt.innerHTML = html;
362 | if (target) elt.target = target;
363 | return addElement(elt, this);
364 | };
365 |
366 | /** INPUT **/
367 |
368 |
369 | /**
370 | * Creates a slider <input></input> element in the DOM.
371 | * Use .size() to set the display length of the slider.
372 | * Appends to the container node if one is specified, otherwise
373 | * appends to body.
374 | *
375 | * @method createSlider
376 | * @param {Number} min minimum value of the slider
377 | * @param {Number} max maximum value of the slider
378 | * @param {Number} [value] default value of the slider
379 | * @param {Number} [step] step size for each tick of the slider (if step is set to 0, the slider will move continuously from the minimum to the maximum value)
380 | * @return {Object|p5.Element} pointer to p5.Element holding created node
381 | * @example
382 | *
383 | * var slider;
384 | * function setup() {
385 | * slider = createSlider(0, 255, 100);
386 | * slider.position(10, 10);
387 | * slider.style('width', '80px');
388 | * }
389 | *
390 | * function draw() {
391 | * var val = slider.value();
392 | * background(val);
393 | * }
394 | *
395 | *
396 | *
397 | * var slider;
398 | * function setup() {
399 | * colorMode(HSB);
400 | * slider = createSlider(0, 360, 60, 40);
401 | * slider.position(10, 10);
402 | * slider.style('width', '80px');
403 | * }
404 | *
405 | * function draw() {
406 | * var val = slider.value();
407 | * background(val, 100, 100, 1);
408 | * }
409 | *
410 | */
411 | p5.prototype.createSlider = function(min, max, value, step) {
412 | var elt = document.createElement('input');
413 | elt.type = 'range';
414 | elt.min = min;
415 | elt.max = max;
416 | if (step === 0) {
417 | elt.step = .000000000000000001; // smallest valid step
418 | } else if (step) {
419 | elt.step = step;
420 | }
421 | if (typeof(value) === "number") elt.value = value;
422 | return addElement(elt, this);
423 | };
424 |
425 | /**
426 | * Creates a <button></button> element in the DOM.
427 | * Use .size() to set the display size of the button.
428 | * Use .mousePressed() to specify behavior on press.
429 | * Appends to the container node if one is specified, otherwise
430 | * appends to body.
431 | *
432 | * @method createButton
433 | * @param {String} label label displayed on the button
434 | * @param {String} [value] value of the button
435 | * @return {Object|p5.Element} pointer to p5.Element holding created node
436 | * @example
437 | *
438 | * var button;
439 | * function setup() {
440 | * createCanvas(100, 100);
441 | * background(0);
442 | * button = createButton('click me');
443 | * button.position(19, 19);
444 | * button.mousePressed(changeBG);
445 | * }
446 | *
447 | * function changeBG() {
448 | * var val = random(255);
449 | * background(val);
450 | * }
451 | *
452 | */
453 | p5.prototype.createButton = function(label, value) {
454 | var elt = document.createElement('button');
455 | elt.innerHTML = label;
456 | elt.value = value;
457 | if (value) elt.value = value;
458 | return addElement(elt, this);
459 | };
460 |
461 | /**
462 | * Creates a checkbox <input></input> element in the DOM.
463 | * Calling .checked() on a checkbox returns if it is checked or not
464 | *
465 | * @method createCheckbox
466 | * @param {String} [label] label displayed after checkbox
467 | * @param {boolean} [value] value of the checkbox; checked is true, unchecked is false.Unchecked if no value given
468 | * @return {Object|p5.Element} pointer to p5.Element holding created node
469 | * @example
470 | *
471 | * var checkbox;
472 | *
473 | * function setup() {
474 | * checkbox = createCheckbox('label', false);
475 | * checkbox.changed(myCheckedEvent);
476 | * }
477 | *
478 | * function myCheckedEvent() {
479 | * if (this.checked()) {
480 | * console.log("Checking!");
481 | * } else {
482 | * console.log("Unchecking!");
483 | * }
484 | * }
485 | *
486 | */
487 | p5.prototype.createCheckbox = function() {
488 | var elt = document.createElement('div');
489 | var checkbox = document.createElement('input');
490 | checkbox.type = 'checkbox';
491 | elt.appendChild(checkbox);
492 | //checkbox must be wrapped in p5.Element before label so that label appears after
493 | var self = addElement(elt, this);
494 | self.checked = function(){
495 | var cb = self.elt.getElementsByTagName('input')[0];
496 | if (cb) {
497 | if (arguments.length === 0){
498 | return cb.checked;
499 | }else if(arguments[0]){
500 | cb.checked = true;
501 | }else{
502 | cb.checked = false;
503 | }
504 | }
505 | return self;
506 | };
507 | this.value = function(val){
508 | self.value = val;
509 | return this;
510 | };
511 | if (arguments[0]){
512 | var ran = Math.random().toString(36).slice(2);
513 | var label = document.createElement('label');
514 | checkbox.setAttribute('id', ran);
515 | label.htmlFor = ran;
516 | self.value(arguments[0]);
517 | label.appendChild(document.createTextNode(arguments[0]));
518 | elt.appendChild(label);
519 | }
520 | if (arguments[1]){
521 | checkbox.checked = true;
522 | }
523 | return self;
524 | };
525 |
526 | /**
527 | * Creates a dropdown menu <select></select> element in the DOM.
528 | * @method createSelect
529 | * @param {boolean} [multiple] true if dropdown should support multiple selections
530 | * @return {Object|p5.Element} pointer to p5.Element holding created node
531 | * @example
532 | *
533 | * var sel;
534 | *
535 | * function setup() {
536 | * textAlign(CENTER);
537 | * background(200);
538 | * sel = createSelect();
539 | * sel.position(10, 10);
540 | * sel.option('pear');
541 | * sel.option('kiwi');
542 | * sel.option('grape');
543 | * sel.changed(mySelectEvent);
544 | * }
545 | *
546 | * function mySelectEvent() {
547 | * var item = sel.value();
548 | * background(200);
549 | * text("it's a "+item+"!", 50, 50);
550 | * }
551 | *
552 | */
553 | p5.prototype.createSelect = function(mult) {
554 | var elt = document.createElement('select');
555 | if (mult){
556 | elt.setAttribute('multiple', 'true');
557 | }
558 | var self = addElement(elt, this);
559 | self.option = function(name, value){
560 | var opt = document.createElement('option');
561 | opt.innerHTML = name;
562 | if (arguments.length > 1)
563 | opt.value = value;
564 | else
565 | opt.value = name;
566 | elt.appendChild(opt);
567 | };
568 | self.selected = function(value){
569 | var arr = [];
570 | if (arguments.length > 0){
571 | for (var i = 0; i < this.elt.length; i++){
572 | if (value.toString() === this.elt[i].value){
573 | this.elt.selectedIndex = i;
574 | }
575 | }
576 | return this;
577 | }else{
578 | if (mult){
579 | for (var i = 0; i < this.elt.selectedOptions.length; i++){
580 | arr.push(this.elt.selectedOptions[i].value);
581 | }
582 | return arr;
583 | }else{
584 | return this.elt.value;
585 | }
586 | }
587 | };
588 | return self;
589 | };
590 |
591 | /**
592 | * Creates a radio button <input></input> element in the DOM.
593 | * The .option() method can be used to set options for the radio after it is
594 | * created. The .value() method will return the currently selected option.
595 | *
596 | * @method createRadio
597 | * @param {String} [divId] the id and name of the created div and input field respectively
598 | * @return {Object|p5.Element} pointer to p5.Element holding created node
599 | * @example
600 | *
601 | * var radio;
602 | *
603 | * function setup() {
604 | * radio = createRadio();
605 | * radio.option("black");
606 | * radio.option("white");
607 | * radio.option("gray");
608 | * radio.style('width', '60px');
609 | * textAlign(CENTER);
610 | * fill(255, 0, 0);
611 | * }
612 | *
613 | * function draw() {
614 | * var val = radio.value();
615 | * background(val);
616 | * text(val, width/2, height/2);
617 | * }
618 | *
619 | *
620 | * var radio;
621 | *
622 | * function setup() {
623 | * radio = createRadio();
624 | * radio.option('apple', 1);
625 | * radio.option('bread', 2);
626 | * radio.option('juice', 3);
627 | * radio.style('width', '60px');
628 | * textAlign(CENTER);
629 | * }
630 | *
631 | * function draw() {
632 | * background(200);
633 | * var val = radio.value();
634 | * if (val) {
635 | * text('item cost is $'+val, width/2, height/2);
636 | * }
637 | * }
638 | *
639 | */
640 | p5.prototype.createRadio = function() {
641 | var radios = document.querySelectorAll("input[type=radio]");
642 | var count = 0;
643 | if(radios.length > 1){
644 | var length = radios.length;
645 | var prev=radios[0].name;
646 | var current = radios[1].name;
647 | count = 1;
648 | for(var i = 1; i < length; i++) {
649 | current = radios[i].name;
650 | if(prev != current){
651 | count++;
652 | }
653 | prev = current;
654 | }
655 | }
656 | else if (radios.length == 1){
657 | count = 1;
658 | }
659 | var elt = document.createElement('div');
660 | var self = addElement(elt, this);
661 | var times = -1;
662 | self.option = function(name, value){
663 | var opt = document.createElement('input');
664 | opt.type = 'radio';
665 | opt.innerHTML = name;
666 | if (arguments.length > 1)
667 | opt.value = value;
668 | else
669 | opt.value = name;
670 | opt.setAttribute('name',"defaultradio"+count);
671 | elt.appendChild(opt);
672 | if (name){
673 | times++;
674 | var ran = Math.random().toString(36).slice(2);
675 | var label = document.createElement('label');
676 | opt.setAttribute('id', "defaultradio"+count+"-"+times);
677 | label.htmlFor = "defaultradio"+count+"-"+times;
678 | label.appendChild(document.createTextNode(name));
679 | elt.appendChild(label);
680 | }
681 | return opt;
682 | };
683 | self.selected = function(){
684 | var length = this.elt.childNodes.length;
685 | if(arguments.length == 1) {
686 | for (var i = 0; i < length; i+=2){
687 | if(this.elt.childNodes[i].value == arguments[0])
688 | this.elt.childNodes[i].checked = true;
689 | }
690 | return this;
691 | } else {
692 | for (var i = 0; i < length; i+=2){
693 | if(this.elt.childNodes[i].checked == true)
694 | return this.elt.childNodes[i].value;
695 | }
696 | }
697 | };
698 | self.value = function(){
699 | var length = this.elt.childNodes.length;
700 | if(arguments.length == 1) {
701 | for (var i = 0; i < length; i+=2){
702 | if(this.elt.childNodes[i].value == arguments[0])
703 | this.elt.childNodes[i].checked = true;
704 | }
705 | return this;
706 | } else {
707 | for (var i = 0; i < length; i+=2){
708 | if(this.elt.childNodes[i].checked == true)
709 | return this.elt.childNodes[i].value;
710 | }
711 | return "";
712 | }
713 | };
714 | return self
715 | };
716 |
717 | /**
718 | * Creates an <input></input> element in the DOM for text input.
719 | * Use .size() to set the display length of the box.
720 | * Appends to the container node if one is specified, otherwise
721 | * appends to body.
722 | *
723 | * @method createInput
724 | * @param {Number} [value] default value of the input box
725 | * @param {String} [type] type of text, ie text, password etc. Defaults to text
726 | * @return {Object|p5.Element} pointer to p5.Element holding created node
727 | * @example
728 | *
729 | * function setup(){
730 | * var inp = createInput('');
731 | * inp.input(myInputEvent);
732 | * }
733 | *
734 | * function myInputEvent(){
735 | * console.log('you are typing: ', this.value());
736 | * }
737 | *
738 | *
739 | */
740 | p5.prototype.createInput = function(value, type) {
741 | var elt = document.createElement('input');
742 | elt.type = type ? type : 'text';
743 | if (value) elt.value = value;
744 | return addElement(elt, this);
745 | };
746 |
747 | /**
748 | * Creates an <input></input> element in the DOM of type 'file'.
749 | * This allows users to select local files for use in a sketch.
750 | *
751 | * @method createFileInput
752 | * @param {Function} [callback] callback function for when a file loaded
753 | * @param {String} [multiple] optional to allow multiple files selected
754 | * @return {Object|p5.Element} pointer to p5.Element holding created DOM element
755 | * @example
756 | * var input;
757 | * var img;
758 | *
759 | * function setup() {
760 | * input = createFileInput(handleFile);
761 | * input.position(0, 0);
762 | * }
763 | *
764 | * function draw() {
765 | * if (img) {
766 | * image(img, 0, 0, width, height);
767 | * }
768 | * }
769 | *
770 | * function handleFile(file) {
771 | * print(file);
772 | * if (file.type === 'image') {
773 | * img = createImg(file.data);
774 | * img.hide();
775 | * }
776 | * }
777 | */
778 | p5.prototype.createFileInput = function(callback, multiple) {
779 |
780 | // Is the file stuff supported?
781 | if (window.File && window.FileReader && window.FileList && window.Blob) {
782 | // Yup, we're ok and make an input file selector
783 | var elt = document.createElement('input');
784 | elt.type = 'file';
785 |
786 | // If we get a second argument that evaluates to true
787 | // then we are looking for multiple files
788 | if (multiple) {
789 | // Anything gets the job done
790 | elt.multiple = 'multiple';
791 | }
792 |
793 | // Function to handle when a file is selected
794 | // We're simplifying life and assuming that we always
795 | // want to load every selected file
796 | function handleFileSelect(evt) {
797 | // These are the files
798 | var files = evt.target.files;
799 | // Load each one and trigger a callback
800 | for (var i = 0; i < files.length; i++) {
801 | var f = files[i];
802 | var reader = new FileReader();
803 | function makeLoader(theFile) {
804 | // Making a p5.File object
805 | var p5file = new p5.File(theFile);
806 | return function(e) {
807 | p5file.data = e.target.result;
808 | callback(p5file);
809 | };
810 | };
811 | reader.onload = makeLoader(f);
812 |
813 | // Text or data?
814 | // This should likely be improved
815 | if (f.type.indexOf('text') > -1) {
816 | reader.readAsText(f);
817 | } else {
818 | reader.readAsDataURL(f);
819 | }
820 | }
821 | }
822 |
823 | // Now let's handle when a file was selected
824 | elt.addEventListener('change', handleFileSelect, false);
825 | return addElement(elt, this);
826 | } else {
827 | console.log('The File APIs are not fully supported in this browser. Cannot create element.');
828 | }
829 | };
830 |
831 |
832 | /** VIDEO STUFF **/
833 |
834 | function createMedia(pInst, type, src, callback) {
835 | var elt = document.createElement(type);
836 |
837 | // allow src to be empty
838 | var src = src || '';
839 | if (typeof src === 'string') {
840 | src = [src];
841 | }
842 | for (var i=0; ithis
878 | * page for further information about supported formats.
879 | *
880 | * @method createVideo
881 | * @param {String|Array} src path to a video file, or array of paths for
882 | * supporting different browsers
883 | * @param {Object} [callback] callback function to be called upon
884 | * 'canplaythrough' event fire, that is, when the
885 | * browser can play the media, and estimates that
886 | * enough data has been loaded to play the media
887 | * up to its end without having to stop for
888 | * further buffering of content
889 | * @return {Object|p5.Element} pointer to video p5.Element
890 | */
891 | p5.prototype.createVideo = function(src, callback) {
892 | return createMedia(this, 'video', src, callback);
893 | };
894 |
895 | /** AUDIO STUFF **/
896 |
897 | /**
898 | * Creates a hidden HTML5 <audio> element in the DOM for simple audio
899 | * playback. Appends to the container node if one is specified,
900 | * otherwise appends to body. The first parameter
901 | * can be either a single string path to a audio file, or an array of string
902 | * paths to different formats of the same audio. This is useful for ensuring
903 | * that your audio can play across different browsers, as each supports
904 | * different formats. See this
905 | * page for further information about supported formats.
906 | *
907 | * @method createAudio
908 | * @param {String|Array} src path to an audio file, or array of paths for
909 | * supporting different browsers
910 | * @param {Object} [callback] callback function to be called upon
911 | * 'canplaythrough' event fire, that is, when the
912 | * browser can play the media, and estimates that
913 | * enough data has been loaded to play the media
914 | * up to its end without having to stop for
915 | * further buffering of content
916 | * @return {Object|p5.Element} pointer to audio p5.Element
917 | */
918 | p5.prototype.createAudio = function(src, callback) {
919 | return createMedia(this, 'audio', src, callback);
920 | };
921 |
922 |
923 | /** CAMERA STUFF **/
924 |
925 | p5.prototype.VIDEO = 'video';
926 | p5.prototype.AUDIO = 'audio';
927 |
928 | navigator.getUserMedia = navigator.getUserMedia ||
929 | navigator.webkitGetUserMedia ||
930 | navigator.mozGetUserMedia ||
931 | navigator.msGetUserMedia;
932 |
933 | /**
934 | * Creates a new <video> element that contains the audio/video feed
935 | * from a webcam. This can be drawn onto the canvas using video().
936 | * More specific properties of the feed can be passing in a Constraints object.
937 | * See the
938 | * W3C
939 | * spec for possible properties. Note that not all of these are supported
940 | * by all browsers.
941 | * Security note: A new browser security specification requires that getUserMedia,
942 | * which is behind createCapture(), only works when you're running the code locally,
943 | * or on HTTPS. Learn more here
944 | * and here.
945 | *
946 | * @method createCapture
947 | * @param {String|Constant|Object} type type of capture, either VIDEO or
948 | * AUDIO if none specified, default both,
949 | * or a Constraints object
950 | * @param {Function} callback function to be called once
951 | * stream has loaded
952 | * @return {Object|p5.Element} capture video p5.Element
953 | * @example
954 | *
955 | * var capture;
956 | *
957 | * function setup() {
958 | * createCanvas(480, 120);
959 | * capture = createCapture(VIDEO);
960 | * }
961 | *
962 | * function draw() {
963 | * image(capture, 0, 0, width, width*capture.height/capture.width);
964 | * filter(INVERT);
965 | * }
966 | *
967 | *
968 | * function setup() {
969 | * createCanvas(480, 120);
970 | * var constraints = {
971 | * video: {
972 | * mandatory: {
973 | * minWidth: 1280,
974 | * minHeight: 720
975 | * },
976 | * optional: [
977 | * { maxFrameRate: 10 }
978 | * ]
979 | * },
980 | * audio: true
981 | * };
982 | * createCapture(constraints, function(stream) {
983 | * console.log(stream);
984 | * });
985 | * }
986 | *
987 | */
988 | p5.prototype.createCapture = function() {
989 | var useVideo = true;
990 | var useAudio = true;
991 | var constraints;
992 | var cb;
993 | for (var i=0; i
1049 | * var h2 = createElement('h2','im an h2 p5.element!');
1050 | *
1051 | */
1052 | p5.prototype.createElement = function(tag, content) {
1053 | var elt = document.createElement(tag);
1054 | if (typeof content !== 'undefined') {
1055 | elt.innerHTML = content;
1056 | }
1057 | return addElement(elt, this);
1058 | };
1059 |
1060 |
1061 | // =============================================================================
1062 | // p5.Element additions
1063 | // =============================================================================
1064 | /**
1065 | *
1066 | * Adds specified class to the element.
1067 | *
1068 | * @for p5.Element
1069 | * @method addClass
1070 | * @param {String} class name of class to add
1071 | * @return {Object|p5.Element}
1072 | * @example
1073 | *
1074 | * var div = createDiv('div');
1075 | * div.addClass('myClass');
1076 | *
1077 | */
1078 | p5.Element.prototype.addClass = function(c) {
1079 | if (this.elt.className) {
1080 | // PEND don't add class more than once
1081 | //var regex = new RegExp('[^a-zA-Z\d:]?'+c+'[^a-zA-Z\d:]?');
1082 | //if (this.elt.className.search(/[^a-zA-Z\d:]?hi[^a-zA-Z\d:]?/) === -1) {
1083 | this.elt.className = this.elt.className+' '+c;
1084 | //}
1085 | } else {
1086 | this.elt.className = c;
1087 | }
1088 | return this;
1089 | }
1090 |
1091 | /**
1092 | *
1093 | * Removes specified class from the element.
1094 | *
1095 | * @method removeClass
1096 | * @param {String} class name of class to remove
1097 | * @return {Object|p5.Element}
1098 | */
1099 | p5.Element.prototype.removeClass = function(c) {
1100 | var regex = new RegExp('(?:^|\\s)'+c+'(?!\\S)');
1101 | this.elt.className = this.elt.className.replace(regex, '');
1102 | this.elt.className = this.elt.className.replace(/^\s+|\s+$/g, ""); //prettify (optional)
1103 | return this;
1104 | }
1105 |
1106 | /**
1107 | *
1108 | * Attaches the element as a child to the parent specified.
1109 | * Accepts either a string ID, DOM node, or p5.Element.
1110 | * If no argument is specified, an array of children DOM nodes is returned.
1111 | *
1112 | * @method child
1113 | * @param {String|Object|p5.Element} [child] the ID, DOM node, or p5.Element
1114 | * to add to the current element
1115 | * @return {p5.Element}
1116 | * @example
1117 | *
1118 | * var div0 = createDiv('this is the parent');
1119 | * var div1 = createDiv('this is the child');
1120 | * div0.child(div1); // use p5.Element
1121 | *
1122 | *
1123 | * var div0 = createDiv('this is the parent');
1124 | * var div1 = createDiv('this is the child');
1125 | * div1.id('apples');
1126 | * div0.child('apples'); // use id
1127 | *
1128 | *
1129 | * var div0 = createDiv('this is the parent');
1130 | * var elt = document.getElementById('myChildDiv');
1131 | * div0.child(elt); // use element from page
1132 | *
1133 | */
1134 | p5.Element.prototype.child = function(c) {
1135 | if (typeof c === 'undefined'){
1136 | return this.elt.childNodes
1137 | }
1138 | if (typeof c === 'string') {
1139 | if (c[0] === '#') {
1140 | c = c.substring(1);
1141 | }
1142 | c = document.getElementById(c);
1143 | } else if (c instanceof p5.Element) {
1144 | c = c.elt;
1145 | }
1146 | this.elt.appendChild(c);
1147 | return this;
1148 | };
1149 |
1150 | /**
1151 | * Centers a p5 Element either vertically, horizontally,
1152 | * or both, relative to its parent or according to
1153 | * the body if the Element has no parent. If no argument is passed
1154 | * the Element is aligned both vertically and horizontally.
1155 | *
1156 | * @param {String} align passing 'vertical', 'horizontal' aligns element accordingly
1157 | * @return {Object|p5.Element} pointer to p5.Element
1158 | * @example
1159 | *
1160 | * function setup() {
1161 | * var div = createDiv('').size(10,10);
1162 | * div.style('background-color','orange');
1163 | * div.center();
1164 | *
1165 | * }
1166 | *
1167 | */
1168 | p5.Element.prototype.center = function(align) {
1169 | var style = this.elt.style.display;
1170 | var hidden = this.elt.style.display === 'none';
1171 | var parentHidden = this.parent().style.display === 'none';
1172 | var pos = { x : this.elt.offsetLeft, y : this.elt.offsetTop };
1173 |
1174 | if (hidden) this.show();
1175 |
1176 | this.elt.style.display = 'block';
1177 | this.position(0,0);
1178 |
1179 | if (parentHidden) this.parent().style.display = 'block';
1180 |
1181 | var wOffset = Math.abs(this.parent().offsetWidth - this.elt.offsetWidth);
1182 | var hOffset = Math.abs(this.parent().offsetHeight - this.elt.offsetHeight);
1183 | var y = pos.y;
1184 | var x = pos.x;
1185 |
1186 | if (align === 'both' || align === undefined){
1187 | this.position(wOffset/2, hOffset/2);
1188 | }else if (align === 'horizontal'){
1189 | this.position(wOffset/2, y);
1190 | }else if (align === 'vertical'){
1191 | this.position(x, hOffset/2);
1192 | }
1193 |
1194 | this.style('display', style);
1195 |
1196 | if (hidden) this.hide();
1197 |
1198 | if (parentHidden) this.parent().style.display = 'none';
1199 |
1200 | return this;
1201 | };
1202 |
1203 | /**
1204 | *
1205 | * If an argument is given, sets the inner HTML of the element,
1206 | * replacing any existing html. If true is included as a second
1207 | * argument, html is appended instead of replacing existing html.
1208 | * If no arguments are given, returns
1209 | * the inner HTML of the element.
1210 | *
1211 | * @for p5.Element
1212 | * @method html
1213 | * @param {String} [html] the HTML to be placed inside the element
1214 | * @param {boolean} [append] whether to append HTML to existing
1215 | * @return {Object|p5.Element|String}
1216 | * @example
1217 | *
1218 | * var div = createDiv('').size(100,100);
1219 | * div.html('hi');
1220 | *
1221 | *
1222 | * var div = createDiv('Hello ').size(100,100);
1223 | * div.html('World', true);
1224 | *
1225 | */
1226 | p5.Element.prototype.html = function() {
1227 | if (arguments.length === 0) {
1228 | return this.elt.innerHTML;
1229 | } else if (arguments[1]) {
1230 | this.elt.innerHTML += arguments[0];
1231 | return this;
1232 | } else {
1233 | this.elt.innerHTML = arguments[0];
1234 | return this;
1235 | }
1236 | };
1237 |
1238 | /**
1239 | *
1240 | * Sets the position of the element relative to (0, 0) of the
1241 | * window. Essentially, sets position:absolute and left and top
1242 | * properties of style. If no arguments given returns the x and y position
1243 | * of the element in an object.
1244 | *
1245 | * @method position
1246 | * @param {Number} [x] x-position relative to upper left of window
1247 | * @param {Number} [y] y-position relative to upper left of window
1248 | * @return {Object|p5.Element}
1249 | * @example
1250 | *
1251 | * function setup() {
1252 | * var cnv = createCanvas(100, 100);
1253 | * // positions canvas 50px to the right and 100px
1254 | * // below upper left corner of the window
1255 | * cnv.position(50, 100);
1256 | * }
1257 | *
1258 | */
1259 | p5.Element.prototype.position = function() {
1260 | if (arguments.length === 0){
1261 | return { 'x' : this.elt.offsetLeft , 'y' : this.elt.offsetTop };
1262 | }else{
1263 | this.elt.style.position = 'absolute';
1264 | this.elt.style.left = arguments[0]+'px';
1265 | this.elt.style.top = arguments[1]+'px';
1266 | this.x = arguments[0];
1267 | this.y = arguments[1];
1268 | return this;
1269 | }
1270 | };
1271 |
1272 | /* Helper method called by p5.Element.style() */
1273 | p5.Element.prototype._translate = function(){
1274 | this.elt.style.position = 'absolute';
1275 | // save out initial non-translate transform styling
1276 | var transform = '';
1277 | if (this.elt.style.transform) {
1278 | transform = this.elt.style.transform.replace(/translate3d\(.*\)/g, '');
1279 | transform = transform.replace(/translate[X-Z]?\(.*\)/g, '');
1280 | }
1281 | if (arguments.length === 2) {
1282 | this.elt.style.transform = 'translate('+arguments[0]+'px, '+arguments[1]+'px)';
1283 | } else if (arguments.length > 2) {
1284 | this.elt.style.transform = 'translate3d('+arguments[0]+'px,'+arguments[1]+'px,'+arguments[2]+'px)';
1285 | if (arguments.length === 3) {
1286 | this.elt.parentElement.style.perspective = '1000px';
1287 | } else {
1288 | this.elt.parentElement.style.perspective = arguments[3]+'px';
1289 | }
1290 | }
1291 | // add any extra transform styling back on end
1292 | this.elt.style.transform += transform;
1293 | return this;
1294 | };
1295 |
1296 | /* Helper method called by p5.Element.style() */
1297 | p5.Element.prototype._rotate = function(){
1298 | // save out initial non-rotate transform styling
1299 | var transform = '';
1300 | if (this.elt.style.transform) {
1301 | var transform = this.elt.style.transform.replace(/rotate3d\(.*\)/g, '');
1302 | transform = transform.replace(/rotate[X-Z]?\(.*\)/g, '');
1303 | }
1304 |
1305 | if (arguments.length === 1){
1306 | this.elt.style.transform = 'rotate('+arguments[0]+'deg)';
1307 | }else if (arguments.length === 2){
1308 | this.elt.style.transform = 'rotate('+arguments[0]+'deg, '+arguments[1]+'deg)';
1309 | }else if (arguments.length === 3){
1310 | this.elt.style.transform = 'rotateX('+arguments[0]+'deg)';
1311 | this.elt.style.transform += 'rotateY('+arguments[1]+'deg)';
1312 | this.elt.style.transform += 'rotateZ('+arguments[2]+'deg)';
1313 | }
1314 | // add remaining transform back on
1315 | this.elt.style.transform += transform;
1316 | return this;
1317 | };
1318 |
1319 | /**
1320 | * Sets the given style (css) property (1st arg) of the element with the
1321 | * given value (2nd arg). If a single argument is given, .style()
1322 | * returns the value of the given property; however, if the single argument
1323 | * is given in css syntax ('text-align:center'), .style() sets the css
1324 | * appropriatly. .style() also handles 2d and 3d css transforms. If
1325 | * the 1st arg is 'rotate', 'translate', or 'position', the following arguments
1326 | * accept Numbers as values. ('translate', 10, 100, 50);
1327 | *
1328 | * @method style
1329 | * @param {String} property property to be set
1330 | * @param {String|Number|p5.Color} [value] value to assign to property (only String|Number for rotate/translate)
1331 | * @return {String|Object|p5.Element} value of property, if no value is specified
1332 | * or p5.Element
1333 | * @example
1334 | *
1335 | * var myDiv = createDiv("I like pandas.");
1336 | * myDiv.style("font-size", "18px");
1337 | * myDiv.style("color", "#ff0000");
1338 | *
1339 | *
1340 | * var col = color(25,23,200,50);
1341 | * var button = createButton("button");
1342 | * button.style("background-color", col);
1343 | * button.position(10, 10);
1344 | *
1345 | *
1346 | * var myDiv = createDiv("I like lizards.");
1347 | * myDiv.style("position", 20, 20);
1348 | * myDiv.style("rotate", 45);
1349 | *
1350 | *
1351 | * var myDiv;
1352 | * function setup() {
1353 | * background(200);
1354 | * myDiv = createDiv("I like gray.");
1355 | * myDiv.position(20, 20);
1356 | * }
1357 | *
1358 | * function draw() {
1359 | * myDiv.style("font-size", mouseX+"px");
1360 | * }
1361 | *
1362 | */
1363 | p5.Element.prototype.style = function(prop, val) {
1364 | var self = this;
1365 |
1366 | if (val instanceof p5.Color) {
1367 | val = 'rgba(' + val.levels[0] + ',' + val.levels[1] + ',' + val.levels[2] + ',' + val.levels[3]/255 + ')'
1368 | }
1369 |
1370 | if (typeof val === 'undefined') {
1371 | if (prop.indexOf(':') === -1) {
1372 | var styles = window.getComputedStyle(self.elt);
1373 | var style = styles.getPropertyValue(prop);
1374 | return style;
1375 | } else {
1376 | var attrs = prop.split(';');
1377 | for (var i = 0; i < attrs.length; i++) {
1378 | var parts = attrs[i].split(':');
1379 | if (parts[0] && parts[1]) {
1380 | this.elt.style[parts[0].trim()] = parts[1].trim();
1381 | }
1382 | }
1383 | }
1384 | } else {
1385 | if (prop === 'rotate' || prop === 'translate' || prop === 'position'){
1386 | var trans = Array.prototype.shift.apply(arguments);
1387 | var f = this[trans] || this['_'+trans];
1388 | f.apply(this, arguments);
1389 | } else {
1390 | this.elt.style[prop] = val;
1391 | if (prop === 'width' || prop === 'height' || prop === 'left' || prop === 'top') {
1392 | var numVal = val.replace(/\D+/g, '');
1393 | this[prop] = parseInt(numVal, 10); // pend: is this necessary?
1394 | }
1395 | }
1396 | }
1397 | return this;
1398 | };
1399 |
1400 |
1401 | /**
1402 | *
1403 | * Adds a new attribute or changes the value of an existing attribute
1404 | * on the specified element. If no value is specified, returns the
1405 | * value of the given attribute, or null if attribute is not set.
1406 | *
1407 | * @method attribute
1408 | * @param {String} attr attribute to set
1409 | * @param {String} [value] value to assign to attribute
1410 | * @return {String|Object|p5.Element} value of attribute, if no value is
1411 | * specified or p5.Element
1412 | * @example
1413 | *
1414 | * var myDiv = createDiv("I like pandas.");
1415 | * myDiv.attribute("align", "center");
1416 | *
1417 | */
1418 | p5.Element.prototype.attribute = function(attr, value) {
1419 | if (typeof value === 'undefined') {
1420 | return this.elt.getAttribute(attr);
1421 | } else {
1422 | this.elt.setAttribute(attr, value);
1423 | return this;
1424 | }
1425 | };
1426 |
1427 |
1428 | /**
1429 | *
1430 | * Removes an attribute on the specified element.
1431 | *
1432 | * @method removeAttribute
1433 | * @param {String} attr attribute to remove
1434 | * @return {Object|p5.Element}
1435 | *
1436 | * @example
1437 | *
1438 | * var button;
1439 | * var checkbox;
1440 | *
1441 | * function setup() {
1442 | * checkbox = createCheckbox('enable', true);
1443 | * checkbox.changed(enableButton);
1444 | * button = createButton('button');
1445 | * button.position(10, 10);
1446 | * }
1447 | *
1448 | * function enableButton() {
1449 | * if( this.checked() ) {
1450 | * // Re-enable the button
1451 | * button.removeAttribute('disabled');
1452 | * } else {
1453 | * // Disable the button
1454 | * button.attribute('disabled','');
1455 | * }
1456 | * }
1457 | *
1458 | */
1459 | p5.Element.prototype.removeAttribute = function(attr) {
1460 | this.elt.removeAttribute(attr);
1461 | return this;
1462 | };
1463 |
1464 |
1465 | /**
1466 | * Either returns the value of the element if no arguments
1467 | * given, or sets the value of the element.
1468 | *
1469 | * @method value
1470 | * @param {String|Number} [value]
1471 | * @return {String|Object|p5.Element} value of element if no value is specified or p5.Element
1472 | * @example
1473 | *
1474 | * // gets the value
1475 | * var inp;
1476 | * function setup() {
1477 | * inp = createInput('');
1478 | * }
1479 | *
1480 | * function mousePressed() {
1481 | * print(inp.value());
1482 | * }
1483 | *
1484 | *
1485 | * // sets the value
1486 | * var inp;
1487 | * function setup() {
1488 | * inp = createInput('myValue');
1489 | * }
1490 | *
1491 | * function mousePressed() {
1492 | * inp.value("myValue");
1493 | * }
1494 | *
1495 | */
1496 | p5.Element.prototype.value = function() {
1497 | if (arguments.length > 0) {
1498 | this.elt.value = arguments[0];
1499 | return this;
1500 | } else {
1501 | if (this.elt.type === 'range') {
1502 | return parseFloat(this.elt.value);
1503 | }
1504 | else return this.elt.value;
1505 | }
1506 | };
1507 |
1508 | /**
1509 | *
1510 | * Shows the current element. Essentially, setting display:block for the style.
1511 | *
1512 | * @method show
1513 | * @return {Object|p5.Element}
1514 | * @example
1515 | *
1516 | * var div = createDiv('div');
1517 | * div.style("display", "none");
1518 | * div.show(); // turns display to block
1519 | *
1520 | */
1521 | p5.Element.prototype.show = function() {
1522 | this.elt.style.display = 'block';
1523 | return this;
1524 | };
1525 |
1526 | /**
1527 | * Hides the current element. Essentially, setting display:none for the style.
1528 | *
1529 | * @method hide
1530 | * @return {Object|p5.Element}
1531 | * @example
1532 | *
1533 | * var div = createDiv('this is a div');
1534 | * div.hide();
1535 | *
1536 | */
1537 | p5.Element.prototype.hide = function() {
1538 | this.elt.style.display = 'none';
1539 | return this;
1540 | };
1541 |
1542 | /**
1543 | *
1544 | * Sets the width and height of the element. AUTO can be used to
1545 | * only adjust one dimension. If no arguments given returns the width and height
1546 | * of the element in an object.
1547 | *
1548 | * @method size
1549 | * @param {Number} [w] width of the element
1550 | * @param {Number} [h] height of the element
1551 | * @return {Object|p5.Element}
1552 | * @example
1553 | *
1554 | * var div = createDiv('this is a div');
1555 | * div.size(100, 100);
1556 | *
1557 | */
1558 | p5.Element.prototype.size = function(w, h) {
1559 | if (arguments.length === 0){
1560 | return { 'width' : this.elt.offsetWidth , 'height' : this.elt.offsetHeight };
1561 | }else{
1562 | var aW = w;
1563 | var aH = h;
1564 | var AUTO = p5.prototype.AUTO;
1565 | if (aW !== AUTO || aH !== AUTO) {
1566 | if (aW === AUTO) {
1567 | aW = h * this.width / this.height;
1568 | } else if (aH === AUTO) {
1569 | aH = w * this.height / this.width;
1570 | }
1571 | // set diff for cnv vs normal div
1572 | if (this.elt instanceof HTMLCanvasElement) {
1573 | var j = {};
1574 | var k = this.elt.getContext('2d');
1575 | for (var prop in k) {
1576 | j[prop] = k[prop];
1577 | }
1578 | this.elt.setAttribute('width', aW * this._pInst._pixelDensity);
1579 | this.elt.setAttribute('height', aH * this._pInst._pixelDensity);
1580 | this.elt.setAttribute('style', 'width:' + aW + 'px; height:' + aH + 'px');
1581 | this._pInst.scale(this._pInst._pixelDensity, this._pInst._pixelDensity);
1582 | for (var prop in j) {
1583 | this.elt.getContext('2d')[prop] = j[prop];
1584 | }
1585 | } else {
1586 | this.elt.style.width = aW+'px';
1587 | this.elt.style.height = aH+'px';
1588 | this.elt.width = aW;
1589 | this.elt.height = aH;
1590 | this.width = aW;
1591 | this.height = aH;
1592 | }
1593 |
1594 | this.width = this.elt.offsetWidth;
1595 | this.height = this.elt.offsetHeight;
1596 |
1597 | if (this._pInst) { // main canvas associated with p5 instance
1598 | if (this._pInst._curElement.elt === this.elt) {
1599 | this._pInst._setProperty('width', this.elt.offsetWidth);
1600 | this._pInst._setProperty('height', this.elt.offsetHeight);
1601 | }
1602 | }
1603 | }
1604 | return this;
1605 | }
1606 | };
1607 |
1608 | /**
1609 | * Removes the element and deregisters all listeners.
1610 | * @method remove
1611 | * @example
1612 | *
1613 | * var myDiv = createDiv('this is some text');
1614 | * myDiv.remove();
1615 | *
1616 | */
1617 | p5.Element.prototype.remove = function() {
1618 | // deregister events
1619 | for (var ev in this._events) {
1620 | this.elt.removeEventListener(ev, this._events[ev]);
1621 | }
1622 | if (this.elt.parentNode) {
1623 | this.elt.parentNode.removeChild(this.elt);
1624 | }
1625 | delete(this);
1626 | };
1627 |
1628 |
1629 |
1630 | // =============================================================================
1631 | // p5.MediaElement additions
1632 | // =============================================================================
1633 |
1634 |
1635 | /**
1636 | * Extends p5.Element to handle audio and video. In addition to the methods
1637 | * of p5.Element, it also contains methods for controlling media. It is not
1638 | * called directly, but p5.MediaElements are created by calling createVideo,
1639 | * createAudio, and createCapture.
1640 | *
1641 | * @class p5.MediaElement
1642 | * @constructor
1643 | * @param {String} elt DOM node that is wrapped
1644 | * @param {Object} [pInst] pointer to p5 instance
1645 | */
1646 | p5.MediaElement = function(elt, pInst) {
1647 | p5.Element.call(this, elt, pInst);
1648 |
1649 | var self = this;
1650 | this.elt.crossOrigin = 'anonymous';
1651 |
1652 | this._prevTime = 0;
1653 | this._cueIDCounter = 0;
1654 | this._cues = [];
1655 | this._pixelDensity = 1;
1656 |
1657 | /**
1658 | * Path to the media element source.
1659 | *
1660 | * @property src
1661 | * @return {String} src
1662 | */
1663 | Object.defineProperty(self, 'src', {
1664 | get: function() {
1665 | var firstChildSrc = self.elt.children[0].src;
1666 | var srcVal = self.elt.src === window.location.href ? '' : self.elt.src;
1667 | var ret = firstChildSrc === window.location.href ? srcVal : firstChildSrc;
1668 | return ret;
1669 | },
1670 | set: function(newValue) {
1671 | for (var i = 0; i < self.elt.children.length; i++) {
1672 | self.elt.removeChild(self.elt.children[i]);
1673 | }
1674 | var source = document.createElement('source');
1675 | source.src = newValue;
1676 | elt.appendChild(source);
1677 | self.elt.src = newValue;
1678 | },
1679 | });
1680 |
1681 | // private _onended callback, set by the method: onended(callback)
1682 | self._onended = function() {};
1683 | self.elt.onended = function() {
1684 | self._onended(self);
1685 | }
1686 | };
1687 | p5.MediaElement.prototype = Object.create(p5.Element.prototype);
1688 |
1689 |
1690 |
1691 |
1692 | /**
1693 | * Play an HTML5 media element.
1694 | *
1695 | * @method play
1696 | * @return {Object|p5.Element}
1697 | */
1698 | p5.MediaElement.prototype.play = function() {
1699 | if (this.elt.currentTime === this.elt.duration) {
1700 | this.elt.currentTime = 0;
1701 | }
1702 |
1703 | if (this.elt.readyState > 1) {
1704 | this.elt.play();
1705 | } else {
1706 | // in Chrome, playback cannot resume after being stopped and must reload
1707 | this.elt.load();
1708 | this.elt.play();
1709 | }
1710 | return this;
1711 | };
1712 |
1713 | /**
1714 | * Stops an HTML5 media element (sets current time to zero).
1715 | *
1716 | * @method stop
1717 | * @return {Object|p5.Element}
1718 | */
1719 | p5.MediaElement.prototype.stop = function() {
1720 | this.elt.pause();
1721 | this.elt.currentTime = 0;
1722 | return this;
1723 | };
1724 |
1725 | /**
1726 | * Pauses an HTML5 media element.
1727 | *
1728 | * @method pause
1729 | * @return {Object|p5.Element}
1730 | */
1731 | p5.MediaElement.prototype.pause = function() {
1732 | this.elt.pause();
1733 | return this;
1734 | };
1735 |
1736 | /**
1737 | * Set 'loop' to true for an HTML5 media element, and starts playing.
1738 | *
1739 | * @method loop
1740 | * @return {Object|p5.Element}
1741 | */
1742 | p5.MediaElement.prototype.loop = function() {
1743 | this.elt.setAttribute('loop', true);
1744 | this.play();
1745 | return this;
1746 | };
1747 | /**
1748 | * Set 'loop' to false for an HTML5 media element. Element will stop
1749 | * when it reaches the end.
1750 | *
1751 | * @method noLoop
1752 | * @return {Object|p5.Element}
1753 | */
1754 | p5.MediaElement.prototype.noLoop = function() {
1755 | this.elt.setAttribute('loop', false);
1756 | return this;
1757 | };
1758 |
1759 |
1760 | /**
1761 | * Set HTML5 media element to autoplay or not.
1762 | *
1763 | * @method autoplay
1764 | * @param {Boolean} autoplay whether the element should autoplay
1765 | * @return {Object|p5.Element}
1766 | */
1767 | p5.MediaElement.prototype.autoplay = function(val) {
1768 | this.elt.setAttribute('autoplay', val);
1769 | return this;
1770 | };
1771 |
1772 | /**
1773 | * Sets volume for this HTML5 media element. If no argument is given,
1774 | * returns the current volume.
1775 | *
1776 | * @param {Number} [val] volume between 0.0 and 1.0
1777 | * @return {Number|p5.MediaElement} current volume or p5.MediaElement
1778 | * @method volume
1779 | */
1780 | p5.MediaElement.prototype.volume = function(val) {
1781 | if (typeof val === 'undefined') {
1782 | return this.elt.volume;
1783 | } else {
1784 | this.elt.volume = val;
1785 | }
1786 | };
1787 |
1788 | /**
1789 | * If no arguments are given, returns the current playback speed of the
1790 | * element. The speed parameter sets the speed where 2.0 will play the
1791 | * element twice as fast, 0.5 will play at half the speed, and -1 will play
1792 | * the element in normal speed in reverse.(Note that not all browsers support
1793 | * backward playback and even if they do, playback might not be smooth.)
1794 | *
1795 | * @method speed
1796 | * @param {Number} [speed] speed multiplier for element playback
1797 | * @return {Number|Object|p5.MediaElement} current playback speed or p5.MediaElement
1798 | */
1799 | p5.MediaElement.prototype.speed = function(val) {
1800 | if (typeof val === 'undefined') {
1801 | return this.elt.playbackRate;
1802 | } else {
1803 | this.elt.playbackRate = val;
1804 | }
1805 | };
1806 |
1807 | /**
1808 | * If no arguments are given, returns the current time of the element.
1809 | * If an argument is given the current time of the element is set to it.
1810 | *
1811 | * @method time
1812 | * @param {Number} [time] time to jump to (in seconds)
1813 | * @return {Number|Object|p5.MediaElement} current time (in seconds)
1814 | * or p5.MediaElement
1815 | */
1816 | p5.MediaElement.prototype.time = function(val) {
1817 | if (typeof val === 'undefined') {
1818 | return this.elt.currentTime;
1819 | } else {
1820 | this.elt.currentTime = val;
1821 | }
1822 | };
1823 |
1824 | /**
1825 | * Returns the duration of the HTML5 media element.
1826 | *
1827 | * @method duration
1828 | * @return {Number} duration
1829 | */
1830 | p5.MediaElement.prototype.duration = function() {
1831 | return this.elt.duration;
1832 | };
1833 | p5.MediaElement.prototype.pixels = [];
1834 | p5.MediaElement.prototype.loadPixels = function() {
1835 | if (!this.canvas) {
1836 | this.canvas = document.createElement('canvas');
1837 | this.drawingContext = this.canvas.getContext('2d');
1838 | }
1839 | if (this.loadedmetadata) { // wait for metadata for w/h
1840 | if (this.canvas.width !== this.elt.width) {
1841 | this.canvas.width = this.elt.width;
1842 | this.canvas.height = this.elt.height;
1843 | this.width = this.canvas.width;
1844 | this.height = this.canvas.height;
1845 | }
1846 | this.drawingContext.drawImage(this.elt, 0, 0, this.canvas.width, this.canvas.height);
1847 | p5.Renderer2D.prototype.loadPixels.call(this);
1848 | }
1849 | return this;
1850 | }
1851 | p5.MediaElement.prototype.updatePixels = function(x, y, w, h){
1852 | if (this.loadedmetadata) { // wait for metadata
1853 | p5.Renderer2D.prototype.updatePixels.call(this, x, y, w, h);
1854 | }
1855 | return this;
1856 | }
1857 | p5.MediaElement.prototype.get = function(x, y, w, h){
1858 | if (this.loadedmetadata) { // wait for metadata
1859 | return p5.Renderer2D.prototype.get.call(this, x, y, w, h);
1860 | } else if (typeof x === 'undefined') {
1861 | return new p5.Image(1, 1);
1862 | } else if (w > 1) {
1863 | return new p5.Image(x, y, w, h);
1864 | } else {
1865 | return [0, 0, 0, 255];
1866 | }
1867 | };
1868 | p5.MediaElement.prototype.set = function(x, y, imgOrCol){
1869 | if (this.loadedmetadata) { // wait for metadata
1870 | p5.Renderer2D.prototype.set.call(this, x, y, imgOrCol);
1871 | }
1872 | };
1873 | p5.MediaElement.prototype.copy = function(){
1874 | p5.Renderer2D.prototype.copy.apply(this, arguments);
1875 | };
1876 | p5.MediaElement.prototype.mask = function(){
1877 | this.loadPixels();
1878 | p5.Image.prototype.mask.apply(this, arguments);
1879 | };
1880 | /**
1881 | * Schedule an event to be called when the audio or video
1882 | * element reaches the end. If the element is looping,
1883 | * this will not be called. The element is passed in
1884 | * as the argument to the onended callback.
1885 | *
1886 | * @method onended
1887 | * @param {Function} callback function to call when the
1888 | * soundfile has ended. The
1889 | * media element will be passed
1890 | * in as the argument to the
1891 | * callback.
1892 | * @return {Object|p5.MediaElement}
1893 | * @example
1894 | *
1895 | * function setup() {
1896 | * audioEl = createAudio('assets/beat.mp3');
1897 | * audioEl.showControls(true);
1898 | * audioEl.onended(sayDone);
1899 | * }
1900 | *
1901 | * function sayDone(elt) {
1902 | * alert('done playing ' + elt.src );
1903 | * }
1904 | *
1905 | */
1906 | p5.MediaElement.prototype.onended = function(callback) {
1907 | this._onended = callback;
1908 | return this;
1909 | };
1910 |
1911 |
1912 | /*** CONNECT TO WEB AUDIO API / p5.sound.js ***/
1913 |
1914 | /**
1915 | * Send the audio output of this element to a specified audioNode or
1916 | * p5.sound object. If no element is provided, connects to p5's master
1917 | * output. That connection is established when this method is first called.
1918 | * All connections are removed by the .disconnect() method.
1919 | *
1920 | * This method is meant to be used with the p5.sound.js addon library.
1921 | *
1922 | * @method connect
1923 | * @param {AudioNode|p5.sound object} audioNode AudioNode from the Web Audio API,
1924 | * or an object from the p5.sound library
1925 | */
1926 | p5.MediaElement.prototype.connect = function(obj) {
1927 | var audioContext, masterOutput;
1928 |
1929 | // if p5.sound exists, same audio context
1930 | if (typeof p5.prototype.getAudioContext === 'function') {
1931 | audioContext = p5.prototype.getAudioContext();
1932 | masterOutput = p5.soundOut.input;
1933 | } else {
1934 | try {
1935 | audioContext = obj.context;
1936 | masterOutput = audioContext.destination
1937 | } catch(e) {
1938 | throw 'connect() is meant to be used with Web Audio API or p5.sound.js'
1939 | }
1940 | }
1941 |
1942 | // create a Web Audio MediaElementAudioSourceNode if none already exists
1943 | if (!this.audioSourceNode) {
1944 | this.audioSourceNode = audioContext.createMediaElementSource(this.elt);
1945 |
1946 | // connect to master output when this method is first called
1947 | this.audioSourceNode.connect(masterOutput);
1948 | }
1949 |
1950 | // connect to object if provided
1951 | if (obj) {
1952 | if (obj.input) {
1953 | this.audioSourceNode.connect(obj.input);
1954 | } else {
1955 | this.audioSourceNode.connect(obj);
1956 | }
1957 | }
1958 |
1959 | // otherwise connect to master output of p5.sound / AudioContext
1960 | else {
1961 | this.audioSourceNode.connect(masterOutput);
1962 | }
1963 |
1964 | };
1965 |
1966 | /**
1967 | * Disconnect all Web Audio routing, including to master output.
1968 | * This is useful if you want to re-route the output through
1969 | * audio effects, for example.
1970 | *
1971 | * @method disconnect
1972 | */
1973 | p5.MediaElement.prototype.disconnect = function() {
1974 | if (this.audioSourceNode) {
1975 | this.audioSourceNode.disconnect();
1976 | } else {
1977 | throw 'nothing to disconnect';
1978 | }
1979 | };
1980 |
1981 |
1982 | /*** SHOW / HIDE CONTROLS ***/
1983 |
1984 | /**
1985 | * Show the default MediaElement controls, as determined by the web browser.
1986 | *
1987 | * @method showControls
1988 | */
1989 | p5.MediaElement.prototype.showControls = function() {
1990 | // must set style for the element to show on the page
1991 | this.elt.style['text-align'] = 'inherit';
1992 | this.elt.controls = true;
1993 | };
1994 |
1995 | /**
1996 | * Hide the default mediaElement controls.
1997 | *
1998 | * @method hideControls
1999 | */
2000 | p5.MediaElement.prototype.hideControls = function() {
2001 | this.elt.controls = false;
2002 | };
2003 |
2004 | /*** SCHEDULE EVENTS ***/
2005 |
2006 | /**
2007 | * Schedule events to trigger every time a MediaElement
2008 | * (audio/video) reaches a playback cue point.
2009 | *
2010 | * Accepts a callback function, a time (in seconds) at which to trigger
2011 | * the callback, and an optional parameter for the callback.
2012 | *
2013 | * Time will be passed as the first parameter to the callback function,
2014 | * and param will be the second parameter.
2015 | *
2016 | *
2017 | * @method addCue
2018 | * @param {Number} time Time in seconds, relative to this media
2019 | * element's playback. For example, to trigger
2020 | * an event every time playback reaches two
2021 | * seconds, pass in the number 2. This will be
2022 | * passed as the first parameter to
2023 | * the callback function.
2024 | * @param {Function} callback Name of a function that will be
2025 | * called at the given time. The callback will
2026 | * receive time and (optionally) param as its
2027 | * two parameters.
2028 | * @param {Object} [value] An object to be passed as the
2029 | * second parameter to the
2030 | * callback function.
2031 | * @return {Number} id ID of this cue,
2032 | * useful for removeCue(id)
2033 | * @example
2034 | *
2035 | * function setup() {
2036 | * background(255,255,255);
2037 | *
2038 | * audioEl = createAudio('assets/beat.mp3');
2039 | * audioEl.showControls();
2040 | *
2041 | * // schedule three calls to changeBackground
2042 | * audioEl.addCue(0.5, changeBackground, color(255,0,0) );
2043 | * audioEl.addCue(1.0, changeBackground, color(0,255,0) );
2044 | * audioEl.addCue(2.5, changeBackground, color(0,0,255) );
2045 | * audioEl.addCue(3.0, changeBackground, color(0,255,255) );
2046 | * audioEl.addCue(4.2, changeBackground, color(255,255,0) );
2047 | * audioEl.addCue(5.0, changeBackground, color(255,255,0) );
2048 | * }
2049 | *
2050 | * function changeBackground(val) {
2051 | * background(val);
2052 | * }
2053 | *
2054 | */
2055 | p5.MediaElement.prototype.addCue = function(time, callback, val) {
2056 | var id = this._cueIDCounter++;
2057 |
2058 | var cue = new Cue(callback, time, id, val);
2059 | this._cues.push(cue);
2060 |
2061 | if (!this.elt.ontimeupdate) {
2062 | this.elt.ontimeupdate = this._onTimeUpdate.bind(this);
2063 | }
2064 |
2065 | return id;
2066 | };
2067 |
2068 | /**
2069 | * Remove a callback based on its ID. The ID is returned by the
2070 | * addCue method.
2071 | *
2072 | * @method removeCue
2073 | * @param {Number} id ID of the cue, as returned by addCue
2074 | */
2075 | p5.MediaElement.prototype.removeCue = function(id) {
2076 | for (var i = 0; i < this._cues.length; i++) {
2077 | if (this._cues[i] === id) {
2078 | console.log(id)
2079 | this._cues.splice(i, 1);
2080 | }
2081 | }
2082 |
2083 | if (this._cues.length === 0) {
2084 | this.elt.ontimeupdate = null
2085 | }
2086 | };
2087 |
2088 | /**
2089 | * Remove all of the callbacks that had originally been scheduled
2090 | * via the addCue method.
2091 | *
2092 | * @method clearCues
2093 | */
2094 | p5.MediaElement.prototype.clearCues = function() {
2095 | this._cues = [];
2096 | this.elt.ontimeupdate = null;
2097 | };
2098 |
2099 | // private method that checks for cues to be fired if events
2100 | // have been scheduled using addCue(callback, time).
2101 | p5.MediaElement.prototype._onTimeUpdate = function() {
2102 | var playbackTime = this.time();
2103 |
2104 | for (var i = 0 ; i < this._cues.length; i++) {
2105 | var callbackTime = this._cues[i].time;
2106 | var val = this._cues[i].val;
2107 |
2108 |
2109 | if (this._prevTime < callbackTime && callbackTime <= playbackTime) {
2110 |
2111 | // pass the scheduled callbackTime as parameter to the callback
2112 | this._cues[i].callback(val);
2113 | }
2114 |
2115 | }
2116 |
2117 | this._prevTime = playbackTime;
2118 | };
2119 |
2120 |
2121 | // Cue inspired by JavaScript setTimeout, and the
2122 | // Tone.js Transport Timeline Event, MIT License Yotam Mann 2015 tonejs.org
2123 | var Cue = function(callback, time, id, val) {
2124 | this.callback = callback;
2125 | this.time = time;
2126 | this.id = id;
2127 | this.val = val;
2128 | };
2129 |
2130 | // =============================================================================
2131 | // p5.File
2132 | // =============================================================================
2133 |
2134 |
2135 | /**
2136 | * Base class for a file
2137 | * Using this for createFileInput
2138 | *
2139 | * @class p5.File
2140 | * @constructor
2141 | * @param {File} file File that is wrapped
2142 | * @param {Object} [pInst] pointer to p5 instance
2143 | */
2144 | p5.File = function(file, pInst) {
2145 | /**
2146 | * Underlying File object. All normal File methods can be called on this.
2147 | *
2148 | * @property file
2149 | */
2150 | this.file = file;
2151 |
2152 | this._pInst = pInst;
2153 |
2154 | // Splitting out the file type into two components
2155 | // This makes determining if image or text etc simpler
2156 | var typeList = file.type.split('/');
2157 | /**
2158 | * File type (image, text, etc.)
2159 | *
2160 | * @property type
2161 | */
2162 | this.type = typeList[0];
2163 | /**
2164 | * File subtype (usually the file extension jpg, png, xml, etc.)
2165 | *
2166 | * @property subtype
2167 | */
2168 | this.subtype = typeList[1];
2169 | /**
2170 | * File name
2171 | *
2172 | * @property name
2173 | */
2174 | this.name = file.name;
2175 | /**
2176 | * File size
2177 | *
2178 | * @property size
2179 | */
2180 | this.size = file.size;
2181 |
2182 | /**
2183 | * URL string containing image data.
2184 | *
2185 | * @property data
2186 | */
2187 | this.data = undefined;
2188 | };
2189 |
2190 | }));
2191 |
--------------------------------------------------------------------------------
/Chess/sketch.js:
--------------------------------------------------------------------------------
1 | var test;
2 | var moving = false;
3 |
4 | var tileSize = 100;
5 | var movingPiece;
6 | var whitesMove = true;
7 | var moveCounter = 10;
8 | var images = [];
9 | var whiteAI = false;
10 | var blackAI = true;
11 |
12 | var depthPara;
13 | var depthPlus;
14 | var depthMinus;
15 | var tempMaxDepth = 3;
16 |
17 | function setup() {
18 | createCanvas(800, 800);
19 | htmlStuff();
20 |
21 | for (var i = 1; i < 10; i++) {
22 | images.push(loadImage("assets/2000px-Chess_Pieces_Sprite_0" + i + ".png"));
23 | }
24 | for (var i = 10; i < 13; i++) {
25 | images.push(loadImage("assets/2000px-Chess_Pieces_Sprite_" + i + ".png"));
26 | }
27 | test = new Board();
28 | }
29 |
30 | function draw() {
31 |
32 | background(100);
33 | showGrid();
34 | test.show();
35 |
36 | runAIs();
37 |
38 | }
39 |
40 | function runAIs() {
41 | maxDepth = tempMaxDepth;
42 | if (!test.isDead() && !test.hasWon()) {
43 | if (blackAI) {
44 | if (!whitesMove) {
45 | if (moveCounter < 0) {
46 | test = maxFunAB(test, -400, 400, 0);
47 | // test = maxFun(test, 0);
48 | print(test);
49 | whitesMove = true;
50 | moveCounter = 10;
51 | } else {
52 | moveCounter--;
53 | }
54 | }
55 | }
56 | if (whiteAI) {
57 | if (whitesMove) {
58 | if (moveCounter < 0) {
59 | test = minFunAB(test, -400, 400, 0);
60 | // test = minFun(test, 0);
61 |
62 | print("test", test);
63 |
64 | whitesMove = false;
65 | moveCounter = 10;
66 | } else {
67 | moveCounter--;
68 | }
69 | }
70 | }
71 | }
72 | }
73 |
74 | function showGrid() {
75 | for (var i = 0; i < 8; i++) {
76 | for (var j = 0; j < 8; j++) {
77 | if ((i + j) % 2 == 1) {
78 | fill(0);
79 | } else {
80 | fill(240);
81 | }
82 | noStroke();
83 | rect(i * tileSize, j * tileSize, tileSize, tileSize);
84 |
85 | }
86 | }
87 |
88 |
89 | }
90 |
91 | function keyPressed() {
92 |
93 | }
94 |
95 | function mousePressed() {
96 | var x = floor(mouseX / tileSize);
97 | var y = floor(mouseY / tileSize);
98 | if (!test.isDone()) {
99 | if (!moving) {
100 | movingPiece = test.getPieceAt(x, y);
101 | if (movingPiece != null && movingPiece.white == whitesMove) {
102 |
103 | movingPiece.movingThisPiece = true;
104 | } else {
105 | return;
106 | }
107 | } else {
108 | if (movingPiece.canMove(x, y, test)) {
109 | movingPiece.move(x, y, test);
110 | movingPiece.movingThisPiece = false;
111 | whitesMove = !whitesMove;
112 | } else {
113 | movingPiece.movingThisPiece = false;
114 |
115 | }
116 | }
117 | moving = !moving;
118 | }
119 | }
120 | //---------------------------------------------------------------------------------------------------------------------
121 | function htmlStuff() {
122 | createP(
123 | ""
124 | )
125 | depthPara = createDiv("Thinking " + maxDepth + " moves ahead");
126 | depthMinus = createButton("-");
127 | depthPlus = createButton('+');
128 |
129 | depthPlus.mousePressed(plusDepth);
130 | depthMinus.mousePressed(minusDepth);
131 |
132 | }
133 |
134 | function minusDepth() {
135 | if (tempMaxDepth > 1) {
136 | tempMaxDepth -= 1;
137 | depthPara.html("Thinking " + tempMaxDepth + " moves ahead");
138 | }
139 | }
140 |
141 | function plusDepth() {
142 | if (tempMaxDepth < 5) {
143 | tempMaxDepth += 1;
144 | depthPara.html("Thinking " + tempMaxDepth + " moves ahead");
145 | }
146 | }
147 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Chess-AI
2 | Using minimax i created a chess AI
3 |
--------------------------------------------------------------------------------