Refactoring

main
selim 2025-01-02 16:28:32 +01:00
parent 26a0a195c2
commit bc6b3f9487
9 changed files with 252 additions and 282 deletions

View File

@ -2,7 +2,7 @@
<html lang="en"> <html lang="en">
<head> <head>
<meta charset="UTF-8" /> <meta charset="UTF-8" />
<link rel="icon" type="image/svg+xml" href="/vite.svg" /> <link rel="icon" type="image/svg+xml" href="/src/assets/react.svg" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>CONNECT4</title> <title>CONNECT4</title>
</head> </head>

View File

@ -1 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" class="iconify iconify--logos" width="31.88" height="32" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 257"><defs><linearGradient id="IconifyId1813088fe1fbc01fb466" x1="-.828%" x2="57.636%" y1="7.652%" y2="78.411%"><stop offset="0%" stop-color="#41D1FF"></stop><stop offset="100%" stop-color="#BD34FE"></stop></linearGradient><linearGradient id="IconifyId1813088fe1fbc01fb467" x1="43.376%" x2="50.316%" y1="2.242%" y2="89.03%"><stop offset="0%" stop-color="#FFEA83"></stop><stop offset="8.333%" stop-color="#FFDD35"></stop><stop offset="100%" stop-color="#FFA800"></stop></linearGradient></defs><path fill="url(#IconifyId1813088fe1fbc01fb466)" d="M255.153 37.938L134.897 252.976c-2.483 4.44-8.862 4.466-11.382.048L.875 37.958c-2.746-4.814 1.371-10.646 6.827-9.67l120.385 21.517a6.537 6.537 0 0 0 2.322-.004l117.867-21.483c5.438-.991 9.574 4.796 6.877 9.62Z"></path><path fill="url(#IconifyId1813088fe1fbc01fb467)" d="M185.432.063L96.44 17.501a3.268 3.268 0 0 0-2.634 3.014l-5.474 92.456a3.268 3.268 0 0 0 3.997 3.378l24.777-5.718c2.318-.535 4.413 1.507 3.936 3.838l-7.361 36.047c-.495 2.426 1.782 4.5 4.151 3.78l15.304-4.649c2.372-.72 4.652 1.36 4.15 3.788l-11.698 56.621c-.732 3.542 3.979 5.473 5.943 2.437l1.313-2.028l72.516-144.72c1.215-2.423-.88-5.186-3.54-4.672l-25.505 4.922c-2.396.462-4.435-1.77-3.759-4.114l16.646-57.705c.677-2.35-1.37-4.583-3.769-4.113Z"></path></svg>

Before

Width:  |  Height:  |  Size: 1.5 KiB

View File

@ -0,0 +1,40 @@
#app-container{
font-family: Arial, Helvetica, sans-serif;
}
.gamemode {
text-align: center;
margin-left: auto;
margin-right: auto;
width: 300px;
height: 202px;
border: 5px solid black;
background-color: blue;
}
.gamemode-selection {
margin-top: 34px;
border: 3px solid black;
width: 50%;
height: 50px;
font-size: larger;
}
.gamemode-selection:hover {
cursor: pointer;
background-color: lightgray;
}
.message{
text-align: center;
font-size: larger;
}
.heading{
text-align: center;
transition: font-size 1s ease-out 100ms;
}
.heading:hover{
font-size:3em;
}

View File

@ -0,0 +1,62 @@
import { useState } from "react";
import { clickHandlerGamemode } from "./AppFunctions.js";
import "./App.css";
import Board from "../Board/Board.jsx";
export const self = {};
const App = () => {
const [menu, setMenu] = useState(true);
self.menu = menu;
self.setMenu = setMenu;
const [gamemode, setGamemode] = useState(0);
self.gamemode = gamemode;
self.setGamemode = setGamemode;
return (
<div id="app-container">
<Heading />
<Gamemode />
<Board />
<Message />
</div>
);
};
const Gamemode = () => (
<div className="gamemode" hidden={!self.menu}>
<button
className="gamemode-selection"
onClick={async () => await clickHandlerGamemode(self, 1)}
>
singleplayer
</button>
<br />
<button
className="gamemode-selection"
onClick={async () => await clickHandlerGamemode(self, 2)}
>
multiplayer
</button>
</div>
);
const Heading = () => (
<h1 className="heading" hidden={!self.menu}>
CONNECT4
</h1>
);
const Message = () => {
const [message, setMessage] = useState("");
self.message = message;
self.setMessage = setMessage;
return (
<p className="message" hidden={self.menu}>
{message}
</p>
);
};
export default App;

View File

@ -0,0 +1,4 @@
export const clickHandlerGamemode = async (self, gamemode) => {
await self.setMenu(false);
await self.setGamemode(gamemode);
};

View File

@ -1,9 +1,3 @@
body {
text-align: center;
font-family: Arial, Helvetica, sans-serif;
color: black;
}
.board-outer { .board-outer {
width: 600px; width: 600px;
border: 5px solid black; border: 5px solid black;
@ -31,7 +25,17 @@ body {
outline-offset: -7px; outline-offset: -7px;
} }
.inner-button { .board-action{
display: flex;
align-items: center;
justify-content: center;
margin-left: auto;
margin-right: auto;
margin-top: 30px;
margin-bottom: 30px;
}
.action-button {
width: 17%; width: 17%;
height: 60px; height: 60px;
font-size: larger; font-size: larger;
@ -45,73 +49,11 @@ body {
font-size: x-large; font-size: x-large;
} }
.inner-button:hover { .action-button:hover {
cursor: pointer; cursor: pointer;
background-color: lightgray; background-color: lightgray;
} }
#board-load-button{
margin-left: 16.1%;
}
.flex-box .inner-button{
width: 200px;
}
.board-state .inner-button:disabled{
margin-left: 16.1%;
color: black;
background-color: lightgray;
border-color: black;
cursor: not-allowed ;
}
.gamemode-div {
margin-left: auto;
margin-right: auto;
width: 300px;
height: 202px;
border: 5px solid black;
background-color: blue;
}
.gamemode-div .gamemode-button {
margin-top: 34px;
border: 3px solid black;
width: 50%;
height: 50px;
font-size: larger;
}
.gamemode-div .gamemode-button:hover {
cursor: pointer;
background-color: lightgray;
}
.message {
font-size: larger;
}
.heading{
transition: font-size 1s ease-out 100ms;
}
.heading:hover{
font-size:3em;
}
.board-rw{
height: 40px;
width: 60%;
border: 3px solid black;
font-size: medium;
margin-right: auto;
}
.board-state{ .board-state{
display: flex; display: flex;
align-items: center; align-items: center;
@ -123,21 +65,24 @@ body {
margin-top: 10px; margin-top: 10px;
} }
.action-bar{ .board-state-action{
display: flex; margin-right: 3%;
align-items: center;
justify-content: center;
margin-left: auto;
margin-right: auto;
margin-bottom: 30px;
} }
.board-state .inner-button{ .board-state-number{
height: 40px;
width: 60%;
border: 3px solid black;
font-size: medium;
}
.board-state .board-action{
margin-top: 0px;
margin-bottom: 0px;
}
.board-state .action-button{
width: 100px; width: 100px;
height: 48px; height: 48px;
} }
.field-div{
width: 20%;
margin-left: auto;
}

View File

@ -2,15 +2,14 @@ import { useState } from "react";
import { import {
clickHandlerTurn, clickHandlerTurn,
clickHandlerRestart, clickHandlerRestart,
clickHandlerGamemode,
clickHandlerReturn, clickHandlerReturn,
clickHandlerLoadBoard, clickHandlerLoadBoard,
clickHandlerCopyClipboard, clickHandlerCopyClipboard,
} from "./functions"; } from "./BoardFunctions.js";
import "./Board.css";
import { self } from "../App/App.jsx";
const self = {}; const Board = () => {
export default function App() {
const [colorBoard, setColorBoard] = useState( const [colorBoard, setColorBoard] = useState(
Array.from(Array(6), () => new Array(7).fill("white")) Array.from(Array(6), () => new Array(7).fill("white"))
); );
@ -31,37 +30,48 @@ export default function App() {
self.currentPlayer = currentPlayer; self.currentPlayer = currentPlayer;
self.setCurrentPlayer = setCurrentPlayer; self.setCurrentPlayer = setCurrentPlayer;
const [message, setMessage] = useState("");
self.message = message;
self.setMessage = setMessage;
const [turns, setTurns] = useState(0); const [turns, setTurns] = useState(0);
self.turns = turns; self.turns = turns;
self.setTurns = setTurns; self.setTurns = setTurns;
const [menu, setMenu] = useState(true);
self.menu = menu;
self.setMenu = setMenu;
const [gamemode, setGamemode] = useState(0);
self.gamemode = gamemode;
self.setGamemode = setGamemode;
const [turnsMem, setTurnsMem] = useState(""); const [turnsMem, setTurnsMem] = useState("");
self.turnsMem = turnsMem; self.turnsMem = turnsMem;
self.setTurnsMem = setTurnsMem; self.setTurnsMem = setTurnsMem;
return ( const fields = colorBoard.map((subarr, row) =>
<> subarr.map((color, col) => {
<Heading /> return (
<Gamemode /> <Field
<Board /> key={row.toString() + col.toString()}
<Message /> row={row}
</> col={col}
style={{
backgroundColor: color,
outlineWidth: outlineBoard[row][col].split(" ")[0],
outlineColor: outlineBoard[row][col].split(" ")[2],
outlineStyle: outlineBoard[row][col].split(" ")[1],
}}
disabled={row === 0 ? gameOver : true}
/>
);
})
); );
}
function Field({ row, col, style, disabled }) { return (
<div className="board-outer" hidden={self.menu}>
<div className="board-inner">
{fields.map((subarr) => subarr.map((field) => field))}
</div>
<BoardState />
<div className="board-action">
<Return />
<Restart />
</div>
</div>
);
};
const Field = ({ row, col, style, disabled }) => {
const [pointer, setPointer] = useState(false); const [pointer, setPointer] = useState(false);
const [hoverColor, setHoverColor] = useState("white"); const [hoverColor, setHoverColor] = useState("white");
@ -108,106 +118,9 @@ function Field({ row, col, style, disabled }) {
&nbsp; &nbsp;
</button> </button>
); );
} };
function Board() { const BoardState = () => {
const fields = self.colorBoard.map((subarr, row) =>
subarr.map((color, col) => {
return (
<Field
key={row.toString() + col.toString()}
row={row}
col={col}
style={{
backgroundColor: color,
outlineWidth: self.outlineBoard[row][col].split(" ")[0],
outlineColor: self.outlineBoard[row][col].split(" ")[2],
outlineStyle: self.outlineBoard[row][col].split(" ")[1],
}}
disabled={row === 0 ? self.gameOver : true}
/>
);
})
);
const displayMem = self.menu ? "none" : "";
const displayState = self.gamemode === 1 ? "none" : "";
return (
<div className="board-outer" style={{ display: displayMem }}>
<div className="board-inner">
{fields.map((subarr) => subarr.map((field) => field))}
</div>
<BoardState display={displayState} />
<br />
<div className="action-bar">
<Return />
<Restart />
</div>
</div>
);
}
function Restart() {
return (
<button
className="inner-button"
id="restart"
hidden={!self.gameOver}
onClick={() => clickHandlerRestart(self)}
>
&#8634;
</button>
);
}
function Return() {
return (
<button className="inner-button" onClick={() => clickHandlerReturn(self)}>
menu
</button>
);
}
function Gamemode() {
return (
<div className="gamemode-div" hidden={!self.menu}>
<button
className="gamemode-button"
onClick={() => clickHandlerGamemode(self, 1)}
>
singleplayer
</button>
<br />
<button
className="gamemode-button"
onClick={() => clickHandlerGamemode(self, 2)}
>
multiplayer
</button>
</div>
);
}
function Message() {
const displayMem = self.menu ? "none" : "";
return (
<p className="message" style={{ display: displayMem }}>
{self.message}
</p>
);
}
function Heading() {
const displayMem = !self.menu ? "none" : "";
return (
<h1 className="heading" style={{ display: displayMem }}>
CONNECT4
</h1>
);
}
function BoardState({ display }) {
const [boardDecimal, setBoardDecimal] = useState(""); const [boardDecimal, setBoardDecimal] = useState("");
self.boardDecimal = boardDecimal; self.boardDecimal = boardDecimal;
self.setBoardDecimal = setBoardDecimal; self.setBoardDecimal = setBoardDecimal;
@ -221,11 +134,11 @@ function BoardState({ display }) {
self.setShowCopy = setShowCopy; self.setShowCopy = setShowCopy;
return ( return (
<div style={{ display: display }}> <div hidden={self.gamemode !== 2}>
<div className="board-state"> <div className="board-state">
<div className="field-div"> <div className="board-state-action">
<button <button
className="inner-button" className="action-button"
onClick={() => { onClick={() => {
clickHandlerCopyClipboard(self); clickHandlerCopyClipboard(self);
}} }}
@ -234,29 +147,52 @@ function BoardState({ display }) {
</button> </button>
</div> </div>
<input <input
className="board-rw" className="board-state-number"
id="1"
type="text" type="text"
readOnly={true} readOnly={true}
value={self.showCopy ? "copied to clipboard!" : self.boardDecimal} value={showCopy ? "copied to clipboard!" : boardDecimal}
name="board-state-output"
/> />
</div> </div>
<div className="board-state"> <div className="board-state">
<div className="field-div"> <div className="board-state-action">
<button <button
className="inner-button" className="action-button"
onClick={() => clickHandlerLoadBoard(self, self.inputDecimal)} onClick={() => clickHandlerLoadBoard(self, inputDecimal)}
> >
load load
</button> </button>
</div> </div>
<input <input
className="board-rw" className="board-state-number"
type="text" type="number"
value={self.inputDecimal} min="7"
onChange={(i) => setInputDecimal(i.target.value)} max="6239465226101869857685537024892857210"
step="1"
value={inputDecimal === 0 ? "" : inputDecimal}
name="board-state-input"
onChange={(i) => setInputDecimal(Math.floor(i.target.value))}
/> />
</div> </div>
</div> </div>
); );
} };
const Return = () => (
<button className="action-button" onClick={() => clickHandlerReturn(self)}>
menu
</button>
);
const Restart = () => (
<button
className="action-button"
id="restart"
hidden={!self.gameOver}
onClick={() => clickHandlerRestart(self)}
>
&#8634;
</button>
);
export default Board;

View File

@ -1,10 +1,10 @@
async function putChip( const putChip = async (
col, col,
colorBoard, colorBoard,
currentPlayer, currentPlayer,
setColorBoard, setColorBoard,
setCurrentPlayer setCurrentPlayer
) { ) => {
for (let row = 5; row >= 0; row--) { for (let row = 5; row >= 0; row--) {
if (colorBoard[row][col] === "white") { if (colorBoard[row][col] === "white") {
if (currentPlayer === "red") { if (currentPlayer === "red") {
@ -23,14 +23,14 @@ async function putChip(
} }
} }
return false; return false;
} };
async function checkWin( const checkWin = async (
colorBoard, colorBoard,
currentPlayer, currentPlayer,
outlineBoard, outlineBoard,
setOutlineBoard setOutlineBoard
) { ) => {
const memOutlineBoard = outlineBoard; const memOutlineBoard = outlineBoard;
for (let row = 0; row <= 5; row++) { for (let row = 0; row <= 5; row++) {
@ -90,28 +90,44 @@ async function checkWin(
} }
return false; return false;
} };
function botChoice(colorBoard) { const botChoice = (colorBoard) => {
while (true) { while (true) {
const rand = Math.floor(Math.random() * 7); const rand = Math.floor(Math.random() * 7);
if (colorBoard[0][rand] === "white") { if (colorBoard[0][rand] === "white") {
return rand; return rand;
} }
} }
} };
export function colFull(col, colorBoard) { const sepToDec = (sep) => {
for (let row = 5; row >= 0; row--) { let res = 0n;
if (colorBoard[row][col] === "white") { let ind = 0n;
return false; let mem = sep.split("").reverse().join("");
} else { while (ind < mem.length) {
return true; res = BigInt(7n ** ind * BigInt(mem[ind])) + res;
} ind++;
} }
} res = BigInt(7n ** ind) + res;
export async function clickHandlerTurn(self, col) { return res;
};
const decToSep = (dec) => {
let mem = BigInt(dec);
let res = "";
while (mem > 0n) {
res = (mem % 7n).toString() + res;
mem = mem / 7n;
}
res = res.slice(1, res.length);
return res;
};
export const clickHandlerTurn = async (self, col) => {
const iMax = self.gamemode === 1 ? 2 : 1; const iMax = self.gamemode === 1 ? 2 : 1;
for (let i = 0; i < iMax; i++) { for (let i = 0; i < iMax; i++) {
@ -166,9 +182,9 @@ export async function clickHandlerTurn(self, col) {
if (self.gamemode === 2) { if (self.gamemode === 2) {
await self.setBoardDecimal(sepToDec(self.turnsMem).toString()); await self.setBoardDecimal(sepToDec(self.turnsMem).toString());
} }
} };
export async function clickHandlerRestart(self) { export const clickHandlerRestart = async (self) => {
await self.setTurns(0); await self.setTurns(0);
await self.setGameOver(false); await self.setGameOver(false);
await self.setCurrentPlayer("red"); await self.setCurrentPlayer("red");
@ -182,14 +198,9 @@ export async function clickHandlerRestart(self) {
await self.setTurnsMem(""); await self.setTurnsMem("");
await self.setBoardDecimal(""); await self.setBoardDecimal("");
await self.setInputDecimal(""); await self.setInputDecimal("");
} };
export async function clickHandlerGamemode(self, gamemode) { export const clickHandlerReturn = async (self) => {
await self.setMenu(false);
await self.setGamemode(gamemode);
}
export async function clickHandlerReturn(self) {
await self.setMenu(true); await self.setMenu(true);
await self.setTurns(0); await self.setTurns(0);
await self.setGameOver(false); await self.setGameOver(false);
@ -204,9 +215,9 @@ export async function clickHandlerReturn(self) {
await self.setTurnsMem(""); await self.setTurnsMem("");
await self.setBoardDecimal(""); await self.setBoardDecimal("");
await self.setInputDecimal(""); await self.setInputDecimal("");
} };
export async function clickHandlerLoadBoard(self, dec) { export const clickHandlerLoadBoard = async (self, dec) => {
let sep = decToSep(dec); let sep = decToSep(dec);
await clickHandlerRestart(self); await clickHandlerRestart(self);
@ -214,38 +225,12 @@ export async function clickHandlerLoadBoard(self, dec) {
await clickHandlerTurn(self, sep[sep.length - 1]); await clickHandlerTurn(self, sep[sep.length - 1]);
sep = sep.slice(0, -1); sep = sep.slice(0, -1);
} }
} };
export async function clickHandlerCopyClipboard(self) { export const clickHandlerCopyClipboard = async (self) => {
navigator.clipboard.writeText(self.boardDecimal); navigator.clipboard.writeText(self.boardDecimal);
self.setShowCopy(true); self.setShowCopy(true);
setTimeout(() => { setTimeout(() => {
self.setShowCopy(false); self.setShowCopy(false);
}, 1500); }, 1500);
} };
function sepToDec(sep) {
let res = 0n;
let ind = 0n;
let mem = sep.split("").reverse().join("");
while (ind < mem.length) {
res = BigInt(7n ** ind * BigInt(mem[ind])) + res;
ind++;
}
res = BigInt(7n ** ind) + res;
return res;
}
function decToSep(dec) {
let mem = BigInt(dec);
let res = "";
while (mem > 0n) {
res = (mem % 7n).toString() + res;
mem = mem / 7n;
}
res = res.slice(1, res.length);
return res;
}

View File

@ -1,7 +1,6 @@
import { StrictMode } from "react"; import { StrictMode } from "react";
import { createRoot } from "react-dom/client"; import { createRoot } from "react-dom/client";
import "./index.css"; import App from "./components/App/App.jsx";
import App from "./App.jsx";
createRoot(document.getElementById("root")).render( createRoot(document.getElementById("root")).render(
<StrictMode> <StrictMode>