(undefined);
+ const [playerNum, setPlayerNum] = useState(0);
+ const [username, setUsername] = useState("");
+ const [oppUsername, setOppUsername] = useState("");
+ const [gameOn, setGameOn] = useState(false)
+
+ return (
+
+ {gameOn && conn
+ ? ()
+ : ()
+ }
+
+ );
+}
\ No newline at end of file
diff --git a/src/components/Apps/TicTacToe/components/Circle.tsx b/src/components/Apps/TicTacToe/components/Circle.tsx
new file mode 100644
index 0000000..858ff1f
--- /dev/null
+++ b/src/components/Apps/TicTacToe/components/Circle.tsx
@@ -0,0 +1,22 @@
+export function Circle() {
+ return (
+
+ )
+}
\ No newline at end of file
diff --git a/src/components/Apps/TicTacToe/components/Cross.tsx b/src/components/Apps/TicTacToe/components/Cross.tsx
new file mode 100644
index 0000000..5b24de4
--- /dev/null
+++ b/src/components/Apps/TicTacToe/components/Cross.tsx
@@ -0,0 +1,23 @@
+export function Cross() {
+ return (
+
+ );
+}
\ No newline at end of file
diff --git a/src/components/Apps/TicTacToe/components/Empty.tsx b/src/components/Apps/TicTacToe/components/Empty.tsx
new file mode 100644
index 0000000..5caa3c2
--- /dev/null
+++ b/src/components/Apps/TicTacToe/components/Empty.tsx
@@ -0,0 +1,14 @@
+export function Empty() {
+ return (
+
+ );
+}
\ No newline at end of file
diff --git a/src/components/Apps/TicTacToe/components/TTTBtn.tsx b/src/components/Apps/TicTacToe/components/TTTBtn.tsx
new file mode 100644
index 0000000..d9c3123
--- /dev/null
+++ b/src/components/Apps/TicTacToe/components/TTTBtn.tsx
@@ -0,0 +1,21 @@
+type TTTBtnProps = {
+ btnIndex: number;
+ isBtnDisabled: (index: number) => boolean;
+ isBtnHidden: (index: number) => boolean;
+ getBtnState: (index: number) => string | JSX.Element;
+ setField: (index: number) => void;
+}
+
+export function TTTBtn(props: TTTBtnProps) {
+
+ return (
+
+
+ |
+ );
+}
\ No newline at end of file
diff --git a/src/components/Apps/TicTacToe/components/TTTGame.tsx b/src/components/Apps/TicTacToe/components/TTTGame.tsx
new file mode 100644
index 0000000..3f00b3a
--- /dev/null
+++ b/src/components/Apps/TicTacToe/components/TTTGame.tsx
@@ -0,0 +1,142 @@
+import { TTTRow } from "./TTTRow.tsx";
+import { Dispatch, SetStateAction, useEffect, useRef, useState } from "react";
+import { DataConnection } from "peerjs";
+
+type TTTGameProps = {
+ setConn: Dispatch>;
+ conn: DataConnection;
+ setPlayerNum: Dispatch>;
+ playerNum: number;
+ setGameOn: Dispatch>;
+}
+
+export function TTTGame(props: TTTGameProps) {
+ const [gameState, setGameState] = useState([0, 0, 0, 0, 0, 0, 0, 0, 0]);
+ const [newGameState, setNewGameState] = useState([0, 0, 0, 0, 0, 0, 0, 0, 0]);
+ const inputType = useRef(0);
+
+ useEffect(() => {
+ props.conn.on("data", function(data) {
+ inputType.current = 2;
+ console.log("recv", data);
+ setNewGameState(data as number[]);
+ });
+ props.conn.on("close", function() {
+ props.setGameOn(false);
+ props.setConn(undefined);
+ });
+ }, [props.conn]);
+
+ function setField(index: number) {
+ setNewGameState(newGameState => {
+ const tmpGameState = [...newGameState];
+ tmpGameState[index] = props.playerNum;
+ inputType.current = 1;
+ props.conn.send(tmpGameState);
+ return tmpGameState;
+ });
+ }
+
+ useEffect(() => {
+ console.log("use-effect-new", newGameState);
+ if (inputType.current > 0) {
+ evaluate(newGameState, gameState);
+ setGameState(newGameState);
+ inputType.current = 0;
+ }
+ }, [newGameState]);
+
+ function endGame(status: number) {
+ console.log("exit-game", status);
+ props.setPlayerNum(status);
+ props.setGameOn(false);
+ }
+
+ function checkIfWon(num1: number, num2: number, num3: number, newGameState: number[]) {
+ if (newGameState[num1] == newGameState[num2] && newGameState[num2] == newGameState[num3]) {
+ if (newGameState[num1] == 0) {
+ return;
+ } else if (newGameState[num1] == props.playerNum) {
+ endGame(3);
+ } else {
+ endGame(4);
+ }
+ }
+ }
+
+ function evaluate(newGameState: number[], oldGameState: number[]) {
+ console.log("=============evaluate==========");
+ console.log("old", oldGameState);
+ console.log("new", newGameState);
+ //Check if player can do move
+ if ((gameState.filter(state => state == 0).length % 2 == props.playerNum - 1) && inputType.current == 1) {
+ console.log("player not at turn");
+ endGame(5);
+ }
+
+ //Check if not more than on field has been changed
+
+ //Check if field has not already been set
+ for (let i = 0; i < oldGameState.length - 1; i++) {
+ if (newGameState[i] != 0 && oldGameState[i] != 0 && newGameState[i] != oldGameState[i]) {
+ console.log("field already set");
+ endGame(5);
+ }
+ }
+
+ //Check if someone has won
+ //horizontal
+ for (let i = 1; i <= 3; i++) {
+ checkIfWon(i * 3 - 1, i * 3 - 2, i * 3 - 3, newGameState);
+ }
+ //vertical
+ for (let i = 6; i <= 8; i++) {
+ checkIfWon(i, i - 3, i - 6, newGameState);
+ }
+ //diagonal
+ checkIfWon(0, 4, 8, newGameState);
+ checkIfWon(2, 4, 6, newGameState);
+ console.log("=============ev done==========");
+ return;
+ }
+
+
+ function isBtnDisabled(index: number): boolean {
+ return gameState.filter(state => state == 0).length % 2 == props.playerNum - 1 || gameState[index] != 0;
+ }
+
+ function getBtnState(index: number): JSX.Element | string {
+ switch (gameState[index]) {
+ case 1:
+ return "X";
+ case 2:
+ return "O";
+ }
+ if (gameState.filter(state => state == 0).length % 2 != props.playerNum - 1) {
+ switch (props.playerNum) {
+ case 1:
+ return "X";
+ case 2:
+ return "O";
+ }
+ }
+ return "C";
+ }
+
+ function isBtnHidden(index: number): boolean {
+ return getBtnState(index) == "C";
+ }
+
+ return (
+
+ );
+}
\ No newline at end of file
diff --git a/src/components/Apps/TicTacToe/components/TTTLogin.tsx b/src/components/Apps/TicTacToe/components/TTTLogin.tsx
new file mode 100644
index 0000000..0a87a69
--- /dev/null
+++ b/src/components/Apps/TicTacToe/components/TTTLogin.tsx
@@ -0,0 +1,120 @@
+import React, { Dispatch, SetStateAction, useEffect, useState } from "react";
+import { DataConnection, Peer } from "peerjs";
+import { Alert, AlertColor, Box, Button, Container, TextField, Typography } from "@mui/material";
+
+type TTTLoginProps = {
+ peer: Peer | undefined;
+ setPeer: Dispatch>;
+ setConn: Dispatch>
+ setPlayerNum: Dispatch>;
+ playerNum: number
+ username: string;
+ setUsername: Dispatch>;
+ oppUsername: string;
+ setOppUsername: Dispatch>;
+ setGameOn: Dispatch>;
+}
+
+export function TTTLogin(props: TTTLoginProps) {
+ const [msg, setMsg] = useState("Connect to a game");
+ const [msgSeverity, setMsgSeverity] = useState("info");
+
+ function onConnOpen(conn: DataConnection) {
+ props.setConn(conn);
+ props.setGameOn(true);
+ }
+
+ function onPeerClose() {
+ props.setPlayerNum(6);
+ props.setGameOn(false);
+ props.setConn(undefined);
+ props.setPeer(undefined);
+ }
+
+ function setupPeer() {
+ const peer = new Peer(props.username, { debug: 3 });
+ peer.on("open", function(id) {
+ props.setUsername(id);
+ props.setPeer(peer);
+ peer.on("connection", function(conn) {
+ onConnOpen(conn);
+ props.setOppUsername(conn.peer);
+ props.setPlayerNum(2);
+ });
+ peer.on("close", function() {
+ onPeerClose();
+ });
+ peer.on("disconnected", function() {
+ onPeerClose();
+ });
+ });
+ }
+
+ function connectToGame() {
+ props.setPeer(peer => {
+ if (peer) {
+ const conn = peer.connect(props.oppUsername);
+ conn.on("open", function() {
+ onConnOpen(conn);
+ props.setPlayerNum(1);
+ });
+
+ }
+ return peer;
+ });
+
+ }
+
+ useEffect(() => {
+ let tmpMsg = "Connect to a game";
+ let tmpMsgSeverity: AlertColor = "info";
+ switch (props.playerNum) {
+ case 3:
+ tmpMsg = "You won against " + props.oppUsername;
+ break;
+ case 4:
+ tmpMsg = "You lost against " + props.oppUsername;
+ break;
+ case 5:
+ tmpMsg = "Error: Game corrupted";
+ tmpMsgSeverity = "error";
+ break;
+ case 6:
+ tmpMsg = "Error: Disconnected";
+ tmpMsgSeverity = "error";
+ break;
+ }
+ setMsg(tmpMsg);
+ setMsgSeverity(tmpMsgSeverity);
+ }, [props.playerNum]);
+
+ return (
+ <>
+
+
+
+ {msg}
+
+
+ props.setUsername(e.target.value)}
+ disabled={!!props.peer} />
+
+ props.setOppUsername(e.target.value)} disabled={!props.peer} />
+
+
+
+
+ >
+ );
+}
\ No newline at end of file
diff --git a/src/components/Apps/TicTacToe/components/TTTRow.tsx b/src/components/Apps/TicTacToe/components/TTTRow.tsx
new file mode 100644
index 0000000..eae2861
--- /dev/null
+++ b/src/components/Apps/TicTacToe/components/TTTRow.tsx
@@ -0,0 +1,32 @@
+import { TTTBtn } from "./TTTBtn.tsx";
+
+type TTTRowProps = {
+ rowIndex: number;
+ isBtnDisabled: (index: number) => boolean;
+ isBtnHidden: (index: number) => boolean;
+ getBtnState: (index: number) => string | JSX.Element;
+ setField: (index: number) => void;
+}
+
+export function TTTRow(props: TTTRowProps) {
+
+ return (
+
+
+
+
+
+ );
+}
\ No newline at end of file
diff --git a/src/components/Desktop/App/App.css b/src/components/Desktop/App/App.css
index 5bc8594..8fe7913 100644
--- a/src/components/Desktop/App/App.css
+++ b/src/components/Desktop/App/App.css
@@ -86,7 +86,7 @@
}
.appContent {
- height: 100%;
+ height: calc(100% - 35px);
width: 100%;
}
diff --git a/src/components/Desktop/Desktop.tsx b/src/components/Desktop/Desktop.tsx
index 88c3a8d..44375bf 100644
--- a/src/components/Desktop/Desktop.tsx
+++ b/src/components/Desktop/Desktop.tsx
@@ -115,7 +115,6 @@ function Desktop() {
width: (desktopSelectPos.width + "px"),
display: (desktopSelectPos.width + desktopSelectPos.height > 0 ? "block" : "none")
}} />
-
{
openedApps.map((appConfig) => (