Skip to content

Commit 94e89df

Browse files
committed
initial commit
0 parents  commit 94e89df

File tree

16 files changed

+9749
-0
lines changed

16 files changed

+9749
-0
lines changed

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
node_modules/
2+
public/*.js

Dockerfile

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
FROM nginx:1.17
2+
COPY . /usr/share/nginx/html

LICENSE

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
MIT License
2+
3+
Copyright (c) 2019 The GitHub Training Team
4+
5+
Permission is hereby granted, free of charge, to any person obtaining a copy
6+
of this software and associated documentation files (the "Software"), to deal
7+
in the Software without restriction, including without limitation the rights
8+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
copies of the Software, and to permit persons to whom the Software is
10+
furnished to do so, subject to the following conditions:
11+
12+
The above copyright notice and this permission notice shall be included in all
13+
copies or substantial portions of the Software.
14+
15+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21+
SOFTWARE.

README.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
# Tic Tac Toe Game
2+
3+
Learn GitHub Actions through a fun little game.
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
// Jest Snapshot v1, https://goo.gl/fbAQLP
2+
3+
exports[`App Contains the compiled JavaScript 1`] = `"!function(e){var t={};function n(r){if(t[r])return t[r].exports;var l=t[r]={i:r,l:!1,exports:{}};return e[r].call(l.exports,l,l.exports,n),l.l=!0,l.exports}n.m=e,n.c=t,n.d=function(e,t,r){n.o(e,t)||Object.defineProperty(e,t,{enumerable:!0,get:r})},n.r=function(e){\\"undefined\\"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:\\"Module\\"}),Object.defineProperty(e,\\"__esModule\\",{value:!0})},n.t=function(e,t){if(1&t&&(e=n(e)),8&t)return e;if(4&t&&\\"object\\"==typeof e&&e&&e.__esModule)return e;var r=Object.create(null);if(n.r(r),Object.defineProperty(r,\\"default\\",{enumerable:!0,value:e}),2&t&&\\"string\\"!=typeof e)for(var l in e)n.d(r,l,function(t){return e[t]}.bind(null,l));return r},n.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return n.d(t,\\"a\\",t),t},n.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},n.p=\\"\\",n(n.s=1)}([function(e,t,n){\\"use strict\\";n.r(t),n.d(t,\\"default\\",(function(){return r}));class r{constructor(e,t){this.p1=e,this.p2=t,this.board=[[null,null,null],[null,null,null],[null,null,null]],this.player=Math.random()<.5?this.p1:this.p2,this.sym=\\"X\\"}turn(e,t){t=t||e,this.board[e][t]=this.sym}nextPlayer(){this.player=this.player===this.p1?this.p2:this.p1,this.sym=\\"X\\"===this.sym?\\"O\\":\\"X\\"}hasWinner(){return this.rowWin()||this.colWin()||this.diagWin()}rowWin(){let e=!1;for(let t=0;t<3;t++){const n=this.board[t];null!==n[0]&&(e=e||n[0]===n[1]&&n[0]===n[2])}return e}colWin(){let e=!1;for(let t=0;t<3;t++){const n=this.board;null!==n[0][t]&&(e=e||n[0][t]===n[1][t]&&n[0][t]===n[2][t])}return e}diagWin(){const e=this.board;return null!==e[0][0]&&e[0][0]===e[1][1]&&e[0][0]===e[2][2]||null!==e[0][2]&&e[0][2]===e[1][1]&&e[0][2]===e[2][0]}}},function(e,t,n){n(2),e.exports=n(0)},function(e,t,n){\\"use strict\\";n.r(t);var r=n(0);let l,o;for(;!l;)l=window.prompt(\\"Enter player 1 name:\\");for(;!o&&l!==o;)o=window.prompt(l===o?\`Please enter a different name than \${l}.\`:\\"Enter player 2 name:\\");window.onload=()=>{document.getElementById(\\"p1Name\\").innerText=l,document.getElementById(\\"p2Name\\").innerText=o;let e=0,t=0;!function n(l,o){document.getElementById(\\"win\\").style.display=\\"none\\",document.getElementById(\\"turn\\").style.display=\\"inline\\",document.getElementById(\\"p1Score\\").innerText=e,document.getElementById(\\"p2Score\\").innerText=t;const i=new r.default(l,o),u=document.getElementById(\\"player\\");u.innerText=i.player,document.querySelectorAll(\\"#tictactoe td\\").forEach(r=>{r.innerText=\\"\\",r.onclick=c=>{r.onclick=void 0,c.target.innerText=i.sym,c.target.onclick=void 0;const[d,a]=c.target.classList;i.turn(d,a),i.hasWinner()?(document.getElementById(\\"winner\\").innerText=i.player,document.getElementById(\\"win\\").style.display=\\"inline\\",document.getElementById(\\"turn\\").style.display=\\"none\\",i.player===l?document.getElementById(\\"p1Score\\").innerText=++e:document.getElementById(\\"p2Score\\").innerText=++t,document.getElementById(\\"newGame\\").style.display=\\"inline\\",document.getElementById(\\"newGame\\").onclick=()=>n(l,o),document.querySelectorAll(\\"td\\").forEach(e=>{e.onclick=void 0})):(i.nextPlayer(),u.innerText=i.player)}})}(l,o)}}]);"`;

__test__/game.test.js

Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
const Game = require('../src/game').default
2+
const fs = require('fs')
3+
4+
describe('App', () => {
5+
it('Contains the compiled JavaScript', async (done) => {
6+
fs.readFile('./public/main.js', 'utf8', (err, data) => {
7+
expect(err).toBe(null)
8+
expect(data).toMatchSnapshot()
9+
done()
10+
})
11+
})
12+
})
13+
14+
describe('Game', () => {
15+
let game, p1, p2
16+
beforeEach(() => {
17+
p1 = 'Salem'
18+
p2 = 'Nate'
19+
game = new Game(p1, p2)
20+
})
21+
22+
describe('Game', () => {
23+
it('Initializes with two players', async () => {
24+
expect(game.p1).toBe('Salem')
25+
expect(game.p2).toBe('Nate')
26+
})
27+
28+
it('Initializes with an empty board', async () => {
29+
for (let r = 0; r < game.board.length; r++) {
30+
for (let c = 0; c < game.board[r].lenght; c++) {
31+
expect(game.board[r][c]).toBeUndefined()
32+
}
33+
}
34+
})
35+
36+
it('Starts the game with a random player', async () => {
37+
Math.random = () => 0.4
38+
expect(new Game(p1, p2).player).toBe('Salem')
39+
40+
Math.random = () => 0.6
41+
expect(new Game(p1, p2).player).toBe('Nate')
42+
})
43+
})
44+
45+
describe('turn', () => {
46+
it("Inserts an 'X' into the top center", async () => {
47+
game.turn(0, 1)
48+
expect(game.board[0][1]).toBe('X')
49+
})
50+
51+
it("Inserts an 'X' into the top left", async () => {
52+
game.turn(0)
53+
expect(game.board[0][0]).toBe('X')
54+
})
55+
})
56+
57+
describe('nextPlayer', () => {
58+
it('Sets the current player to be whoever it is not', async () => {
59+
Math.random = () => 0.4
60+
const game = new Game(p1, p2)
61+
expect(game.player).toBe('Salem')
62+
game.nextPlayer()
63+
expect(game.player).toBe('Nate')
64+
})
65+
})
66+
67+
describe('hasWinner', () => {
68+
it('Wins if any row is filled', async () => {
69+
for (let r = 0; r < game.board.length; r++) {
70+
for (let c = 0; c < game.board[r].length; c++) {
71+
game.board[r][c] = 'X'
72+
}
73+
expect(game.hasWinner()).toBe(true)
74+
75+
for (let c = 0; c < game.board[r].length; c++) {
76+
game.board[r][c] = null
77+
}
78+
}
79+
})
80+
81+
it('Wins if any column is filled', async () => {
82+
for (let r = 0; r < game.board.length; r++) {
83+
for (let c = 0; c < game.board[r].length; c++) {
84+
game.board[c][r] = 'X'
85+
}
86+
expect(game.hasWinner()).toBe(true)
87+
88+
for (let c = 0; c < game.board[r].length; c++) {
89+
game.board[c][r] = null
90+
}
91+
}
92+
})
93+
94+
it('Wins if down-left diagonal is filled', async () => {
95+
for (let r = 0; r < game.board.length; r++) {
96+
game.board[r][r] = 'X'
97+
}
98+
expect(game.hasWinner()).toBe(true)
99+
})
100+
101+
it('Wins if up-right diagonal is filled', async () => {
102+
for (let r = 0; r < game.board.length; r++) {
103+
game.board[2 - r][r] = 'X'
104+
}
105+
expect(game.hasWinner()).toBe(true)
106+
})
107+
})
108+
})

automation.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
The team would like:
2+
- [ ] branch protections
3+
- [ ] required review approvals
4+
- [ ] easy way to see when enough approvals has been achieved
5+
- [ ] matrix build
6+
- [ ] save build artifacts
7+
- [ ] dedicated test job

babel.config.js

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
module.exports = {
2+
presets: [
3+
[
4+
'@babel/preset-env',
5+
{
6+
targets: {
7+
node: 'current'
8+
}
9+
}
10+
]
11+
]
12+
}

handler.js

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
const fs = require('fs')
2+
const path = require('path')
3+
4+
const files = {
5+
'/public/index.css': {
6+
content: fs.readFileSync(path.join(__dirname, 'public', 'index.css'), 'utf8'),
7+
type: 'text/css'
8+
},
9+
'/public/main.js': {
10+
content: fs.readFileSync(path.join(__dirname, 'public', 'main.js'), 'utf8'),
11+
type: 'text/javascript'
12+
},
13+
'/': {
14+
content: fs.readFileSync(path.join(__dirname, 'index.html'), 'utf8'),
15+
type: 'text/html'
16+
}
17+
}
18+
19+
/**
20+
*
21+
* Event doc: https://docs.aws.amazon.com/apigateway/latest/developerguide/set-up-lambda-proxy-integrations.html#api-gateway-simple-proxy-for-lambda-input-format
22+
* @param {Object} event - API Gateway Lambda Proxy Input Format
23+
*
24+
* Context doc: https://docs.aws.amazon.com/lambda/latest/dg/nodejs-prog-model-context.html
25+
* @param {Object} context
26+
*
27+
* Return doc: https://docs.aws.amazon.com/apigateway/latest/developerguide/set-up-lambda-proxy-integrations.html
28+
* @returns {Object} object - API Gateway Lambda Proxy Output Format
29+
*
30+
*/
31+
exports.lambdaHandler = async (event, context) => {
32+
// This will either be /, /public/index.css, or /public/main.js
33+
const requestPath = event.path
34+
const { content, type } = files[requestPath]
35+
36+
return {
37+
headers: { 'content-type': type },
38+
statusCode: 200,
39+
body: content
40+
}
41+
}

index.html

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
<!DOCTYPE html>
2+
<html lang="en">
3+
<head>
4+
<meta charset="utf-8">
5+
<meta http-equiv="X-UA-Compatible" content="IE=edge">
6+
<meta name="viewport" content="width=device-width, initial-scale=1">
7+
<title>TicTacToe</title>
8+
9+
<link href="public/index.css" type="text/css" rel="stylesheet" />
10+
<script src="public/main.js"></script>
11+
</head>
12+
<body>
13+
<div id="app">
14+
<div>
15+
<h2 id="turn">It's <span id="player"></span>'s turn!</h2>
16+
<h2 id="win">
17+
<span id="winner"></span> wins!
18+
<button id="newGame">Play again?</button>
19+
</h2>
20+
</div>
21+
<div id="game">
22+
<table id="tictactoe">
23+
<tr"0">
24+
<td class="0 0"></td>
25+
<td class="0 1"></td>
26+
<td class="0 2"></td>
27+
</tr>
28+
<tr>
29+
<td class="1 0"></td>
30+
<td class="1 1"></td>
31+
<td class="1 2"></td>
32+
</tr>
33+
<tr>
34+
<td class="2 0"></td>
35+
<td class="2 1"></td>
36+
<td class="2 2"></td>
37+
</tr>
38+
</table>
39+
<div id="score">
40+
<h2>Score</h2>
41+
<table>
42+
<thead>
43+
<tr>
44+
<th id="p1Name"></th>
45+
<th id="p2Name"></th>
46+
</tr>
47+
</thead>
48+
<tbody>
49+
<tr>
50+
<td id="p1Score">0</td>
51+
<td id="p2Score">0</td>
52+
</tr>
53+
</tbody>
54+
</table>
55+
</div>
56+
</div>
57+
</div>
58+
</body>
59+
</html>

0 commit comments

Comments
 (0)