[로데시] 개발
[대학전쟁] 양면빙고 웹 개발 05 - 빙고 판단, player 2명 본문
반응형

0️⃣ 지난 번까지..
대학전쟁에 나온 '양면빙고 (double sided bingo)' 게임을 보고 ☰ 양면빙고 (double-sided-bingo) 개발 과정
1️⃣ 빙고 판단
📌 util.js 코드export const getVisibleColor = (tile) => {
const frontId = tile.isFlipped
? getPairedTileId(tile.id)
: tile.id;
return getTileColorById(frontId);
};
앞면의 색을 판단하는 getVisibleColor 함수를 util.js에 추가한다.
const checkBingo = (boardTiles, targetColor) => {
const lines = [
// 행 빙고
[0,1,2,3], [4,5,6,7], [8,9,10,11], [12,13,14,15],
// 열 빙고
[0,4,8,12], [1,5,9,13], [2,6,10,14], [3,7,11,15],
// 대각선 빙고
[0,5,10,15], [3,6,9,12],
];
return lines.some(line =>
line.every(idx => {
const tile = boardTiles[idx];
if (!tile) return false;
return getVisibleColor(tile) === targetColor;
})
);
};
빙고를 판단하는 checkBingo(boardTiles, targetColor) 함수를 추가한다.
const [winner, setWinner] = useState(null); // 승자
const COLORS = ["red", "blue", "yellow"]; // random으로 배정될 main color
const shuffled = COLORS.sort(() => 0.5 - Math.random()); // 색 random
const [myPlayer] = useState({
id: "me",
mainColor: shuffled[0],
});
const [opponent] = useState({
id: "opponent",
mainColor: shuffled[1],
});
const 5개를 추가한다.
useEffect(() => {
const myWin = checkBingo(boardTiles, myPlayer.mainColor);
const opponentWin = checkBingo(boardTiles, opponent.mainColor);
if (myWin) {
setWinner("me");
} else if (opponentWin) {
setWinner("opponent");
}
}, [boardTiles]);
빙고판(bingoboard)이 바뀔 때 마다 checkBingo 호출될 수 있도록 useEffect을 추가한다.
useEffect(() => {
if (winner) {
console.log("WINNER:", winner);
}
}, [winner]);
winner가 잘 출력되는지 콘솔창에서 테스트해본다.
2️⃣ player 추가
📌 App.js 코드const [currentTurn, setCurrentTurn] = useState("me"); // 턴 상태
const [players, setPlayers] = useState({
me: {
id: "me",
mainColor: shuffled[0],
tiles: initialTiles.map(t => ({ ...t, owner: "me" })),
},
opponent: {
id: "opponent",
mainColor: shuffled[1],
tiles: initialTiles.map(t => ({
...t,
key: `${t.key}-op`,
owner: "opponent",
})),
},
});
const myTiles = players[currentTurn].tiles;
const 3개를 추가한다.
const endTurn = () => {
setCurrentTurn(prev => (prev === "me" ? "opponent" : "me"));
};
turn 변경 함수를 작성한다. 내 turn이 끝나면 현재 턴(current turn)을 상대로, 상대 turn이 끝나면 현재 턴을 나로 바꾼다.
const handleFlip = (key, fromBoard = false) => {
// TileList 뒤집기 (턴 유지)
setPlayers(prev => {
const next = structuredClone(prev);
Object.values(next).forEach(player => {
player.tiles = player.tiles.map(tile =>
tile.key === key ? { ...tile, isFlipped: !tile.isFlipped } : tile
);
});
return next;
});
// Board 뒤집기 (턴 종료)
if (fromBoard) {
setBoardTiles(prev =>
prev.map(cell =>
cell?.key === key ? { ...cell, isFlipped: !cell.isFlipped } : cell
)
);
endTurn();
}
};
뒤집으면 turn이 넘어가도록 handFlip 함수에 endTurn를 추가한다.
const tile = myTiles.find(t => t.key === active.id);
내 타일만 보이도록 handleDragStart 함수를 수정한다.
const tile = myTiles.find(t => t.key === active.id);
내 타일만 보이도록 handleDragEnd 함수를 수정한다.
setPlayers(prev => {
const next = structuredClone(prev);
next[currentTurn].tiles =
next[currentTurn].tiles.filter(t => t.key !== active.id);
return next;
});
endTurn();
타일이 착수되면 타일을 제거되도록 handleDragEnd 함수를 수정한다.
<BingoBoard
boardTiles={boardTiles}
movableCell={movableCell}
onFlip={(key) => handleFlip(key, true)}
/>
<TileList
tiles={players[currentTurn].tiles}
onFlip={(key) => handleFlip(key, false)}
/>
return 되는 BingoBoard와 TileList의 onFlip을 다음과 같이 수정한다.
3️⃣ main color 표시
📌 App.js 코드<div style={{ marginBottom: 12, marginLeft: "auto", marginRight:"300px", textAlign: "right", }}>
<strong>My Main Color:</strong>{" "}
<span style={{ color: currentTurn === "me" ? players.me.mainColor.toUpperCase() : players.opponent.mainColor.toUpperCase() }}>
{currentTurn === "me" ? players.me.mainColor.toUpperCase() : players.opponent.mainColor.toUpperCase()}
</span>
</div>
main color를 빙고판과 타일리스트 사이 우측에 표시되도록 코드를 return에 추가해준다.
4️⃣ 빙고 완성 시 동작 stop
📌 App.js 코드{winner && (
<div className="winner-overlay">
<h1>Winner: {winner === "me" ? "ME" : "OPPONENT"}</h1>
</div>
)}
return <DndContext> 태그 하단에 다음과 같은 코드를 추가해준다.
if (winner) return;
handleFlip, handleDragStart, handleDragEnd 함수 각각 첫 줄에 다음 코드를 추가한다.
if (!winner) {
setCurrentTurn(prev => prev === "me" ? "opponent" : "me");
}
endTurn 함수를 다음과 같이 수정한다.
.winner-overlay {
position: fixed;
inset: 0;
background: rgba(0,0,0,0.6);
color: white;
font-size: 48px;
display: flex;
align-items: center;
justify-content: center;
z-index: 999;
}
빙고가 완성되면 화면 전체에 winner를 표시하고, 착수/뒤집기/이동 등 동작이 불가능하도록 한다.
5️⃣ 앞으로...
양면빙고를 2명이서 paly 할 수 있는 기능을 추가했다.

반응형
'개인 개발 > 대학전쟁' 카테고리의 다른 글
| [대학전쟁3] 양면빙고 웹 개발 07 - timer, highlight, restart (0) | 2026.01.31 |
|---|---|
| [대학전쟁3] 양면빙고 웹 개발 06 - 직전 타일 이동, 뒤집기 제한 (0) | 2026.01.23 |
| [대학전쟁] 양면빙고 웹 개발 04 - 타일 뒤집기 (flip), 이동 (move) (1) | 2026.01.18 |
| [대학전쟁3] 양면빙고 웹 개발 03 - 타일 착수 (place) (0) | 2026.01.16 |
| [대학전쟁3] 양면빙고 웹 개발 02 - 타일 list 내 이동 (0) | 2026.01.14 |