<!DOCTYPE html>
<html lang="ko">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>4x4 랜덤 빙고</title>
<!-- Tailwind CSS 로드 -->
<script src="https://cdn.tailwindcss.com"></script>
<style>
/* Inter 폰트 적용 */
body {
font-family: 'Inter', sans-serif;
}
@import url('https://fonts.googleapis.com/css2?family=Inter:wght@400;600;700&display=swap');
/* 빙고 셀 스타일 */
.bingo-cell {
/* 셀의 비율을 1:1로 유지 */
aspect-ratio: 1 / 1;
/* 기본 스타일 */
background-color: white;
border: 1px solid #d1d5db; /* gray-300 */
border-radius: 0.5rem; /* rounded-lg */
display: flex;
align-items: center;
justify-content: center;
text-align: center;
padding: 0.5rem; /* p-2 */
font-size: 0.875rem; /* text-sm */
line-height: 1.25rem;
cursor: pointer;
transition: all 0.2s ease-in-out;
box-shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.1), 0 1px 2px 0 rgba(0, 0, 0, 0.06); /* shadow-sm */
overflow-wrap: break-word;
word-break: keep-all;
}
/* 클릭된 셀 스타일 */
.bingo-cell.clicked {
background-color: #facc15; /* yellow-400 */
color: #1f2937; /* gray-800 */
font-weight: 700; /* font-bold */
transform: scale(1.05);
box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06); /* shadow-md */
}
</style>
</head>
<body class="bg-gray-100 min-h-screen flex items-center justify-center p-4">
<!-- 플레이어 뷰 -->
<div id="player-view" class="w-full max-w-lg">
<div class="bg-white p-6 rounded-lg shadow-xl">
<h1 class="text-3xl font-bold text-center text-blue-700 mb-2">BINGO!</h1>
<p class="text-center text-gray-600 mb-4">셀을 클릭하여 표시하세요.</p>
<!-- 4x4 빙고 그리드 -->
<div id="bingo-grid" class="grid grid-cols-4 gap-2 sm:gap-3">
<!-- 빙고 셀이 여기에 동적으로 생성됩니다 -->
</div>
<!-- 빙고 상태 표시 -->
<div id="bingo-status" class="mt-4 text-center text-3xl font-bold text-green-600 h-10">
<!-- "1 BINGO!" 등이 여기에 표시됩니다 -->
</div>
</div>
</div>
<script>
document.addEventListener('DOMContentLoaded', () => {
// --- 플레이어 뷰 로직 ---
showPlayerView();
});
// ============================
// 플레이어 뷰 (Player View)
// ============================
function showPlayerView() {
// -----------------------------------------------------------------
// 사장님이 주신 16개 키워드로 업데이트했습니다.
// -----------------------------------------------------------------
const MY_KEYWORDS = [
"아라비안란타", "헬싱키", "공동체", "디지털 트윈",
"놀이터", "도자기 공장", "도시재생", "민관 합자",
"주민 참여", "녹지공간", "아트 디자인 시티", "주거 공간 조성",
"주택 부족 문제", "예술작품", "공공 미술", "첨단 기술"
];
// -----------------------------------------------------------------
if (MY_KEYWORDS.length !== 16) {
document.getElementById('player-view').innerHTML = '<p class="text-red-500">오류: 16개 키워드가 필요합니다. HTML 파일을 수정하세요.</p>';
return;
}
const grid = document.getElementById('bingo-grid');
const status = document.getElementById('bingo-status');
// 16칸의 클릭 상태를 저장하는 배열 (false로 초기화)
let clickedState = Array(16).fill(false);
// 키워드 섞기 (Fisher-Yates Shuffle)
function shuffle(array) {
for (let i = array.length - 1; i > 0; i--) {
const j = Math.floor(Math.random() * (i + 1));
[array[i], array[j]] = [array[j], array[i]];
}
return array;
}
// 원본 배열 복사 후 섞기
const shuffledKeywords = shuffle([...MY_KEYWORDS]);
// 16개 셀 생성 및 그리드에 추가
shuffledKeywords.forEach((keyword, index) => {
const cell = document.createElement('div');
cell.className = 'bingo-cell';
cell.textContent = keyword;
cell.dataset.index = index; // 각 셀에 0~15 인덱스 부여
// 셀 클릭 이벤트
cell.addEventListener('click', () => {
cell.classList.toggle('clicked');
const cellIndex = parseInt(cell.dataset.index);
// 클릭 상태 업데이트
clickedState[cellIndex] = !clickedState[cellIndex];
// 빙고 확인
checkBingo();
});
grid.appendChild(cell);
});
// 빙고 확인 로직
function checkBingo() {
let lines = 0;
// 가로 4줄 확인
for (let i = 0; i < 4; i++) {
if (clickedState[i*4] && clickedState[i*4 + 1] && clickedState[i*4 + 2] && clickedState[i*4 + 3]) {
lines++;
}
}
// 세로 4줄 확인
for (let i = 0; i < 4; i++) {
if (clickedState[i] && clickedState[i + 4] && clickedState[i + 8] && clickedState[i + 12]) {
lines++;
}
}
// 대각선 (왼쪽 위 -> 오른쪽 아래)
if (clickedState[0] && clickedState[5] && clickedState[10] && clickedState[15]) {
lines++;
}
// 대각선 (오른쪽 위 -> 왼쪽 아래)
if (clickedState[3] && clickedState[6] && clickedState[9] && clickedState[12]) {
lines++;
}
// 빙고 상태 업데이트
if (lines > 0) {
status.textContent = `${lines} BINGO!`;
// 빙고 달성 시 축하 효과 (예: 색상 변경)
status.classList.add('animate-pulse');
} else {
status.textContent = '';
status.classList.remove('animate-pulse');
}
}
}
</script>
</body>
</html>