From d063805c0c41665dbdcac175d447d6e156dfa61c Mon Sep 17 00:00:00 2001
From: Michael Urich <80188367+mturich@users.noreply.github.com>
Date: Mon, 11 Jul 2022 07:44:46 +0200
Subject: [PATCH 1/7] first test intoduced
---
src/components/App.tsx | 12 +++---
src/components/{ => Dimention}/Dimension.tsx | 2 +-
.../DisplayAntimatter.tsx | 2 +-
.../{ => GameResetBtns}/GameResets.tsx | 4 +-
src/components/{ => Tickspeed}/TickSpeed.tsx | 38 +++++++++----------
.../Tickspeed/getCostForPurchaseQty.test.tsx | 17 +++++++++
.../Tickspeed/getCostForPurchaseQty.tsx | 7 ++++
.../Tickspeed/maxPurchaseQty.test.ts | 18 +++++++++
src/components/Tickspeed/maxPurchaseQty.ts | 10 +++++
.../getMaxPurchaseQtyRecursive.test.ts | 13 -------
src/components/getMaxPurchaseQtyRecursive.ts | 7 ----
.../useLocalStorage.tsx} | 3 +-
12 files changed, 81 insertions(+), 52 deletions(-)
rename src/components/{ => Dimention}/Dimension.tsx (97%)
rename src/components/{ => DisplayAntimatter}/DisplayAntimatter.tsx (87%)
rename src/components/{ => GameResetBtns}/GameResets.tsx (95%)
rename src/components/{ => Tickspeed}/TickSpeed.tsx (70%)
create mode 100644 src/components/Tickspeed/getCostForPurchaseQty.test.tsx
create mode 100644 src/components/Tickspeed/getCostForPurchaseQty.tsx
create mode 100644 src/components/Tickspeed/maxPurchaseQty.test.ts
create mode 100644 src/components/Tickspeed/maxPurchaseQty.ts
delete mode 100644 src/components/getMaxPurchaseQtyRecursive.test.ts
delete mode 100644 src/components/getMaxPurchaseQtyRecursive.ts
rename src/{components/useSaveToLocalStorage.tsx => customeHooks/useLocalStorage.tsx} (93%)
diff --git a/src/components/App.tsx b/src/components/App.tsx
index f44f9e2..5c93dfd 100644
--- a/src/components/App.tsx
+++ b/src/components/App.tsx
@@ -1,13 +1,13 @@
import { useState, useEffect, useRef } from 'react';
import '../styles/App.css';
-import Dimension from './Dimension';
-import GameResets from './GameResets';
-import Tickspeed from './TickSpeed';
+import Dimension from './Dimention/Dimension';
+import GameResets from './GameResetBtns/GameResets';
+import Tickspeed from './Tickspeed/TickSpeed';
import { GameState, Dim } from '../common/GameStateInterface';
import initialGameState from '../common/initialGameState';
-import DisplayAntimatter from './DisplayAntimatter';
-import { useSaveToLocalStorage } from './useSaveToLocalStorage';
+import DisplayAntimatter from './DisplayAntimatter/DisplayAntimatter';
+import { useLocalStorage } from '../customeHooks/useLocalStorage';
function App() {
const [gameState, setGameState] = useState(() =>
@@ -17,7 +17,7 @@ function App() {
const timerExpiredCallback = useRef(() => {});
const clockSpeedRef = useRef(2000);
const timerIdRef = useRef(-1);
- useSaveToLocalStorage(gameState, setGameState);
+ useLocalStorage(gameState, setGameState);
timerExpiredCallback.current = () => {
setGameState((prevGS: GameState) => ({
diff --git a/src/components/Dimension.tsx b/src/components/Dimention/Dimension.tsx
similarity index 97%
rename from src/components/Dimension.tsx
rename to src/components/Dimention/Dimension.tsx
index e06022d..c195cf5 100644
--- a/src/components/Dimension.tsx
+++ b/src/components/Dimention/Dimension.tsx
@@ -1,4 +1,4 @@
-import { GameState, DimProps, Dim } from '../common/GameStateInterface';
+import { GameState, DimProps, Dim } from '../../common/GameStateInterface';
export default function Dimension(props: DimProps) {
const { nthDim, gs, setGameState } = props;
diff --git a/src/components/DisplayAntimatter.tsx b/src/components/DisplayAntimatter/DisplayAntimatter.tsx
similarity index 87%
rename from src/components/DisplayAntimatter.tsx
rename to src/components/DisplayAntimatter/DisplayAntimatter.tsx
index 4e4c685..750a861 100644
--- a/src/components/DisplayAntimatter.tsx
+++ b/src/components/DisplayAntimatter/DisplayAntimatter.tsx
@@ -1,4 +1,4 @@
-import { GameState } from '../common/GameStateInterface';
+import { GameState } from '../../common/GameStateInterface';
export default function DisplayAntimatter(props: { gameState: GameState }) {
const { gameState } = props;
diff --git a/src/components/GameResets.tsx b/src/components/GameResetBtns/GameResets.tsx
similarity index 95%
rename from src/components/GameResets.tsx
rename to src/components/GameResetBtns/GameResets.tsx
index cdb2364..71db95b 100644
--- a/src/components/GameResets.tsx
+++ b/src/components/GameResetBtns/GameResets.tsx
@@ -1,6 +1,6 @@
import { useEffect, useRef } from 'react';
-import { GameState } from '../common/GameStateInterface';
-import initialGameState from '../common/initialGameState';
+import { GameState } from '../../common/GameStateInterface';
+import initialGameState from '../../common/initialGameState';
export default function GameResets(props: { gameState: GameState; setGameState: any }) {
const { gameState, setGameState } = props;
diff --git a/src/components/TickSpeed.tsx b/src/components/Tickspeed/TickSpeed.tsx
similarity index 70%
rename from src/components/TickSpeed.tsx
rename to src/components/Tickspeed/TickSpeed.tsx
index 0111ad1..db66e73 100644
--- a/src/components/TickSpeed.tsx
+++ b/src/components/Tickspeed/TickSpeed.tsx
@@ -1,5 +1,7 @@
import { useRef, useEffect, useState } from 'react';
-import { GameState } from '../common/GameStateInterface';
+import { GameState } from '../../common/GameStateInterface';
+import { getCostForPurchaseQty } from './getCostForPurchaseQty';
+import { maxPurchaseQty } from './maxPurchaseQty';
export default function Tickspeed(props: {
gameState: GameState;
@@ -20,38 +22,32 @@ export default function Tickspeed(props: {
}));
};
- const getMaxPurchaseQtyRecursive = (price: number, antimatter: number, quantity = 0): number => {
- if (antimatter < price) {
- return quantity
- } else {
- return getMaxPurchaseQtyRecursive(price * 10, antimatter - price, quantity + 1);
- }
- };
+ const maxPurchasableQuantity = maxPurchaseQty({
+ cost: gameState.tickspeedPrice,
+ balance: gameState.antimatter,
+ qty: 0,
+ });
- const maxPurchasableQuantity = getMaxPurchaseQtyRecursive(
- gameState.tickspeedPrice,
- gameState.antimatter,
- 0
- );
-
- const getCostForPurchaseQty = (firstCost: number, quantity: number): number => {
+ /* const getCostForPurchaseQty = (firstCost: number, quantity: number): number => {
if (quantity == 1) {
return firstCost;
} else {
- return firstCost + getCostForPurchaseQty(firstCost * 10, quantity - 1);
- }
- }
+ return firstCost + getCostForPurchaseQty(firstCost * 10, quantity - 1);
+ }
+ }; */
const handleBuyMaxClick = () => {
- clockSpeedRef.current = clockSpeedRef.current * (1 - gameState.tickspeedDeceaseRate) ** maxPurchasableQuantity;
+ clockSpeedRef.current =
+ clockSpeedRef.current * (1 - gameState.tickspeedDeceaseRate) ** maxPurchasableQuantity;
setGameState((prevGS: GameState) => ({
...prevGS,
- antimatter: prevGS.antimatter - getCostForPurchaseQty(maxPurchasableQuantity, prevGS.tickspeedPrice),
+ antimatter:
+ prevGS.antimatter -
+ getCostForPurchaseQty(maxPurchasableQuantity, prevGS.tickspeedPrice),
tickspeedPrice: prevGS.tickspeedPrice * 10 ** maxPurchasableQuantity,
}));
};
-
return (
{`The current clockspeed is ${clockSpeedRef.current.toFixed(
diff --git a/src/components/Tickspeed/getCostForPurchaseQty.test.tsx b/src/components/Tickspeed/getCostForPurchaseQty.test.tsx
new file mode 100644
index 0000000..3a4c67f
--- /dev/null
+++ b/src/components/Tickspeed/getCostForPurchaseQty.test.tsx
@@ -0,0 +1,17 @@
+import { describe, expect, it } from 'vitest';
+import { getCostForPurchaseQty } from './getCostForPurchaseQty';
+
+describe('getCostForPurchaseQty', () => {
+ it('if nothing is bought, there is no cost increase', () => {
+ expect(getCostForPurchaseQty(10, 0)).toEqual(0);
+ });
+ it('if 1 Qty is bought, the cost is the initial cost', () => {
+ expect(getCostForPurchaseQty(10, 1)).toEqual(10);
+ });
+ it('if 2 Qty are bought, the cost is the initial cost + 10 *initial cost', () => {
+ expect(getCostForPurchaseQty(10, 2)).toEqual(110);
+ });
+ it('if 5 Qty are bought, the cost is the initial cost + 10 *initial cost + ... + 10^5*initial cost', () => {
+ expect(getCostForPurchaseQty(10, 2)).toEqual(111110);
+ });
+});
diff --git a/src/components/Tickspeed/getCostForPurchaseQty.tsx b/src/components/Tickspeed/getCostForPurchaseQty.tsx
new file mode 100644
index 0000000..295c8f4
--- /dev/null
+++ b/src/components/Tickspeed/getCostForPurchaseQty.tsx
@@ -0,0 +1,7 @@
+export const getCostForPurchaseQty = (firstCost: number, quantity: number): number => {
+ if (quantity === 0) return 0;
+ else if (quantity === 1) {
+ return firstCost;
+ } else return firstCost + getCostForPurchaseQty(firstCost * 10, quantity - 1)
+};
+
\ No newline at end of file
diff --git a/src/components/Tickspeed/maxPurchaseQty.test.ts b/src/components/Tickspeed/maxPurchaseQty.test.ts
new file mode 100644
index 0000000..3f03b45
--- /dev/null
+++ b/src/components/Tickspeed/maxPurchaseQty.test.ts
@@ -0,0 +1,18 @@
+import { maxPurchaseQty } from './maxPurchaseQty';
+import { describe, expect, it } from 'vitest';
+
+describe('maxPurchaseQty', () => {
+ it('return zero if we have no money', () => {
+ expect(maxPurchaseQty({ cost: 1234242, balance: 0, qty: 0 })).toEqual(0);
+ });
+ it('return one if we can afford only one', () => {
+ expect(maxPurchaseQty({ cost: 10, balance: 100, qty: 0 })).toEqual(1);
+ });
+
+ it('return 2 if we can afford only 2', () => {
+ expect(maxPurchaseQty({ cost: 10, balance: 110, qty: 0 })).toEqual(2);
+ });
+ it('return 3 if we can afford only 3', () => {
+ expect(maxPurchaseQty({ cost: 10, balance: 1110, qty: 0 })).toEqual(3);
+ });
+});
diff --git a/src/components/Tickspeed/maxPurchaseQty.ts b/src/components/Tickspeed/maxPurchaseQty.ts
new file mode 100644
index 0000000..4024c59
--- /dev/null
+++ b/src/components/Tickspeed/maxPurchaseQty.ts
@@ -0,0 +1,10 @@
+interface maxPurchaseQtyInterface {
+ cost: number;
+ balance: number;
+ qty: number;
+}
+
+export const maxPurchaseQty = ({ cost, balance, qty = 0 }: maxPurchaseQtyInterface): number => {
+ if (cost > balance) return qty;
+ else return maxPurchaseQty({ cost: cost * 10, balance: balance - cost, qty: qty + 1 });
+};
diff --git a/src/components/getMaxPurchaseQtyRecursive.test.ts b/src/components/getMaxPurchaseQtyRecursive.test.ts
deleted file mode 100644
index 0e45733..0000000
--- a/src/components/getMaxPurchaseQtyRecursive.test.ts
+++ /dev/null
@@ -1,13 +0,0 @@
-import { maxPurchaseQty } from "./getMaxPurchaseQtyRecursive";
-import {describe, expect, it} from "vitest";
-
-describe("getMaxPurchaseQtyRecursive ", ()=>{
-
- it('return zero if we have no money', () => {
- expect(maxPurchaseQty({cost: 1234242, balance: 0})).toEqual(0)
- })
- it('return one if we can afoard only one', () => {
- expect(maxPurchaseQty({ cost: 100, balance: 100})).toEqual(1)
- })
-
-});
diff --git a/src/components/getMaxPurchaseQtyRecursive.ts b/src/components/getMaxPurchaseQtyRecursive.ts
deleted file mode 100644
index cc9a8e3..0000000
--- a/src/components/getMaxPurchaseQtyRecursive.ts
+++ /dev/null
@@ -1,7 +0,0 @@
-
-
-export const maxPurchaseQty = ({cost, balance}) => {
-
- return 0;
-
-};
diff --git a/src/components/useSaveToLocalStorage.tsx b/src/customeHooks/useLocalStorage.tsx
similarity index 93%
rename from src/components/useSaveToLocalStorage.tsx
rename to src/customeHooks/useLocalStorage.tsx
index 67fba85..097d9ef 100644
--- a/src/components/useSaveToLocalStorage.tsx
+++ b/src/customeHooks/useLocalStorage.tsx
@@ -1,7 +1,7 @@
import { useEffect, useRef } from 'react';
import { Dim, GameState } from '../common/GameStateInterface';
-export function useSaveToLocalStorage(gameState: GameState, setGameState) {
+export function useLocalStorage(gameState: GameState, setGameState:Function):void {
const saveLocStorageRef = useRef(-1);
const displayLocStorageRef = useRef(-1);
@@ -21,6 +21,7 @@ export function useSaveToLocalStorage(gameState: GameState, setGameState) {
saveDateRecursive(gameState);
}, [gameState]);
+
// this prints the saved object from local storage. It is just for dev. No final purpose
/* useEffect(() => {
From 6d355a00d4f84d9723ee3f5872cfcd2be7e5d3bc Mon Sep 17 00:00:00 2001
From: Michael Urich <80188367+mturich@users.noreply.github.com>
Date: Mon, 11 Jul 2022 13:43:18 +0200
Subject: [PATCH 2/7] changed strucutre of the project
---
src/components/App.tsx | 13 +++--
src/components/Tickspeed/TickSpeed.tsx | 49 ++++++++-----------
.../Tickspeed/calcMaxPurchasableQty.test.ts | 19 +++++++
.../Tickspeed/calcMaxPurchasableQty.ts | 10 ++++
.../Tickspeed/maxPurchaseQty.test.ts | 18 -------
src/components/Tickspeed/maxPurchaseQty.ts | 10 ----
6 files changed, 55 insertions(+), 64 deletions(-)
create mode 100644 src/components/Tickspeed/calcMaxPurchasableQty.test.ts
create mode 100644 src/components/Tickspeed/calcMaxPurchasableQty.ts
delete mode 100644 src/components/Tickspeed/maxPurchaseQty.test.ts
delete mode 100644 src/components/Tickspeed/maxPurchaseQty.ts
diff --git a/src/components/App.tsx b/src/components/App.tsx
index 5c93dfd..e32e68b 100644
--- a/src/components/App.tsx
+++ b/src/components/App.tsx
@@ -3,19 +3,18 @@ import '../styles/App.css';
import Dimension from './Dimention/Dimension';
import GameResets from './GameResetBtns/GameResets';
import Tickspeed from './Tickspeed/TickSpeed';
+import DisplayAntimatter from './DisplayAntimatter/DisplayAntimatter';
+import initialGameState from '../common/initialGameState';
import { GameState, Dim } from '../common/GameStateInterface';
-import initialGameState from '../common/initialGameState';
-import DisplayAntimatter from './DisplayAntimatter/DisplayAntimatter';
import { useLocalStorage } from '../customeHooks/useLocalStorage';
function App() {
const [gameState, setGameState] = useState(() =>
JSON.parse(localStorage.getItem('data') || initialGameState)
);
- /* JSON.parse(localStorage.getItem('data')) */
const timerExpiredCallback = useRef(() => {});
- const clockSpeedRef = useRef(2000);
+ const tickspeedRef = useRef(2000);
const timerIdRef = useRef(-1);
useLocalStorage(gameState, setGameState);
@@ -41,7 +40,7 @@ function App() {
timerIdRef.current = setTimeout(() => {
timerExpiredCallback.current();
startTimer();
- }, clockSpeedRef.current);
+ }, tickspeedRef.current);
};
startTimer();
@@ -56,7 +55,7 @@ function App() {
+ tickspeedRef={tickspeedRef}>
{`First Dimension Cost: ${gameState.dims[0].dimPrice}`}
@@ -98,7 +97,7 @@ function App() {
{`Eight Dimension Cost: ${gameState.dims[2].dimPrice}`}
)}
-
+
diff --git a/src/components/Tickspeed/TickSpeed.tsx b/src/components/Tickspeed/TickSpeed.tsx
index db66e73..42c412f 100644
--- a/src/components/Tickspeed/TickSpeed.tsx
+++ b/src/components/Tickspeed/TickSpeed.tsx
@@ -1,56 +1,47 @@
import { useRef, useEffect, useState } from 'react';
import { GameState } from '../../common/GameStateInterface';
import { getCostForPurchaseQty } from './getCostForPurchaseQty';
-import { maxPurchaseQty } from './maxPurchaseQty';
+import { calcMaxPurchasableQty } from './calcMaxPurchasableQty';
export default function Tickspeed(props: {
gameState: GameState;
- setGameState: any;
- clockSpeedRef: any;
+ setGameState: Function;
+ tickspeedRef: any;
}) {
- const { gameState, setGameState, clockSpeedRef } = props;
+ const { gameState, setGameState, tickspeedRef } = props;
const [buyMax, setBuyMax] = useState(
Math.log10(gameState.antimatter / gameState.tickspeedPrice)
);
- // const maxPossibleBuys = useRef(~~Math.log10(gameState.antimatter / gameState.tickspeedPrice));
+
+ // calculte the maximal purchasable
+ const maxPurchaseQtys = calcMaxPurchasableQty({
+ cost: gameState.tickspeedPrice,
+ balance: gameState.antimatter,
+ qty: 0,
+ });
+ const purchasePrice = getCostForPurchaseQty(gameState.tickspeedPrice, maxPurchaseQtys);
+
const handleTickBtnClick = () => {
- clockSpeedRef.current = clockSpeedRef.current * (1 - gameState.tickspeedDeceaseRate);
+ tickspeedRef.current = tickspeedRef.current * (1 - gameState.tickspeedDeceaseRate);
setGameState((prevGS: GameState) => ({
...prevGS,
antimatter: prevGS.antimatter - prevGS.tickspeedPrice,
tickspeedPrice: prevGS.tickspeedPrice * 10,
}));
};
-
- const maxPurchasableQuantity = maxPurchaseQty({
- cost: gameState.tickspeedPrice,
- balance: gameState.antimatter,
- qty: 0,
- });
-
- /* const getCostForPurchaseQty = (firstCost: number, quantity: number): number => {
- if (quantity == 1) {
- return firstCost;
- } else {
- return firstCost + getCostForPurchaseQty(firstCost * 10, quantity - 1);
- }
- }; */
-
const handleBuyMaxClick = () => {
- clockSpeedRef.current =
- clockSpeedRef.current * (1 - gameState.tickspeedDeceaseRate) ** maxPurchasableQuantity;
+ tickspeedRef.current =
+ tickspeedRef.current * (1 - gameState.tickspeedDeceaseRate) ** maxPurchaseQtys;
setGameState((prevGS: GameState) => ({
...prevGS,
- antimatter:
- prevGS.antimatter -
- getCostForPurchaseQty(maxPurchasableQuantity, prevGS.tickspeedPrice),
- tickspeedPrice: prevGS.tickspeedPrice * 10 ** maxPurchasableQuantity,
+ antimatter: prevGS.antimatter - purchasePrice,
+ tickspeedPrice: prevGS.tickspeedPrice * 10 ** maxPurchaseQtys,
}));
};
return (
-
{`The current clockspeed is ${clockSpeedRef.current.toFixed(
+
{`The current clockspeed is ${tickspeedRef.current.toFixed(
0
)} ms. Reduce the tickspeed by ${gameState.tickspeedDeceaseRate * 100}%.`}
@@ -64,7 +55,7 @@ export default function Tickspeed(props: {
className='btn'
onClick={handleBuyMaxClick}
disabled={gameState.antimatter < gameState.tickspeedPrice}>
- Buy Max ({maxPurchasableQuantity})
+ Buy Max ({maxPurchaseQtys})
diff --git a/src/components/Tickspeed/calcMaxPurchasableQty.test.ts b/src/components/Tickspeed/calcMaxPurchasableQty.test.ts
new file mode 100644
index 0000000..862afff
--- /dev/null
+++ b/src/components/Tickspeed/calcMaxPurchasableQty.test.ts
@@ -0,0 +1,19 @@
+import { calcMaxPurchasableQty } from './calcMaxPurchasableQty';
+import { describe, expect, it } from 'vitest';
+
+describe('maxPurchaseQty', () => {
+ it('return zero if we have no money', () => {
+ expect(calcMaxPurchasableQty({ cost: 1234242, balance: 0, qty: 0 })).toEqual(0);
+ });
+ it('return one if we can afford only one', () => {
+ expect(calcMaxPurchasableQty({ cost: 10, balance: 100, qty: 0 })).toEqual(1);
+ });
+
+ it('return 2 if we can afford only 2', () => {
+ expect(calcMaxPurchasableQty({ cost: 10, balance: 110, qty: 0 })).toEqual(2);
+ });
+ it('return 3 if we can afford only 3', () => {
+ expect(calcMaxPurchasableQty
+ ({ cost: 10, balance: 1110, qty: 0 })).toEqual(3);
+ });
+});
diff --git a/src/components/Tickspeed/calcMaxPurchasableQty.ts b/src/components/Tickspeed/calcMaxPurchasableQty.ts
new file mode 100644
index 0000000..95f23c0
--- /dev/null
+++ b/src/components/Tickspeed/calcMaxPurchasableQty.ts
@@ -0,0 +1,10 @@
+interface calcMaxPurchasableQtyInterface {
+ cost: number;
+ balance: number;
+ qty: number;
+}
+
+export const calcMaxPurchasableQty = ({ cost, balance, qty = 0 }: calcMaxPurchasableQtyInterface): number => {
+ if (cost > balance) return qty;
+ else return calcMaxPurchasableQty({ cost: cost * 10, balance: balance - cost, qty: qty + 1 });
+};
diff --git a/src/components/Tickspeed/maxPurchaseQty.test.ts b/src/components/Tickspeed/maxPurchaseQty.test.ts
deleted file mode 100644
index 3f03b45..0000000
--- a/src/components/Tickspeed/maxPurchaseQty.test.ts
+++ /dev/null
@@ -1,18 +0,0 @@
-import { maxPurchaseQty } from './maxPurchaseQty';
-import { describe, expect, it } from 'vitest';
-
-describe('maxPurchaseQty', () => {
- it('return zero if we have no money', () => {
- expect(maxPurchaseQty({ cost: 1234242, balance: 0, qty: 0 })).toEqual(0);
- });
- it('return one if we can afford only one', () => {
- expect(maxPurchaseQty({ cost: 10, balance: 100, qty: 0 })).toEqual(1);
- });
-
- it('return 2 if we can afford only 2', () => {
- expect(maxPurchaseQty({ cost: 10, balance: 110, qty: 0 })).toEqual(2);
- });
- it('return 3 if we can afford only 3', () => {
- expect(maxPurchaseQty({ cost: 10, balance: 1110, qty: 0 })).toEqual(3);
- });
-});
diff --git a/src/components/Tickspeed/maxPurchaseQty.ts b/src/components/Tickspeed/maxPurchaseQty.ts
deleted file mode 100644
index 4024c59..0000000
--- a/src/components/Tickspeed/maxPurchaseQty.ts
+++ /dev/null
@@ -1,10 +0,0 @@
-interface maxPurchaseQtyInterface {
- cost: number;
- balance: number;
- qty: number;
-}
-
-export const maxPurchaseQty = ({ cost, balance, qty = 0 }: maxPurchaseQtyInterface): number => {
- if (cost > balance) return qty;
- else return maxPurchaseQty({ cost: cost * 10, balance: balance - cost, qty: qty + 1 });
-};
From 9b18b0b5c549064620fe18abdb49cfccf7791900 Mon Sep 17 00:00:00 2001
From: Michael Urich <80188367+mturich@users.noreply.github.com>
Date: Mon, 11 Jul 2022 14:43:42 +0200
Subject: [PATCH 3/7] first Refactoring for useReducer; Dimension works
---
src/common/GameStateInterface.ts | 2 +-
src/components/App.tsx | 137 ++++++++++++++++---------
src/components/Dimention/Dimension.tsx | 44 ++------
3 files changed, 99 insertions(+), 84 deletions(-)
diff --git a/src/common/GameStateInterface.ts b/src/common/GameStateInterface.ts
index a14c3c7..8d988f4 100644
--- a/src/common/GameStateInterface.ts
+++ b/src/common/GameStateInterface.ts
@@ -20,6 +20,6 @@ export interface Dim {
export type DimProps = {
nthDim: number;
gs: GameState;
- setGameState: (fn: (gameState: GameState) => void) => void;
+ dispatch: Function;
children: string;
};
diff --git a/src/components/App.tsx b/src/components/App.tsx
index e32e68b..e02b7bd 100644
--- a/src/components/App.tsx
+++ b/src/components/App.tsx
@@ -1,4 +1,4 @@
-import { useState, useEffect, useRef } from 'react';
+import { useState, useEffect, useRef, useReducer } from 'react';
import '../styles/App.css';
import Dimension from './Dimention/Dimension';
import GameResets from './GameResetBtns/GameResets';
@@ -9,31 +9,74 @@ import initialGameState from '../common/initialGameState';
import { GameState, Dim } from '../common/GameStateInterface';
import { useLocalStorage } from '../customeHooks/useLocalStorage';
+export const ACTIONS = {
+ TIMER_CALLBACK: 'TIMER_CALLBACK',
+ UPDATE_DIM: 'UPDATE_DIM',
+ UPDATE_10TH_DIM: 'UPDATE_10TH_DIM',
+};
+
+function reducer(state: GameState, action: { type: string; payload?: any }) {
+ switch (action.type) {
+ case ACTIONS.TIMER_CALLBACK:
+ return {
+ ...state,
+ antimatter: state.antimatter + state.dims[0].dimCount * state.dims[0].dimFactor,
+ dims: state.dims.map((dim: Dim, index: number) => {
+ return {
+ ...dim,
+ dimCount:
+ dim.dimCount +
+ ((state.dims[index + 1]?.dimCount ?? 0) *
+ (state.dims[index + 1]?.dimFactor ?? 0)) /
+ Math.pow(10, index + 1),
+ };
+ }),
+ };
+ case ACTIONS.UPDATE_DIM:
+ return {
+ ...state,
+ antimatter:
+ state.antimatter -
+ state.dims[action.payload.nthDim].dimPrice * action.payload.quantity,
+ dims: state.dims.map((dim: Dim) => {
+ if (dim.nthDim !== action.payload.nthDim) return dim;
+ return {
+ ...dim,
+ dimCount: dim.dimCount + action.payload.quantity,
+ dimFactorCount: dim.dimFactorCount + action.payload.quantity,
+ };
+ }),
+ };
+ case ACTIONS.UPDATE_10TH_DIM:
+ return {
+ ...state,
+ dims: state.dims.map((dim: Dim) => {
+ if (dim.nthDim !== action.payload.nthDim) return dim;
+ return {
+ ...dim,
+ dimPrice: dim.dimPrice * 10,
+ dimFactor: dim.dimFactor * 2,
+ dimFactorCount: 0,
+ };
+ }),
+ };
+ default:
+ return state;
+ }
+}
+
function App() {
- const [gameState, setGameState] = useState(() =>
+ const [state, dispatch] = useReducer(
+ reducer,
JSON.parse(localStorage.getItem('data') || initialGameState)
);
+
const timerExpiredCallback = useRef(() => {});
const tickspeedRef = useRef(2000);
const timerIdRef = useRef(-1);
- useLocalStorage(gameState, setGameState);
+ useLocalStorage(state, dispatch);
- timerExpiredCallback.current = () => {
- setGameState((prevGS: GameState) => ({
- ...prevGS,
- antimatter: prevGS.antimatter + prevGS.dims[0].dimCount * prevGS.dims[0].dimFactor,
- dims: gameState.dims.map((dim: Dim, index: number) => {
- return {
- ...dim,
- dimCount:
- dim.dimCount +
- ((gameState.dims[index + 1]?.dimCount ?? 0) *
- (gameState.dims[index + 1]?.dimFactor ?? 0)) /
- Math.pow(10, index + 1),
- };
- }),
- }));
- };
+ timerExpiredCallback.current = () => dispatch({ type: ACTIONS.TIMER_CALLBACK });
useEffect(() => {
const startTimer = () => {
@@ -50,58 +93,58 @@ function App() {
return (
-
-
+
+ {/*
+ gameState={state}
+ dispatch={dispatch}
+ tickspeedRef={tickspeedRef}> */}
-
- {`First Dimension Cost: ${gameState.dims[0].dimPrice}`}
+
+ {`First Dimension Cost: ${state.dims[0].dimPrice}`}
-
- {`Second Dimension Cost: ${gameState.dims[1].dimPrice}`}
+
+ {`Second Dimension Cost: ${state.dims[1].dimPrice}`}
{
//the 3. dimension must be unlocked
}
- {gameState.resetGameCounter > 2 && (
-
- {`Third Dimension Cost: ${gameState.dims[2].dimPrice}`}
+ {state.resetGameCounter > 2 && (
+
+ {`Third Dimension Cost: ${state.dims[2].dimPrice}`}
)}
- {gameState.resetGameCounter > 3 && (
-
- {`Forth Dimension Cost: ${gameState.dims[2].dimPrice}`}
+ {state.resetGameCounter > 3 && (
+
+ {`Forth Dimension Cost: ${state.dims[2].dimPrice}`}
)}
- {gameState.resetGameCounter > 4 && (
-
- {`Fifth Dimension Cost: ${gameState.dims[2].dimPrice}`}
+ {state.resetGameCounter > 4 && (
+
+ {`Fifth Dimension Cost: ${state.dims[2].dimPrice}`}
)}
- {gameState.resetGameCounter > 5 && (
-
- {`Sixth Dimension Cost: ${gameState.dims[2].dimPrice}`}
+ {state.resetGameCounter > 5 && (
+
+ {`Sixth Dimension Cost: ${state.dims[2].dimPrice}`}
)}
- {gameState.resetGameCounter > 6 && (
-
- {`Seventh Dimension Cost: ${gameState.dims[2].dimPrice}`}
+ {state.resetGameCounter > 6 && (
+
+ {`Seventh Dimension Cost: ${state.dims[2].dimPrice}`}
)}
- {gameState.resetGameCounter > 7 && (
-
- {`Eight Dimension Cost: ${gameState.dims[2].dimPrice}`}
+ {state.resetGameCounter > 7 && (
+
+ {`Eight Dimension Cost: ${state.dims[2].dimPrice}`}
)}
-
+ {/* */}
);
}
diff --git a/src/components/Dimention/Dimension.tsx b/src/components/Dimention/Dimension.tsx
index c195cf5..59a2913 100644
--- a/src/components/Dimention/Dimension.tsx
+++ b/src/components/Dimention/Dimension.tsx
@@ -1,49 +1,21 @@
-import { GameState, DimProps, Dim } from '../../common/GameStateInterface';
+import { DimProps } from '../../common/GameStateInterface';
+import { ACTIONS } from '../App';
export default function Dimension(props: DimProps) {
- const { nthDim, gs, setGameState } = props;
+ const { nthDim, gs, dispatch } = props;
const handleDimBuy = (quantity: number) => {
- const newDim = [gs.dims[nthDim].dimCount + quantity];
-
if (gs.antimatter >= gs.dims[nthDim].dimPrice) {
- /*
- setDimCount(dimCount => dimCount + quantity);
- setAntimatter(prevValue => prevValue - price * quantity);
- setDimFactorCount(prevCount => prevCount + 1); */
- setGameState((prevGS: GameState) => ({
- ...prevGS,
- antimatter: prevGS.antimatter - prevGS.dims[nthDim].dimPrice * quantity,
- dims: prevGS.dims.map((dim: Dim, index: number) => {
- if (dim.nthDim !== nthDim) return dim;
- return {
- ...dim,
- dimCount: dim.dimCount + quantity,
- dimFactorCount: dim.dimFactorCount + quantity,
- };
- }),
- }));
+ dispatch({ type: ACTIONS.UPDATE_DIM, payload: { nthDim: nthDim, quantity: quantity } });
}
if (
((gs.dims[nthDim].dimCount + 1) % 10 === 0 && gs.dims[nthDim].dimCount > 1) ||
quantity === 10
) {
- /*
- setPrice(prevPrice => prevPrice * 10);
- setFactor(prevFactor => prevFactor * 2)
- setDimFactorCount(0) */
- setGameState((prevGS: GameState) => ({
- ...prevGS,
- dims: prevGS.dims.map((dim: Dim, index: number) => {
- if (dim.nthDim !== nthDim) return dim;
- return {
- ...dim,
- dimPrice: dim.dimPrice * 10,
- dimFactor: dim.dimFactor * 2,
- dimFactorCount: 0,
- };
- }),
- }));
+ dispatch({
+ type: ACTIONS.UPDATE_10TH_DIM,
+ payload: { nthDim: nthDim, quantity: quantity },
+ });
}
};
From 99ed941336603cb063a175633a54939f6e08443e Mon Sep 17 00:00:00 2001
From: Michael Urich <80188367+mturich@users.noreply.github.com>
Date: Mon, 11 Jul 2022 15:07:01 +0200
Subject: [PATCH 4/7] useReducer implementation finished
---
src/common/reducer.tsx | 98 +++++++++++++++++++++
src/components/App.tsx | 66 ++------------
src/components/Dimention/Dimension.tsx | 2 +-
src/components/GameResetBtns/GameResets.tsx | 55 +++++-------
src/components/Tickspeed/TickSpeed.tsx | 49 ++++-------
5 files changed, 145 insertions(+), 125 deletions(-)
create mode 100644 src/common/reducer.tsx
diff --git a/src/common/reducer.tsx b/src/common/reducer.tsx
new file mode 100644
index 0000000..43171c8
--- /dev/null
+++ b/src/common/reducer.tsx
@@ -0,0 +1,98 @@
+import { Dim, GameState } from './GameStateInterface';
+import initialGameState from './initialGameState';
+
+export const ACTIONS = {
+ TIMER_CALLBACK: 'TIMER_CALLBACK',
+ UPDATE_DIM: 'UPDATE_DIM',
+ UPDATE_10TH_DIM: 'UPDATE_10TH_DIM',
+ UPDATE_TICKSPEED_ONCE: 'UPDATE_TICKSPEED_ONCE',
+ UPDATE_TICKSPEED_MAX: 'UPDATE_TICKSPEED_MAX',
+ RESET_TO_UNLOCK_DIM: 'RESET_TO_UNLOCK_DIM',
+ RESET_TO_UNLOCK_TICKSPEED: 'RESET_TO_UNLOCK_TICKSPEED',
+ RESET_TO_INITIAL_VALUES: 'RESET_TO_INITIAL_VALUES',
+};
+
+export function reducer(state: GameState, action: { type: string; payload?: any }) {
+ switch (action.type) {
+ case ACTIONS.TIMER_CALLBACK:
+ return {
+ ...state,
+ antimatter: state.antimatter + state.dims[0].dimCount * state.dims[0].dimFactor,
+ dims: state.dims.map((dim: Dim, index: number) => {
+ return {
+ ...dim,
+ dimCount:
+ dim.dimCount +
+ ((state.dims[index + 1]?.dimCount ?? 0) *
+ (state.dims[index + 1]?.dimFactor ?? 0)) /
+ Math.pow(10, index + 1),
+ };
+ }),
+ };
+
+ case ACTIONS.UPDATE_DIM:
+ return {
+ ...state,
+ antimatter:
+ state.antimatter -
+ state.dims[action.payload.nthDim].dimPrice * action.payload.quantity,
+ dims: state.dims.map((dim: Dim) => {
+ if (dim.nthDim !== action.payload.nthDim) return dim;
+ return {
+ ...dim,
+ dimCount: dim.dimCount + action.payload.quantity,
+ dimFactorCount: dim.dimFactorCount + action.payload.quantity,
+ };
+ }),
+ };
+
+ case ACTIONS.UPDATE_10TH_DIM:
+ return {
+ ...state,
+ dims: state.dims.map((dim: Dim) => {
+ if (dim.nthDim !== action.payload.nthDim) return dim;
+ return {
+ ...dim,
+ dimPrice: dim.dimPrice * 10,
+ dimFactor: dim.dimFactor * 2,
+ dimFactorCount: 0,
+ };
+ }),
+ };
+
+ case ACTIONS.UPDATE_TICKSPEED_ONCE:
+ return {
+ ...state,
+ antimatter: state.antimatter - state.tickspeedPrice,
+ tickspeedPrice: state.tickspeedPrice * 10,
+ };
+ case ACTIONS.UPDATE_TICKSPEED_MAX:
+ return {
+ ...state,
+ antimatter: state.antimatter - action.payload.purchasePrice,
+ tickspeedPrice: state.tickspeedPrice * 10 ** action.payload.maxPurchaseQtys,
+ };
+
+ case ACTIONS.RESET_TO_UNLOCK_DIM:
+ return {
+ ...JSON.parse(initialGameState),
+ galaxyCounter: state.galaxyCounter,
+ resetGameCounter: state.resetGameCounter + 1,
+ lastSavedTime: state.lastSavedTime,
+ };
+
+ case ACTIONS.RESET_TO_UNLOCK_TICKSPEED:
+ return {
+ ...JSON.parse(initialGameState),
+ galaxyCounter: state.galaxyCounter + 1,
+ tickspeedDeceaseRate: 0.12,
+ resetGameCounter: state.resetGameCounter,
+ lastSavedTime: state.lastSavedTime,
+ };
+
+ case ACTIONS.RESET_TO_INITIAL_VALUES:
+ return JSON.parse(initialGameState);
+ default:
+ return state;
+ }
+}
diff --git a/src/components/App.tsx b/src/components/App.tsx
index e02b7bd..189e245 100644
--- a/src/components/App.tsx
+++ b/src/components/App.tsx
@@ -6,64 +6,8 @@ import Tickspeed from './Tickspeed/TickSpeed';
import DisplayAntimatter from './DisplayAntimatter/DisplayAntimatter';
import initialGameState from '../common/initialGameState';
-import { GameState, Dim } from '../common/GameStateInterface';
import { useLocalStorage } from '../customeHooks/useLocalStorage';
-
-export const ACTIONS = {
- TIMER_CALLBACK: 'TIMER_CALLBACK',
- UPDATE_DIM: 'UPDATE_DIM',
- UPDATE_10TH_DIM: 'UPDATE_10TH_DIM',
-};
-
-function reducer(state: GameState, action: { type: string; payload?: any }) {
- switch (action.type) {
- case ACTIONS.TIMER_CALLBACK:
- return {
- ...state,
- antimatter: state.antimatter + state.dims[0].dimCount * state.dims[0].dimFactor,
- dims: state.dims.map((dim: Dim, index: number) => {
- return {
- ...dim,
- dimCount:
- dim.dimCount +
- ((state.dims[index + 1]?.dimCount ?? 0) *
- (state.dims[index + 1]?.dimFactor ?? 0)) /
- Math.pow(10, index + 1),
- };
- }),
- };
- case ACTIONS.UPDATE_DIM:
- return {
- ...state,
- antimatter:
- state.antimatter -
- state.dims[action.payload.nthDim].dimPrice * action.payload.quantity,
- dims: state.dims.map((dim: Dim) => {
- if (dim.nthDim !== action.payload.nthDim) return dim;
- return {
- ...dim,
- dimCount: dim.dimCount + action.payload.quantity,
- dimFactorCount: dim.dimFactorCount + action.payload.quantity,
- };
- }),
- };
- case ACTIONS.UPDATE_10TH_DIM:
- return {
- ...state,
- dims: state.dims.map((dim: Dim) => {
- if (dim.nthDim !== action.payload.nthDim) return dim;
- return {
- ...dim,
- dimPrice: dim.dimPrice * 10,
- dimFactor: dim.dimFactor * 2,
- dimFactorCount: 0,
- };
- }),
- };
- default:
- return state;
- }
-}
+import { ACTIONS, reducer } from '../common/reducer';
function App() {
const [state, dispatch] = useReducer(
@@ -94,11 +38,11 @@ function App() {
return (
- {/*
+
*/}
+ tickspeedRef={tickspeedRef}>
{`First Dimension Cost: ${state.dims[0].dimPrice}`}
@@ -144,7 +88,7 @@ function App() {
- {/* */}
+
);
}
diff --git a/src/components/Dimention/Dimension.tsx b/src/components/Dimention/Dimension.tsx
index 59a2913..0d099a4 100644
--- a/src/components/Dimention/Dimension.tsx
+++ b/src/components/Dimention/Dimension.tsx
@@ -1,5 +1,5 @@
import { DimProps } from '../../common/GameStateInterface';
-import { ACTIONS } from '../App';
+import { ACTIONS } from '../../common/reducer';
export default function Dimension(props: DimProps) {
const { nthDim, gs, dispatch } = props;
diff --git a/src/components/GameResetBtns/GameResets.tsx b/src/components/GameResetBtns/GameResets.tsx
index 71db95b..f68a4b2 100644
--- a/src/components/GameResetBtns/GameResets.tsx
+++ b/src/components/GameResetBtns/GameResets.tsx
@@ -1,60 +1,49 @@
import { useEffect, useRef } from 'react';
import { GameState } from '../../common/GameStateInterface';
import initialGameState from '../../common/initialGameState';
+import { ACTIONS } from '../../common/reducer';
-export default function GameResets(props: { gameState: GameState; setGameState: any }) {
- const { gameState, setGameState } = props;
- const resetGameCounterRef = useRef(gameState.resetGameCounter);
+export default function GameResets(props: { gs: GameState; dispatch: Function }) {
+ const { gs, dispatch } = props;
+ const resetGameCounterRef = useRef(gs.resetGameCounter);
useEffect(() => {
- resetGameCounterRef.current = gameState.resetGameCounter;
- }, [gameState.resetGameCounter]);
+ resetGameCounterRef.current = gs.resetGameCounter;
+ }, [gs.resetGameCounter]);
const handleResetGameClick = () => {
- setGameState((prevGS: GameState) => ({
- ...JSON.parse(initialGameState),
- galaxyCounter: prevGS.galaxyCounter,
- resetGameCounter: prevGS.resetGameCounter + 1,
- lastSavedTime: prevGS.lastSavedTime,
- }));
+ dispatch({ type: ACTIONS.RESET_TO_UNLOCK_DIM });
};
const handleGalaxyBtn = () => {
- setGameState((prevGS: GameState) => ({
- ...JSON.parse(initialGameState),
- galaxyCounter: prevGS.galaxyCounter + 1,
- tickspeedDeceaseRate: 0.12,
- resetGameCounter: prevGS.resetGameCounter,
- lastSavedTime: prevGS.lastSavedTime,
- }));
+ dispatch({ type: ACTIONS.RESET_TO_UNLOCK_TICKSPEED });
};
const disableResetBtn = () => {
- if (
- gameState.resetGameCounter < 7 &&
- gameState.dims[gameState.resetGameCounter - 1].dimCount < 20
- )
- return true;
+ if (gs.resetGameCounter < 7 && gs.dims[gs.resetGameCounter - 1].dimCount < 20) return true;
else return false;
};
return (
<>
-
{`Dimension Shift (${gameState.resetGameCounter}) `}
-
{`requires 20 ${gameState.resetGameCounter}. Dimension `}
-
-
{`Antimatter Galaxies (${gameState.galaxyCounter})`}
+
{`Antimatter Galaxies (${gs.galaxyCounter})`}
{`requires 80 8. Dimension `}
-
+
Increase Tickspeed bump to 12%
@@ -63,7 +52,7 @@ export default function GameResets(props: { gameState: GameState; setGameState:
{`resets everything`}
setGameState(JSON.parse(initialGameState))}
+ onClick={() => dispatch({ type: ACTIONS.RESET_TO_INITIAL_VALUES })}
disabled={false}>
Resets game
diff --git a/src/components/Tickspeed/TickSpeed.tsx b/src/components/Tickspeed/TickSpeed.tsx
index 42c412f..a8a10cc 100644
--- a/src/components/Tickspeed/TickSpeed.tsx
+++ b/src/components/Tickspeed/TickSpeed.tsx
@@ -1,60 +1,49 @@
-import { useRef, useEffect, useState } from 'react';
+import { useState } from 'react';
import { GameState } from '../../common/GameStateInterface';
import { getCostForPurchaseQty } from './getCostForPurchaseQty';
import { calcMaxPurchasableQty } from './calcMaxPurchasableQty';
+import { ACTIONS } from '../../common/reducer';
-export default function Tickspeed(props: {
- gameState: GameState;
- setGameState: Function;
- tickspeedRef: any;
-}) {
- const { gameState, setGameState, tickspeedRef } = props;
- const [buyMax, setBuyMax] = useState(
- Math.log10(gameState.antimatter / gameState.tickspeedPrice)
- );
+export default function Tickspeed(props: { gs: GameState; dispatch: Function; tickspeedRef: any }) {
+ const { gs, dispatch, tickspeedRef } = props;
// calculte the maximal purchasable
const maxPurchaseQtys = calcMaxPurchasableQty({
- cost: gameState.tickspeedPrice,
- balance: gameState.antimatter,
+ cost: gs.tickspeedPrice,
+ balance: gs.antimatter,
qty: 0,
});
- const purchasePrice = getCostForPurchaseQty(gameState.tickspeedPrice, maxPurchaseQtys);
-
+ const purchasePrice = getCostForPurchaseQty(gs.tickspeedPrice, maxPurchaseQtys);
+
const handleTickBtnClick = () => {
- tickspeedRef.current = tickspeedRef.current * (1 - gameState.tickspeedDeceaseRate);
- setGameState((prevGS: GameState) => ({
- ...prevGS,
- antimatter: prevGS.antimatter - prevGS.tickspeedPrice,
- tickspeedPrice: prevGS.tickspeedPrice * 10,
- }));
+ tickspeedRef.current = tickspeedRef.current * (1 - gs.tickspeedDeceaseRate);
+ dispatch({ type: ACTIONS.UPDATE_TICKSPEED_ONCE });
};
const handleBuyMaxClick = () => {
tickspeedRef.current =
- tickspeedRef.current * (1 - gameState.tickspeedDeceaseRate) ** maxPurchaseQtys;
- setGameState((prevGS: GameState) => ({
- ...prevGS,
- antimatter: prevGS.antimatter - purchasePrice,
- tickspeedPrice: prevGS.tickspeedPrice * 10 ** maxPurchaseQtys,
- }));
+ tickspeedRef.current * (1 - gs.tickspeedDeceaseRate) ** maxPurchaseQtys;
+ dispatch({
+ type: ACTIONS.UPDATE_TICKSPEED_MAX,
+ payload: { maxPurchaseQtys: maxPurchaseQtys, purchasePrice: purchasePrice },
+ });
};
return (
{`The current clockspeed is ${tickspeedRef.current.toFixed(
0
- )} ms. Reduce the tickspeed by ${gameState.tickspeedDeceaseRate * 100}%.`}
+ )} ms. Reduce the tickspeed by ${gs.tickspeedDeceaseRate * 100}%.`}
- Cost one time: {gameState.tickspeedPrice}{' '}
+ disabled={gs.antimatter - gs.tickspeedPrice <= 0}>
+ Cost one time: {gs.tickspeedPrice}{' '}
+ disabled={gs.antimatter < gs.tickspeedPrice}>
Buy Max ({maxPurchaseQtys})
From 60bb079a90e7561730499ed35083799bdbf681b8 Mon Sep 17 00:00:00 2001
From: Michael Urich <80188367+mturich@users.noreply.github.com>
Date: Tue, 12 Jul 2022 14:09:23 +0200
Subject: [PATCH 5/7] bugs solved, notification when game is saved
---
package.json | 1 +
src/common/initialGameState.ts | 2 +-
src/common/reducer.tsx | 13 +-
src/components/App.tsx | 23 +++-
src/components/GameResetBtns/GameResets.tsx | 33 +++--
src/components/Tickspeed/TickSpeed.tsx | 2 +-
src/customeHooks/useLocalStorage.tsx | 26 +---
src/styles/App.css | 128 +++++++++++++++++++-
yarn.lock | 5 +
9 files changed, 190 insertions(+), 43 deletions(-)
diff --git a/package.json b/package.json
index aec91fa..25edcaf 100644
--- a/package.json
+++ b/package.json
@@ -9,6 +9,7 @@
"test": "vitest"
},
"dependencies": {
+ "clsx": "^1.2.1",
"react": "^18.0.0",
"react-dom": "^18.0.0"
},
diff --git a/src/common/initialGameState.ts b/src/common/initialGameState.ts
index 08e6dba..79be01f 100644
--- a/src/common/initialGameState.ts
+++ b/src/common/initialGameState.ts
@@ -6,7 +6,7 @@ let initialGameState: GameState = {
tickspeedDeceaseRate: 0.11,
resetGameCounter: 2,
galaxyCounter: 0,
- lastSavedTime: 0,
+ lastSavedTime: Date.now(),
dims: [
{
nthDim: 0,
diff --git a/src/common/reducer.tsx b/src/common/reducer.tsx
index 43171c8..0b510b5 100644
--- a/src/common/reducer.tsx
+++ b/src/common/reducer.tsx
@@ -10,6 +10,8 @@ export const ACTIONS = {
RESET_TO_UNLOCK_DIM: 'RESET_TO_UNLOCK_DIM',
RESET_TO_UNLOCK_TICKSPEED: 'RESET_TO_UNLOCK_TICKSPEED',
RESET_TO_INITIAL_VALUES: 'RESET_TO_INITIAL_VALUES',
+ POP_UP: 'POP_UP',
+ SAVE_DATA: 'SAVE_DATA',
};
export function reducer(state: GameState, action: { type: string; payload?: any }) {
@@ -77,6 +79,7 @@ export function reducer(state: GameState, action: { type: string; payload?: any
return {
...JSON.parse(initialGameState),
galaxyCounter: state.galaxyCounter,
+ tickspeedDeceaseRate: state.tickspeedDeceaseRate,
resetGameCounter: state.resetGameCounter + 1,
lastSavedTime: state.lastSavedTime,
};
@@ -85,13 +88,19 @@ export function reducer(state: GameState, action: { type: string; payload?: any
return {
...JSON.parse(initialGameState),
galaxyCounter: state.galaxyCounter + 1,
- tickspeedDeceaseRate: 0.12,
- resetGameCounter: state.resetGameCounter,
+ tickspeedDeceaseRate: state.tickspeedDeceaseRate * 1.1,
lastSavedTime: state.lastSavedTime,
};
case ACTIONS.RESET_TO_INITIAL_VALUES:
return JSON.parse(initialGameState);
+
+ case ACTIONS.SAVE_DATA:
+ return {
+ ...state,
+ lastSavedTime: Date.now(),
+ };
+
default:
return state;
}
diff --git a/src/components/App.tsx b/src/components/App.tsx
index 189e245..6b119ea 100644
--- a/src/components/App.tsx
+++ b/src/components/App.tsx
@@ -14,7 +14,7 @@ function App() {
reducer,
JSON.parse(localStorage.getItem('data') || initialGameState)
);
-
+ const [saveTag, setSaveTag] = useState('gameSaved centered');
const timerExpiredCallback = useRef(() => {});
const tickspeedRef = useRef(2000);
const timerIdRef = useRef(-1);
@@ -24,7 +24,7 @@ function App() {
useEffect(() => {
const startTimer = () => {
- timerIdRef.current = setTimeout(() => {
+ timerIdRef.current = window.setTimeout(() => {
timerExpiredCallback.current();
startTimer();
}, tickspeedRef.current);
@@ -34,11 +34,27 @@ function App() {
// if we ever unmount / destroy this component instance, clear the timeout
return () => clearTimeout(timerIdRef.current);
}, []);
+ /* const classesSnackbar = clsx({
+ "gameSaved": true,
+ "centered": true,
+ "visible": Date.now() <= state.lastSavedTime + 3 * 1000 ? true: false,
+ }) */
+
+ useEffect(() => {
+ if (Date.now() <= state.lastSavedTime + 3 * 1000) setSaveTag('gameSaved centered visible');
+ else setSaveTag('gameSaved centered');
+ });
return (
+
+
{
@@ -32,19 +33,15 @@ export default function GameResets(props: { gs: GameState; dispatch: Function })
+ disabled={gs.resetGameCounter > 7 || gs.dims[gs.resetGameCounter - 1].dimCount < 20}>
Reset game to get new dimension
{`Antimatter Galaxies (${gs.galaxyCounter})`}
{`requires 80 8. Dimension `}
-
- Increase Tickspeed bump to 12%
+
+ Increase Tickspeed by 10%
@@ -52,11 +49,29 @@ export default function GameResets(props: { gs: GameState; dispatch: Function })
{`resets everything`}
dispatch({ type: ACTIONS.RESET_TO_INITIAL_VALUES })}
+ onClick={() => setPopUp(true)}
+ //onClick={() => dispatch({ type: ACTIONS.RESET_TO_INITIAL_VALUES })}
disabled={false}>
Resets game
+ {popUp && (
+
+
+ {
+ setPopUp(false);
+ return dispatch({ type: ACTIONS.RESET_TO_INITIAL_VALUES });
+ }}>
+ Reset game! All data is lost!
+
+ setPopUp(false)}>
+ Cancel
+
+
+
+ )}
>
);
}
diff --git a/src/components/Tickspeed/TickSpeed.tsx b/src/components/Tickspeed/TickSpeed.tsx
index a8a10cc..b87a4ad 100644
--- a/src/components/Tickspeed/TickSpeed.tsx
+++ b/src/components/Tickspeed/TickSpeed.tsx
@@ -32,7 +32,7 @@ export default function Tickspeed(props: { gs: GameState; dispatch: Function; ti
{`The current clockspeed is ${tickspeedRef.current.toFixed(
0
- )} ms. Reduce the tickspeed by ${gs.tickspeedDeceaseRate * 100}%.`}
+ )} ms. Reduce the tickspeed by ${(gs.tickspeedDeceaseRate* 100).toFixed(1)}%.`}
{
const saveDateRecursive = (gameState: GameState) => {
- if (Date.now() > gameState.lastSavedTime + 60 * 1000) {
+ if (Date.now() > gameState.lastSavedTime + 5 * 60 * 1000) {
localStorage.setItem('data', JSON.stringify(gameState));
console.log('data saved', gameState.lastSavedTime);
- setGameState((prevGS: GameState) => ({
- ...prevGS,
- lastSavedTime: Date.now(),
- }));
+ dispatch({ type: ACTIONS.SAVE_DATA });
}
};
saveDateRecursive(gameState);
-
}, [gameState]);
-
-
- // this prints the saved object from local storage. It is just for dev. No final purpose
- /* useEffect(() => {
- const printStorage = () => {
- displayLocStorageRef.current = setTimeout(() => {
- let savedData= JSON.parse(localStorage.getItem('data') ?? '');
- console.log('dataRef from storage', savedData);
- printStorage();
- }, 10000);
- };
- printStorage();
-
- return () => clearTimeout(displayLocStorageRef.current);
- }, []); */
}
diff --git a/src/styles/App.css b/src/styles/App.css
index 3ee50dc..afb338e 100644
--- a/src/styles/App.css
+++ b/src/styles/App.css
@@ -1,5 +1,6 @@
* {
-/* border: 1px solid black; */
+ /* border: 1px solid black; */
+ box-sizing: border-box;
}
.App {
@@ -24,7 +25,6 @@
grid-template-columns: repeat(4, 1fr);
gap: 10px;
grid-auto-rows: minmax(40px, auto);
-
}
.gridContainer3Rows {
@@ -42,12 +42,44 @@
align-items: center;
text-align: center;
}
+.spaceAround {
+ justify-content: space-around;
+}
-.cols-2{
+.cols-2 {
grid-template-columns: repeat(3, 1fr);
margin: 2rem 5rem;
}
+.overlay {
+ position: fixed;
+ width: 100%;
+ top: 0;
+ left: 0;
+ right: 0;
+ bottom: 0;
+
+ z-index: 10000;
+}
+
+.pop-up {
+ position: absolute;
+ top: 45%;
+ left: 0;
+
+ width: 50%;
+ height: 10%;
+ margin-left: 25%;
+ margin-right: 25%;
+ padding: 15px;
+
+ z-index: 100001;
+ background: grey;
+ border-radius: 10px;
+
+ box-shadow: 5px 7px 5px rgba(0, 0, 0, 0.75);
+}
+
.btn {
font-size: calc(10px + 1vmin);
padding: 0.2em 1em 0.2em 1em;
@@ -60,16 +92,100 @@
background-image: linear-gradient(to right, #29323c, #485563, #2b5876, #4e4376);
box-shadow: 0 4px 15px 0 rgba(45, 54, 65, 0.75);
}
-.btn:disabled{
+.btn:disabled {
background: initial;
box-shadow: initial;
}
-.sm{
+.sm {
font-size: calc(10px + 0.5vmin);
}
-.btn:disabled{
+.btn:disabled {
background-color: rgb(255, 254, 254);
border: 1px rgb(240, 238, 238) solid;
color: rgb(180, 177, 177);
}
+
+.red {
+ background-color: red;
+ font-style: bold;
+ color: white;
+}
+.black {
+ background: rgba(0, 0, 0, 0.85);
+}
+
+.snackbar-overlay {
+ position: fixed;
+ left: 0;
+ bottom: 0;
+ top: 0;
+ right: 0;
+ z-index: -1;
+}
+
+.gameSaved {
+ position: absolute;
+ top: 2%;
+ right: 1%;
+ visibility: hidden;
+ width: 10%;
+ height: 5%;
+ padding: 15px;
+
+ z-index: 90001;
+ background-color: rgb(2, 23, 157);
+ color: white;
+ font-weight: 700;
+ border-radius: 5px;
+ -webkit-animation: fadein 3s, fadeout 3s 3s;
+ animation: fadein 3s linear, fadeout 3s linear 3s;
+}
+.visible {
+ visibility: visible;
+}
+
+/* Animations to fade the snackbar in and out */
+@-webkit-keyframes fadein {
+ from {
+ top: 0%;
+ opacity: 0;
+ }
+ to {
+ top: 2%;
+ opacity: 1;
+ }
+}
+
+@keyframes fadein {
+ from {
+ top: -0%;
+ opacity: 0;
+ }
+ to {
+ top: 2%;
+ opacity: 1;
+ }
+}
+
+@-webkit-keyframes fadeout {
+ from {
+ top: 2%;
+ opacity: 1;
+ }
+ to {
+ top: -3%;
+ opacity: 0;
+ }
+}
+
+@keyframes fadeout {
+ from {
+ top: 2%;
+ opacity: 1;
+ }
+ to {
+ top: -3%;
+ opacity: 0;
+ }
+}
diff --git a/yarn.lock b/yarn.lock
index 861fba5..fc0aedd 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -394,6 +394,11 @@ check-error@^1.0.2:
resolved "https://registry.yarnpkg.com/check-error/-/check-error-1.0.2.tgz#574d312edd88bb5dd8912e9286dd6c0aed4aac82"
integrity sha512-BrgHpW9NURQgzoNyjfq0Wu6VFO6D7IZEmJNdtgNqpzGG8RuNFHt2jQxWlAs4HMe119chBnv+34syEZtc6IhLtA==
+clsx@^1.2.1:
+ version "1.2.1"
+ resolved "https://registry.npmmirror.com/clsx/-/clsx-1.2.1.tgz#0ddc4a20a549b59c93a4116bb26f5294ca17dc12"
+ integrity sha512-EcR6r5a8bj6pu3ycsa/E/cKVGuTgZJZdsyUYHOksG/UHIiKfjxzRxYJpyVBwYaQeOvghal9fcc4PidlgzugAQg==
+
color-convert@^1.9.0:
version "1.9.3"
resolved "https://registry.npmmirror.com/color-convert/-/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8"
From b996ac0f18fd3fdbac14a744e0595132821c5e5b Mon Sep 17 00:00:00 2001
From: Michael Urich <80188367+mturich@users.noreply.github.com>
Date: Tue, 12 Jul 2022 15:39:54 +0200
Subject: [PATCH 6/7] GameSavedNotification added
---
src/common/GameStateInterface.ts | 3 ++-
src/common/initialGameState.ts | 1 +
src/common/reducer.tsx | 15 +++++++++++++++
src/components/App.tsx | 18 ++----------------
src/customeHooks/useLocalStorage.tsx | 4 ++--
5 files changed, 22 insertions(+), 19 deletions(-)
diff --git a/src/common/GameStateInterface.ts b/src/common/GameStateInterface.ts
index 8d988f4..0b0121a 100644
--- a/src/common/GameStateInterface.ts
+++ b/src/common/GameStateInterface.ts
@@ -2,10 +2,11 @@ import { Children } from 'react';
export interface GameState {
antimatter: number;
tickspeedPrice: number;
- tickspeedDeceaseRate: number,
+ tickspeedDeceaseRate: number;
resetGameCounter: number;
galaxyCounter: number;
lastSavedTime: number;
+ showGameSavedNotification: boolean;
dims: Dim[];
}
diff --git a/src/common/initialGameState.ts b/src/common/initialGameState.ts
index 79be01f..7589ca7 100644
--- a/src/common/initialGameState.ts
+++ b/src/common/initialGameState.ts
@@ -7,6 +7,7 @@ let initialGameState: GameState = {
resetGameCounter: 2,
galaxyCounter: 0,
lastSavedTime: Date.now(),
+ showGameSavedNotification: false,
dims: [
{
nthDim: 0,
diff --git a/src/common/reducer.tsx b/src/common/reducer.tsx
index 0b510b5..1fe3630 100644
--- a/src/common/reducer.tsx
+++ b/src/common/reducer.tsx
@@ -12,6 +12,8 @@ export const ACTIONS = {
RESET_TO_INITIAL_VALUES: 'RESET_TO_INITIAL_VALUES',
POP_UP: 'POP_UP',
SAVE_DATA: 'SAVE_DATA',
+ TOOGLE_GAME_NOTIFICATION_OPEN: 'TOOGLE_GAME_NOTIFICATION_OPEN',
+ TOOGLE_GAME_NOTIFICATION_CLOSE: 'TOOGLE_GAME_NOTIFICATION_CLOSE',
};
export function reducer(state: GameState, action: { type: string; payload?: any }) {
@@ -101,6 +103,19 @@ export function reducer(state: GameState, action: { type: string; payload?: any
lastSavedTime: Date.now(),
};
+ case ACTIONS.TOOGLE_GAME_NOTIFICATION_CLOSE: {
+ return {
+ ...state,
+ showGameSavedNotification: false,
+ };
+ }
+ case ACTIONS.TOOGLE_GAME_NOTIFICATION_OPEN: {
+ return {
+ ...state,
+ showGameSavedNotification: true,
+ };
+ }
+
default:
return state;
}
diff --git a/src/components/App.tsx b/src/components/App.tsx
index 6b119ea..78d3f7f 100644
--- a/src/components/App.tsx
+++ b/src/components/App.tsx
@@ -8,13 +8,13 @@ import initialGameState from '../common/initialGameState';
import { useLocalStorage } from '../customeHooks/useLocalStorage';
import { ACTIONS, reducer } from '../common/reducer';
+import GameSavedNotification from './GameSavedNotification/GameSavedNotification';
function App() {
const [state, dispatch] = useReducer(
reducer,
JSON.parse(localStorage.getItem('data') || initialGameState)
);
- const [saveTag, setSaveTag] = useState('gameSaved centered');
const timerExpiredCallback = useRef(() => {});
const tickspeedRef = useRef(2000);
const timerIdRef = useRef(-1);
@@ -34,26 +34,12 @@ function App() {
// if we ever unmount / destroy this component instance, clear the timeout
return () => clearTimeout(timerIdRef.current);
}, []);
- /* const classesSnackbar = clsx({
- "gameSaved": true,
- "centered": true,
- "visible": Date.now() <= state.lastSavedTime + 3 * 1000 ? true: false,
- }) */
-
- useEffect(() => {
- if (Date.now() <= state.lastSavedTime + 3 * 1000) setSaveTag('gameSaved centered visible');
- else setSaveTag('gameSaved centered');
- });
return (
-
+
Date: Tue, 12 Jul 2022 21:13:53 +0200
Subject: [PATCH 7/7] changed naming from Snackbar to GameSavedNotification
---
.../GameSavedNotification.tsx | 42 ++++++++++++++
src/styles/GameSavedNotification.css | 55 +++++++++++++++++++
2 files changed, 97 insertions(+)
create mode 100644 src/components/GameSavedNotification/GameSavedNotification.tsx
create mode 100644 src/styles/GameSavedNotification.css
diff --git a/src/components/GameSavedNotification/GameSavedNotification.tsx b/src/components/GameSavedNotification/GameSavedNotification.tsx
new file mode 100644
index 0000000..4aee238
--- /dev/null
+++ b/src/components/GameSavedNotification/GameSavedNotification.tsx
@@ -0,0 +1,42 @@
+import React, { useEffect, useState } from 'react';
+import { GameState } from '../../common/GameStateInterface';
+import { ACTIONS } from '../../common/reducer';
+import '../../styles/GameSavedNotification.css';
+
+export default function GameSavedNotification(gs: GameState, dispatch: Function) {
+ let TIMER: number = 0;
+ function handleTimeout() {
+ TIMER = window.setTimeout(() => {
+ dispatch({ type: ACTIONS.TOOGLE_GAME_NOTIFICATION_CLOSE });
+ }, 3500);
+ }
+
+ useEffect(() => {
+ if (Date.now() <= gs.lastSavedTime + 5) {
+ dispatch({ type: ACTIONS.TOOGLE_GAME_NOTIFICATION_OPEN });
+ }
+ }, [gs.lastSavedTime]);
+
+ useEffect(() => {
+ console.log(gs.showGameSavedNotification);
+ }, [gs.showGameSavedNotification]);
+
+ useEffect(() => {
+ if (gs.showGameSavedNotification) {
+ handleTimeout();
+ }
+ return () => {
+ clearTimeout(TIMER);
+ };
+ }, [gs.showGameSavedNotification, TIMER]);
+
+ return (
+ gs.showGameSavedNotification && (
+
+ )
+ );
+}
diff --git a/src/styles/GameSavedNotification.css b/src/styles/GameSavedNotification.css
new file mode 100644
index 0000000..61d694f
--- /dev/null
+++ b/src/styles/GameSavedNotification.css
@@ -0,0 +1,55 @@
+* {
+ box-sizing: border-box;
+}
+
+.snackbar-overlay {
+ position: fixed;
+ left: 0;
+ bottom: 0;
+ top: 0;
+ right: 0;
+ z-index: -1;
+}
+
+.snackbar {
+ position: absolute;
+ z-index: 1000;
+ top: 2%;
+ right: 7%;
+ transform: translateX(50%);
+ height: auto;
+ padding: 0.625rem 1rem;
+ border-radius: 0.75rem;
+ border: transparent;
+ background-color: hsl(200, 100%, 65%);
+ color: white;
+ box-shadow: 0 3px 6px rgba(0, 0, 0, 0.16), 0 3px 6px rgba(0, 0, 0, 0.23);
+
+ display: flex;
+ justify-content: center;
+ align-items: center;
+
+ animation: fadein 1s, fadeout 1s 3s;
+}
+
+@keyframes fadein {
+ from {
+ top: 0;
+ opacity: 0;
+ }
+ to {
+ top: 2%;
+ opacity: 1;
+ }
+}
+
+@keyframes fadeout {
+ from {
+ top: 2%;
+ opacity: 1;
+ }
+ to {
+ top: 0;
+ opacity: 0;
+ }
+}