fuzzyworld

dao-game / commit

Merge branch 'first-commit' into 'main'

dc31cbf2c34bba40bba6baa273b73291c490c776 · Pavel S · 2022-02-26 21:13:39 +0000 · parents dbee555d9bee 0b6fe8283922

Merge branch 'first-commit' into 'main'

Initial commit:

See merge request fuzzy-rp/dao-game!1
 .vscode/launch.json |  15 ++++
 game.js             | 153 +++++++++++++++++++++++++++++++++++++++
 index.html          |  61 ++++++++++++++++
 styles.css          | 201 ++++++++++++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 430 insertions(+)

diff --git a/.vscode/launch.json b/.vscode/launch.json
new file mode 100644
index 0000000..faf7542
--- /dev/null
+++ b/.vscode/launch.json
@@ -0,0 +1,15 @@
+{
+    // Use IntelliSense to learn about possible attributes.
+    // Hover to view descriptions of existing attributes.
+    // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
+    "version": "0.2.0",
+    "configurations": [
+        {
+            "type": "pwa-chrome",
+            "request": "launch",
+            "name": "Launch Chrome against localhost",
+            "url": "http://127.0.0.1:5500/",
+            "webRoot": "${workspaceFolder}"
+        }
+    ]
+}
\ No newline at end of file
diff --git a/game.js b/game.js
new file mode 100644
index 0000000..aa4619b
--- /dev/null
+++ b/game.js
@@ -0,0 +1,153 @@
+// DOM references
+const cells = () => Array.from(document.querySelectorAll("td"));
+const redPieces = () => Array.from(document.querySelectorAll(".red-piece"));
+const bluePieces = () => Array.from(document.querySelectorAll(".blue-piece"));
+const redTurnText = () => Array.from(document.querySelectorAll(".red-turn-text"));
+const blueTurnText = () => Array.from(document.querySelectorAll(".blue-turn-text"));
+const divider = () => Array.from(document.querySelector("#divider"));
+
+// board
+const board = [
+    0, null, null, 1,
+    null, 2, 3, null,
+    null, 4, 5, null,
+    6, null, null, 7
+];
+
+/** @type {{element: Element, type: string, listener: (event: Event) => void}[]} */
+const listeners = [];
+
+// player properties
+let isRedTurn = false;
+/** @type {NodeListOf<Element>} */
+let playerPieces;
+let selectedPieceId = -1;
+
+/**
+ * @param {Element} element
+ * @param {string} eventName
+ * @param {Event => void} callback
+ */
+const addListener = (element, type, listener) => {
+    element.addEventListener(type, listener);
+    listeners.push({ element, type, listener });
+}
+const removeListeners = () => {
+    listeners.forEach(value => {
+        const { element, type, listener } = value;
+        element.removeEventListener(type, listener);
+    });
+    listeners.length = 0;
+}
+
+const resetBoard = () => {
+    // resetPieces
+    /** @param {Element} piece */
+    const resetPiece = (piece) => {
+        piece.classList.remove(selectedPieceClassName);
+        piece.classList.remove(activePlayerPieceClassName);
+    };
+    redPieces().forEach(resetPiece);
+    bluePieces().forEach(resetPiece);
+
+    // resetCells
+    cells().forEach(cell => {
+        cell.classList.remove('blinking');
+    });
+
+    // remove all listeners
+    removeListeners();
+};
+
+const setActivePlayerPieces = () => {
+    // mark active pieces
+    playerPieces = isRedTurn ? redPieces() : bluePieces()
+    playerPieces.forEach(pp => {
+        pp.classList.add(activePlayerPieceClassName);
+        // pp.addEventListener('click', selectPiece);
+        addListener(pp, 'click', selectPiece);
+    });
+};
+
+/** @param {Event} event */
+const selectPiece = (event) => {
+    resetBoard();
+    setActivePlayerPieces();
+
+    // read event data
+    /** @type {Element} */
+    const piece = event.target;
+    const pieceId = parseInt(piece.id);
+    const pieceIndex = board.indexOf(pieceId);
+
+    // set as selected
+    selectedPieceId = pieceId;
+    piece.classList.add(selectedPieceClassName);
+
+    // blink allowed moves
+    const allowedMoveIndices = board
+        .map((value, index) => {
+            const isOccupied = index === pieceIndex || value !== null;
+            return isOccupied ? -1 : index;
+        })
+        .filter(v => v >= 0);
+    allowedMoveIndices.forEach(i => {
+        const cell = cells()[i];
+        // cell.addEventListener('click', () => makeMove(i))
+        addListener(cell, 'click', () => makeMove(i));
+        cell.classList.add('blinking');
+    });
+};
+
+const selectedPieceClassName = 'selected-piece';
+const selectedPlayerTextClassName = 'selected-player-text';
+const activePlayerPieceClassName = 'active-player-piece';
+
+const makeMove = (destIndex) => {
+    // find current piece
+    const piece = document.getElementById(selectedPieceId);
+    const pieceId = Number.parseInt(piece.id)
+    const pieceIndex = board.indexOf(pieceId);
+
+    // move piece to destination cell
+    const pieceHtml = cells()[pieceIndex].innerHTML;
+    cells()[pieceIndex].innerHTML = '';
+    cells()[destIndex].innerHTML = pieceHtml;
+
+    // move piece on board
+    board[pieceIndex] = null;
+    board[destIndex] = pieceId;
+
+    checkForWin();
+    nextMove();
+}
+
+const nextMove = () => {
+    // reset text
+    redTurnText().forEach(t => t.classList.remove(selectedPlayerTextClassName));
+    blueTurnText().forEach(t => t.classList.remove(selectedPlayerTextClassName));
+
+    // changePlayer
+    // 1. flip flag
+    // 2. set text
+    // 3. set click callbacks
+    if (isRedTurn) {
+        isRedTurn = false;
+        blueTurnText().forEach(t => t.classList.add(selectedPlayerTextClassName));
+    }
+    else {
+        isRedTurn = true;
+        redTurnText().forEach(t => t.classList.add(selectedPlayerTextClassName));
+    }
+
+    resetBoard();
+    setActivePlayerPieces();
+};
+
+const checkForWin = () => {
+
+};
+
+
+// start!
+nextMove();
\ No newline at end of file
diff --git a/index.html b/index.html
new file mode 100644
index 0000000..50e6c89
--- /dev/null
+++ b/index.html
@@ -0,0 +1,61 @@
+<!DOCTYPE html>
+<html lang="en">
+
+    <head>
+        <meta charset="utf-8">
+        <title>Dao Game</title>
+        <meta name="viewport" content="width=device-width, initial-scale=1">
+        <link rel="stylesheet" href="styles.css" />
+        <script defer type="module" src="game.js"></script>
+    </head>
+
+    <body>
+        <main>
+            <div class="red-turn-text mobile">
+                Red's turn
+            </div>
+
+            <table>
+                <tr>
+                    <td class="white"><p class='red-piece' id='0'></p></td>
+                    <td class="black"></td>
+                    <td class="white"></td>
+                    <td class="black"><p class='blue-piece' id='1'></p></td>
+                </tr>
+                <tr>
+                    <td class="black"></td>
+                    <td class="white"><p class='red-piece' id='2'></p></td>
+                    <td class="black"><p class='blue-piece' id='3'></p></td>
+                    <td class="white"></td>
+                </tr>
+                <tr>
+                    <td class="white"></td>
+                    <td class="black"><p class='blue-piece' id='4'></p></td>
+                    <td class="white"><p class='red-piece' id='5'></p></td>
+                    <td class="black"></td>
+                </tr>
+                <tr>
+                    <td class="black"><p class='blue-piece' id='6'></p></td>
+                    <td class="white"></td>
+                    <td class="black"></td>
+                    <td class="white"><p class='red-piece' id='7'></p></td>
+                </tr>
+            </table>
+
+            <div class="desktop">
+                <div class="red-turn-text">
+                    Red's turn
+                </div>
+                <p id="divider">|</p>
+                <div class="blue-turn-text">
+                    Blue's turn
+                </div>
+            </div>
+
+            <div class="blue-turn-text mobile">
+                Blue's turn
+            </div>
+        </main>
+    </body>
+
+</html>
\ No newline at end of file
diff --git a/styles.css b/styles.css
new file mode 100644
index 0000000..cd48150
--- /dev/null
+++ b/styles.css
@@ -0,0 +1,201 @@
+* {
+    margin: auto;
+}
+
+main {
+    display: flex;
+    flex-direction: column;
+    justify-content: space-between;
+    align-items: center;
+    height: 100vh;
+}
+
+body {
+    overflow: hidden;
+    margin: 0px;
+    background-color: white;
+}
+
+div {
+    display: flex;
+    justify-content: space-between;
+}
+
+.mobile {
+    display: none;
+}
+
+.desktop {
+    margin: 0;
+    width: 100%;
+}
+
+td {
+    width: 65px;
+    height: 65px;
+    text-align: center;
+}
+
+/* this puts the circles slightly higher up */
+p {
+    display: inline-block;
+}
+
+#divider {
+    font-size: 90px;
+    margin-left: 15px;
+    margin-right: 15px;
+}
+
+.red-turn-text {
+    text-align: center;
+    color: lightgray;
+    font-family: "open sans";
+    font-size: 55px;
+}
+
+.blue-turn-text {
+    text-align: center;
+    font-family: "open sans";
+    font-size: 55px;
+    color: lightgray;
+}
+
+.white {
+    background-color: orange;
+}
+.black {
+    background-color: burlywood;
+}
+
+.red-piece {
+    width: 20px;
+    height: 20px;
+    padding: 12px;
+    background-color: crimson;
+    border: 1px solid white;
+    border-radius: 50px;
+}
+.blue-piece {
+    width: 20px;
+    height: 20px;
+    padding: 12px;
+    background-color: mediumblue;
+    border: 1px solid white;
+    border-radius: 50px;
+}
+
+.active-player-piece {
+    border: 5px solid white;
+}
+
+.selected-piece {
+    border-color: greenyellow;
+}
+
+.selected-player-text {
+    color: black;
+}
+
+.blinking {
+    /* opacity: .5; */
+    /* background-color: brown; */
+    /* color: aqua; */
+    animation: blinkingText 1s infinite;
+}
+@keyframes blinkingText {
+    0%{opacity: 1;}
+    50%{opacity: .5;}
+    100%{opacity: 1;}
+}
+
+/* breaks */
+
+/* @media screen and (max-width: 560px) {
+    .red-piece {
+        height: 4.5vw;
+        width: 4.5vw;
+    }
+
+    .black-piece {
+        height: 4.5vw;
+        width: 4.5vw;
+    }
+
+    td {
+        width: 12vw;
+        height: 12vw;
+    }
+
+    .red-turn-text {
+        font-size: 40px;
+    }
+    
+    .black-turn-text {
+        font-size: 40px;
+    }
+
+    table {
+        margin: 0;
+    }
+
+    .mobile {
+        display: block;
+    }
+
+    .desktop {
+        display: none;
+    }
+
+    .red-turn-text {
+        -webkit-transform:rotate(-180deg);
+        -moz-transform:rotate(-180deg);
+        -o-transform:rotate(-180deg);
+        transform:rotate(-180deg);
+        filter:progid:DXImageTransform.Microsoft.BasicImage(rotation=2);    
+    }
+}
+
+@media screen and (max-width: 380px) {
+    .red-piece {
+        height: 3vw;
+        width: 3vw;
+    }
+
+    .black-piece {
+        height: 3vw;
+        width: 3vw;
+    }
+}
+
+@media screen and (max-width: 345px) {
+    .red-piece {
+        height: 2.5vw;
+        width: 2.5vw;
+    }
+
+    .black-piece {
+        height: 2.5vw;
+        width: 2.5vw;
+    }
+}
+
+@media screen and (max-width: 300px) {
+    .red-piece {
+        height: 1.5vw;
+        width: 1.5vw;
+    }
+
+    .black-piece {
+        height: 1.5vw;
+        width: 1.5vw;
+    }
+
+    .red-turn-text {
+        font-size: 35px;
+    }
+    
+    .black-turn-text {
+        font-size: 35px;
+    }
+} */
\ No newline at end of file