Skip to content

Commit

Permalink
refactor: use flat indexing for block position
Browse files Browse the repository at this point in the history
  • Loading branch information
thisisWooyeol committed Sep 15, 2024
1 parent a202432 commit 284321d
Show file tree
Hide file tree
Showing 2 changed files with 40 additions and 32 deletions.
44 changes: 27 additions & 17 deletions src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,13 @@ import './App.css';

import { useEffect, useState } from 'react';

import { getRandomInitPos, getRandomPos, isGameLose, isGameWin,type Map2048, moveMapIn2048Rule, stringDirectionMap } from './Map2048';
import { getRandomInitPos, getRandomPos, isGameLose, isGameWin, type Map2048, moveMapIn2048Rule, stringDirectionMap } from './Map2048';


function App() {
const rowLength: number = 4;
const columnLength: number = 4;
const initPos: number[][] = getRandomInitPos(rowLength, columnLength);
const initPos: number[] = getRandomInitPos(rowLength, columnLength);

const [keyPressed, setKeyPressed] = useState<string>('');
const [gameStatus, setGameStatus] = useState<'playing' | 'win' | 'lose'>('playing');
Expand All @@ -18,14 +18,12 @@ function App() {
Array.from(
{ length: columnLength },
(_, columnIndex) => {
if (initPos.some(pos => pos[0] === rowIndex && pos[1] === columnIndex)) {
return 2;
}
return null;
},
),
)
);
return initPos.some(pos =>
pos === rowIndex * rowLength + columnIndex) ? 2 : null;
},
),
)
);

useEffect(() => {
const handleKeyUp = (event: WindowEventMap['keyup']) => {
Expand All @@ -48,11 +46,11 @@ function App() {
const {result, isMoved} = moveMapIn2048Rule(map, direction);
// Update the map state if moved
if (isMoved) {
const newBlockPos: [number, number] | null = getRandomPos(result);
const newBlockPos: number | null = getRandomPos(result);
if (newBlockPos !== null) {
const [rowIndex, columnIndex] = newBlockPos;
result[rowIndex][columnIndex] = 2;
console.info(`New block at: ${rowIndex}, ${columnIndex}`);
const pos = newBlockPos;
result[Math.floor(pos / rowLength)][pos % columnLength] = 2;
console.info(`New block at: ${Math.floor(pos / rowLength)}, ${pos % columnLength}`);
}
setMap(result);
}
Expand Down Expand Up @@ -99,8 +97,8 @@ function App() {
{/* Game instructions */}
<div className='grid grid-cols-4 gap-4'>
<div className='col-span-3'>
Join the tiles, get to <strong>2048!</strong> <br />
Original game link at <a href='https://play2048.co/'style={{color: 'blue'}}>here!</a>
<p>Join the tiles, get to <strong>2048!</strong></p>
<p>Original game link at <a href='https://play2048.co/'style={{color: 'blue'}}>here!</a></p>
</div>
<div>
<button className='bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded'>
Expand All @@ -110,7 +108,7 @@ function App() {
</div>

{/* Game 2048 board */}
<div className='box-border w-full aspect-square p-4 bg-gray-400 rounded-lg'>
<div className='relative box-border w-full aspect-square p-4 bg-gray-400 rounded-lg'>
<div className='grid grid-cols-4 grid-rows-4 gap-4'>
{Array.from({ length: rowLength}, (_, rowIndex) =>
Array.from({ length: columnLength }, (_, columnIndex) =>
Expand All @@ -122,6 +120,18 @@ function App() {
)
)}
</div>

{/* Game status */}
{gameStatus === 'win' &&
<div className='absolute inset-0 bg-green-400 bg-opacity-50 rounded-lg flex items-center justify-center text-5xl font-extrabold'>
You Win!
</div>
}
{gameStatus === 'lose' &&
<div className='absolute inset-0 bg-red-400 bg-opacity-50 rounded-lg flex items-center justify-center text-5xl font-extrabold'>
You Lose! Try again?
</div>
}
</div>
</div>
</div>
Expand Down
28 changes: 13 additions & 15 deletions src/Map2048.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -120,33 +120,31 @@ export const moveMapIn2048Rule = (
* 2048 게임에서, Map의 2개의 초기 블록 위치를 반환하는 함수입니다.
* @param rowLength Map의 행 길이
* @param columnLength Map의 열 길이
* @returns 2048 게임의 2개의 초기 블록 위치
* @returns (0, ... , rowLength * columnLength - 1)의 배열
*/
export const getRandomInitPos = (rowLength: number, columnLength: number): number[][] => {
export const getRandomInitPos = (rowLength: number, columnLength: number): number[] => {
const firstPosition: number = Math.floor(Math.random() * rowLength * columnLength);
let secondPosition: number;
let tmp: number;
do {
secondPosition = Math.floor(Math.random() * rowLength * columnLength);
} while (firstPosition === secondPosition);
tmp = Math.floor(Math.random() * rowLength * columnLength);
} while (firstPosition === tmp);
const secondPosition: number = tmp;

const firstRow: number = Math.floor(firstPosition / rowLength);
const firstColumn: number = firstPosition % rowLength;
const secondRow: number = Math.floor(secondPosition / rowLength);
const secondColumn: number = secondPosition % rowLength;
return [[firstRow, firstColumn], [secondRow, secondColumn]];
return [firstPosition, secondPosition];
};

/**
* 2048 게임에서, Map에 랜덤한 위치에 블록을 놓을 수 있는지 확인하고, 가능하다면 랜덤한 위치를 반환하는 함수입니다.
* @param map Map2048
* @returns 신규 블록을 놓을 수 있는 랜덤한 위치 (행, 열) 또는 null
* @returns 신규 블록을 놓을 수 있는 랜덤한 위치 (0, rowLength * columnLength -1) 범위의 number 또는 null
*/
export const getRandomPos = (map: Map2048): [number, number] | null => {
const emptyPositions: [number, number][] = [];
export const getRandomPos = (map: Map2048): number | null => {
const rowLength = map.length;
const emptyPositions: number[] = [];
map.forEach((row, rowIndex) => {
row.forEach((cell, columnIndex) => {
if (cell === null) {
emptyPositions.push([rowIndex, columnIndex]);
emptyPositions.push(rowIndex * rowLength + columnIndex);
}
});
});
Expand All @@ -166,7 +164,7 @@ export const stringDirectionMap: Record<string, Direction> = {
};

export const isGameWin = (map: Map2048): boolean => {
const WINNING_SCORE = 2048;
const WINNING_SCORE = 128;
return map.some(row => row.some(cell => cell === WINNING_SCORE));
}

Expand Down

0 comments on commit 284321d

Please sign in to comment.