diff --git a/frontend/src/App.tsx b/frontend/src/App.tsx
index 06dcf31..5533c3b 100644
--- a/frontend/src/App.tsx
+++ b/frontend/src/App.tsx
@@ -1,109 +1,41 @@
-import { faBurst, faCrosshairs, faXmark } from '@fortawesome/free-solid-svg-icons';
+import { faCrosshairs } from '@fortawesome/free-solid-svg-icons';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
-import { CSSProperties, useEffect, useState } from 'react';
-import { TargetPreviewType } from './interfaces';
+import { CSSProperties, useEffect, useReducer, useState } from 'react';
+import BorderTiles from './components/BorderTiles';
+import FogImages from './components/FogImages';
+import HitElems from './components/HitElems';
+import Labeling from './components/Labeling';
+import Ships from './components/Ships';
+import { hitReducer, initlialTarget, initlialTargetPreview } from './helpers';
+import { HitType, TargetPreviewType, TargetType } from './interfaces';
import './styles/App.scss';
function App() {
- const [target, setTarget] = useState({
- show: false,
- x: 0,
- y: 0
- })
- const [targetPreview, setTargetPreview] = useState({
- newX: 0,
- newY: 0,
- shouldShow: false,
- appearOK: false,
- eventReady: true,
- show: false,
- x: 0,
- y: 0
- })
+ const count = 12;
+ const [target, setTarget] = useState(initlialTarget);
+ const [targetPreview, setTargetPreview] = useState(initlialTargetPreview);
+ const [hits, DispatchHits] = useReducer(hitReducer, [] as HitType[]);
+ const [x, setX] = useState(0);
+ const [y, setY] = useState(0);
- let borderTiles: JSX.Element[] = [];
- let shipElems: JSX.Element[] = [];
- let elems2: {
- field: string,
- x: number,
- y: number,
- }[] = [];
- let hitElems: {
- field: string,
- x: number,
- y: number,
- }[] = [],
- count = 12;
- for (let y = 0; y < count; y++) {
- elems2.push(...[
- // Up
- { field: String.fromCharCode(65+y), x: y+2, y: 1 },
- // Left
- { field: (y+1).toString(), x: 1, y: y+2 },
- // Bottom
- { field: String.fromCharCode(65+y), x: y+2, y: count+2 },
- // Right
- { field: (y+1).toString(), x: count+2, y: y+2 }
- ]);
- for (let x = 0; x < count; x++) {
- hitElems.push({ field: String.fromCharCode(65+x)+(y), x: x+2, y: y+2 })
+ useEffect(() => {
+ if (hits.length === count*count)
+ return;
+ if (x === count) {
+ setX(0);
+ setY(y => y+1);
+ return;
}
- }
- const hitSVGs = hitElems.map((obj, i) =>
-
-
-
);
- const corner = (x: number, y: number, count: number) => {switch (true) {
- case x === 0 && y === 0:
- return 'left-top-corner';
- case x === count+1 && y === 0:
- return 'right-top-corner';
- case x === 0 && y === count+1:
- return 'left-bottom-corner';
- case x === count+1 && y === count+1:
- return 'right-bottom-corner';
-
- default:
- return '';
- }};
- const border = (x: number, y: number, count: number) => {switch (true) {
- case x === 0:
- return 'left';
- case y === 0:
- return 'top';
- case x === count+1:
- return 'right';
- case y === count+1:
- return 'bottom';
-
- default:
- return '';
- }};
- for (let y = 0; y < count+2; y++) {
- for (let x = 0; x < count+2; x++) {
- const cornerReslt = corner(x, y, count);
- const borderType = cornerReslt ? cornerReslt : border(x, y, count);
- const isGameTile = x > 0 && x < count+1 && y > 0 && y < count+1;
- const classNames = ['border-tile'];
- if (borderType)
- classNames.push('edge', borderType);
- if (isGameTile)
- classNames.push('game-tile');
- borderTiles.push(
- {
- if (isGameTile)
- setTarget({ show: true, x, y });
- }}
- onMouseEnter={() => setTargetPreview(e => ({...e, newX: x, newY: y, shouldShow: isGameTile}))}
- >
- )
+ const autoTimer = setTimeout(() => {
+ DispatchHits({type: 'fireMissle', payload: {hit: (x+y)%2 !== 0, x: x+2, y: y+2}});
+ setX(x => x+1);
+ }, 100);
+
+ return () => {
+ clearTimeout(autoTimer);
}
- }
+ }, [x, y, hits.length]);
// handle visibility and position change of targetPreview
useEffect(() => {
@@ -150,33 +82,23 @@ function App() {
}
}, [targetPreview.shouldShow, targetPreview.newX, targetPreview.newY]);
- for (let i = 1; i <= 6; i++) {
- shipElems.push(
-
-

-
);
- }
-
return (
{/* Bordes */}
- { borderTiles }
+
{/* Collumn lettes and row numbers */}
- {elems2.map((obj, i) =>
-
{obj.field}
- )}
- { hitSVGs }
+
{/* Ships */}
- {/* { shipElems } */}
+ {/*
*/}
+
+
{/* Fog images */}
- {/*

-

-

*/}
+ {/*
*/}
@@ -184,9 +106,9 @@ function App() {
-
+ {/*
Edit src/App.tsx
and save to reload.
-
+
*/}
>, setTargetPreview: React.Dispatch>}}) {
+ let tilesProperties: {
+ key: number,
+ isGameTile: boolean,
+ classNameString: string,
+ x: number,
+ y: number
+ }[] = [];
+
+ for (let y = 0; y < count+2; y++) {
+ for (let x = 0; x < count+2; x++) {
+ const key = fieldIndex(count, x, y);
+ const cornerReslt = cornerCN(count, x, y);
+ const borderType = cornerReslt ? cornerReslt : borderCN(count, x, y);
+ const isGameTile = x > 0 && x < count+1 && y > 0 && y < count+1;
+ const classNames = ['border-tile'];
+ if (borderType)
+ classNames.push('edge', borderType);
+ if (isGameTile)
+ classNames.push('game-tile');
+ const classNameString = classNames.join(' ')
+ tilesProperties.push({key, classNameString, isGameTile, x, y})
+ }
+ }
+ return <>
+ {tilesProperties.map(({key, classNameString, isGameTile, x, y}) => {
+ return {
+ if (isGameTile)
+ setTarget({ show: true, x, y });
+ }}
+ onMouseEnter={() => setTargetPreview(e => ({...e, newX: x, newY: y, shouldShow: isGameTile}))}
+ >
+ })}
+ >
+}
+
+export default BorderTiles;
diff --git a/frontend/src/components/FogImages.tsx b/frontend/src/components/FogImages.tsx
new file mode 100644
index 0000000..ac3c230
--- /dev/null
+++ b/frontend/src/components/FogImages.tsx
@@ -0,0 +1,9 @@
+function FogImages() {
+ return <>
+
+
+
+ >
+}
+
+export default FogImages;
diff --git a/frontend/src/components/HitElems.tsx b/frontend/src/components/HitElems.tsx
new file mode 100644
index 0000000..e304b6e
--- /dev/null
+++ b/frontend/src/components/HitElems.tsx
@@ -0,0 +1,17 @@
+import { faBurst, faXmark } from '@fortawesome/free-solid-svg-icons';
+import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
+import { CSSProperties } from 'react';
+import { HitType } from '../interfaces';
+
+function HitElems({hits}: {hits: HitType[]}) {
+
+ return <>
+ {hits.map(({hit, x, y}, i) =>
+
+
+
+ )}
+ >
+}
+
+export default HitElems;
diff --git a/frontend/src/components/Labeling.tsx b/frontend/src/components/Labeling.tsx
new file mode 100644
index 0000000..b3d0c9a
--- /dev/null
+++ b/frontend/src/components/Labeling.tsx
@@ -0,0 +1,29 @@
+import { CSSProperties } from 'react'
+import { fieldIndex } from '../helpers';
+import { FieldType } from '../interfaces';
+
+function Labeling({count}: {count: number}) {
+ let elems: (FieldType & {
+ orientation: string
+ })[] = [];
+ for (let x = 0; x < count; x++) {
+ elems.push(
+ // Up
+ {field: String.fromCharCode(65+x), x: x+2, y: 1, orientation: 'up'},
+ // Left
+ {field: (x+1).toString(), x: 1, y: x+2, orientation: 'left'},
+ // Bottom
+ {field: String.fromCharCode(65+x), x: x+2, y: count+2, orientation: 'bottom'},
+ // Right
+ {field: (x+1).toString(), x: count+2, y: x+2, orientation: 'right'}
+ );
+ }
+ elems = elems.sort((a, b) => fieldIndex(count, a.x, a.y)-fieldIndex(count, b.x, b.y));
+ return <>
+ {elems.map(({field, x, y, orientation}, i) =>
+ {field}
+ )}
+ >
+}
+
+export default Labeling;
diff --git a/frontend/src/components/Ships.tsx b/frontend/src/components/Ships.tsx
new file mode 100644
index 0000000..11b2fa5
--- /dev/null
+++ b/frontend/src/components/Ships.tsx
@@ -0,0 +1,19 @@
+import { CSSProperties } from 'react'
+
+function Ships() {
+ let shipIndexes: number[] = [];
+
+ for (let i = 1; i <= 6; i++) {
+ shipIndexes.push(i);
+ }
+
+ return <>
+ {shipIndexes.map(i =>
+
+

+
+ )}
+ >
+}
+
+export default Ships;
diff --git a/frontend/src/helpers.ts b/frontend/src/helpers.ts
new file mode 100644
index 0000000..da0fcf4
--- /dev/null
+++ b/frontend/src/helpers.ts
@@ -0,0 +1,52 @@
+import { HitType, HitDispatchType } from "./interfaces";
+
+export const hitReducer = (formObject: HitType[], action: HitDispatchType) => {
+ switch (action.type) {
+
+ case 'fireMissle': {
+ const result = [...formObject, action.payload];
+ return result;
+ }
+
+ default:
+ return formObject;
+ }
+}
+export const fieldIndex = (count: number, x: number, y: number) => y*(count+2)+x;
+export const cornerCN = (count: number, x: number, y: number) => {
+ if (x === 0 && y === 0)
+ return 'left-top-corner';
+ if (x === count+1 && y === 0)
+ return 'right-top-corner';
+ if (x === 0 && y === count+1)
+ return 'left-bottom-corner';
+ if (x === count+1 && y === count+1)
+ return 'right-bottom-corner';
+ return '';
+};
+export const borderCN = (count: number, x: number, y: number) => {
+ if (x === 0)
+ return 'left';
+ if (y === 0)
+ return 'top';
+ if (x === count+1)
+ return 'right';
+ if (y === count+1)
+ return 'bottom';
+ return '';
+};
+export const initlialTarget = {
+ show: false,
+ x: 0,
+ y: 0
+};
+export const initlialTargetPreview = {
+ newX: 0,
+ newY: 0,
+ shouldShow: false,
+ appearOK: false,
+ eventReady: true,
+ show: false,
+ x: 0,
+ y: 0
+};
\ No newline at end of file
diff --git a/frontend/src/interfaces.ts b/frontend/src/interfaces.ts
index 3b45114..61f9cb2 100644
--- a/frontend/src/interfaces.ts
+++ b/frontend/src/interfaces.ts
@@ -1,3 +1,8 @@
+export interface TargetType {
+ show: boolean,
+ x: number,
+ y: number
+};
export interface TargetPreviewType {
newX: number,
newY: number,
@@ -7,4 +12,18 @@ export interface TargetPreviewType {
show: boolean,
x: number,
y: number
-}
\ No newline at end of file
+};
+export interface FieldType {
+ field: string,
+ x: number,
+ y: number,
+};
+export interface HitType {
+ hit: boolean,
+ x: number,
+ y: number,
+};
+
+interface fireMissle { type: 'fireMissle', payload: { x: number, y: number, hit: boolean } };
+
+export type HitDispatchType = fireMissle;
diff --git a/frontend/src/styles/App.scss b/frontend/src/styles/App.scss
index d7b0d9c..210303e 100644
--- a/frontend/src/styles/App.scss
+++ b/frontend/src/styles/App.scss
@@ -48,7 +48,7 @@
grid-template-columns: .75fr repeat(12, 1fr) .75fr;
// grid-gap: 1px solid blue;
- > .r1 {
+ > .label {
grid-column: var(--x);
grid-row: var(--y);
}
@@ -83,6 +83,7 @@
// justify-content: center;
border: 1px solid yellow;
grid-row: var(--x);
+ pointer-events: none;
img {
position: absolute;