[P-Reinforce] 2026-04-20: Processed 5 New Knowledge Gems (Tetris Engineering Lessons)

This commit is contained in:
2026-04-20 15:00:36 +09:00
parent 46fd50381e
commit 62153b5741
19 changed files with 658 additions and 0 deletions
@@ -0,0 +1,20 @@
---
# 💡 Lesson Learned: Web Worker를 이용한 고성능 아키텍처 설계 (Performance)
## 🎯 문제 상황 (The Problem)
테트리스 게임과 같이 **매우 높은 빈도(High Frequency)**로 상태 변화가 발생하는 실시간 애플리케이션을 React의 메인 스레드에서 처리할 경우, UI 업데이트와 물리 계산이 충돌하여 **프레임 드롭(Jank)** 현상이나 성능 저하가 발생했습니다.
## 🔬 근본 원인 (Root Cause)
게임 엔진 로직은 CPU를 매우 많이 사용합니다. 이 무거운 계산을 메인 스레드에서 수행하면, 브라우저의 UI 업데이트 루프(`requestAnimationFrame`)와 충돌하여 사용자에게 부드럽지 않은 경험(Poor UX)을 제공하게 됩니다.
## ✅ 해결책 (The Solution)
**Web Worker**를 사용하여 게임 엔진 로직 전체를 **메인 스레드에서 완전히 분리(Isolate)** 했습니다.
* **원리:** Web Worker는 별도의 백그라운드 스레드에서 동작하므로, 아무리 복잡한 계산을 해도 메인 스레드의 UI 렌더링에는 영향을 주지 않습니다.
## 💡 교훈 (Lesson Learned)
> **"성능 병목 현상은 종종 '스레딩(Threading)'의 문제이다."**
> 실시간으로 높은 연산량이 요구되는 모든 시스템은, 반드시 Web Worker 또는 별도의 백그라운드 프로세스로 로직을 분리하여 처리해야 합니다.
## 🔗 관련 키워드
`Web Worker`, `Concurrency`, `High-Frequency Updates`, `Performance Optimization`
---
@@ -0,0 +1,19 @@
---
# 💡 Lesson Learned: 상태 관리의 단일 진실 공급원 원칙 (Data Consistency)
## 🎯 문제 상황 (The Problem)
테트리스 게임은 '현재 보드 상태'와 '움직이는 블록 위치'라는 두 가지 핵심 데이터를 가지고 있습니다. 이 데이터들이 여러 곳에서 독립적으로 업데이트될 위험이 있었습니다. 만약 A 부분에서 값을 바꾸고, B 부분에서 같은 값을 다르게 계산한다면 **데이터 불일치(Inconsistency)**가 발생합니다.
## 🔬 근본 원인 (Root Cause)
시스템의 핵심 상태가 분산되어 관리되고 있었기 때문입니다. 여러 컴포넌트와 로직이 각자 '진실'이라고 믿는 데이터를 가지고 충돌할 가능성이 높았습니다.
## ✅ 해결책 (The Solution)
**Redux/Zustand 패턴을 차용하여 모든 게임의 핵심 상태(State)**를 `src/TetrisGame.jsx` 컴포넌트가 관리하는 **단일 지점(Single Source of Truth)**으로 만들었습니다. 모든 데이터 변경은 이 중앙 저장소를 통해 이루어지게 했습니다.
## 💡 교훈 (Lesson Learned)
> **"상태는 오직 한 곳에서만 정의하고, 모든 로직은 그 상태를 읽고 쓰는 방식으로 동작해야 한다."**
> 복잡한 시스템을 설계할 때, 핵심 데이터의 흐름(Data Flow)과 책임 범위(Responsibility)를 명확히 분리하는 것이 가장 중요합니다.
## 🔗 관련 키워드
`Single Source of Truth`, `Redux Pattern`, `State Management`, `Predictable State`
---
@@ -0,0 +1,22 @@
---
# 💡 Lesson Learned: 시스템 아키텍처의 중요성 (The Need for Abstraction)
## 🎯 문제 상황 (The Problem)
이번 프로젝트를 진행하면서, 코드를 짜는 것이 아니라 '어떤 구조로 짤지'가 가장 어려웠습니다. 이는 단순히 기술적인 문제가 아닌 **설계 패턴(Design Pattern)**과 관련된 문제입니다.
## 🔬 근본 원인 (Root Cause)
모든 로직을 한 파일에 때려 넣으려는 유혹에 빠지는 것, 즉 '스파게티 코드'를 만들 위험이 가장 큰 문제였습니다. 모든 것을 한곳에서 처리하려 했기 때문에 유지보수성과 확장성이 0에 수렴했습니다.
## ✅ 해결책 (The Solution)
**아키텍처적 분리 원칙(Separation of Concerns, SoC)**을 적용하여 코드를 다음과 같이 역할별로 나눴습니다:
1. **게임 규칙:** `gameWorker.js` (논리 엔진)
2. **상태 관리:** `TetrisGame.jsx` (데이터의 출입구)
3. **렌더링:** React 컴포넌트 (화면에 보여주는 역할만 수행)
## 💡 교훈 (Lesson Learned)
> **"시스템을 구성할 때는 '책임 분리(Separation of Concerns)'를 최우선 원칙으로 삼아야 한다."**
> 기능이 복잡해질수록, 코드는 반드시 경계가 명확한 모듈들로 분리되어야 합니다.
## 🔗 관련 키워드
`Separation of Concerns`, `Modular Design`, `Microservices Pattern`
---
@@ -0,0 +1,22 @@
---
# 💡 Lesson Learned: 개발 환경 및 실행 프로세스 관리 (DevOps & DevOps)
## 🎯 문제 상황 (The Problem)
이번 프로젝트는 단순히 코드를 짜고 끝나는 것이 아니라, **'어떻게 이 코드를 구동시킬 수 있는가?'**라는 물리적 절차의 중요성을 깨달았습니다. (오류 코드: `npm audit`, `index.html` 누락, 권한 오류 등)
## 🔬 근본 원인 (Root Cause)
개발자는 종종 **'논리적 완성도(Logical Completion)'에만 집중**하고, 프로젝트를 실행하는 데 필요한 **물리적인 설정 파일(Configuration)**과 **운영체제 레벨의 환경 변수/권한** 관리에 소홀해지기 쉽습니다.
## ✅ 해결책 (The Solution)
프로젝트 시작 시점에 다음 절차를 반드시 거쳐야 함을 확립했습니다:
1. `npm install`: 필요한 모든 패키지를 설치한다.
2. 환경 설정 확인: `public/index.html` 등 필수 진입점이 존재하는지 확인한다.
3. 권한 확보: 운영체제 레벨에서 스크립트 실행 권한(Execution Policy)을 확보한다.
## 💡 교훈 (Lesson Learned)
> **"코딩 능력만큼이나 중요한 것은 '운영 환경에 대한 이해'와 '체계적인 개발 프로세스 확립'이다."**
> 프로젝트 관리자는 항상 이 세 가지 단계를 점검해야 합니다.
## 🔗 관련 키워드
`DevOps`, `CI/CD Pipeline`, `Execution Policy`, `Build Environment`
---
@@ -0,0 +1,19 @@
---
# 💡 Lesson Learned: 시스템 시뮬레이션의 핵심 원리 (Simulation Design)
## 🎯 문제 상황 (The Problem)
테트리스는 단순한 게임이 아니라, **물리 법칙(Physics)**과 **규칙 기반의 상태 변화**가 작동하는 작은 시뮬레이터였습니다. 이 경험을 통해 '시뮬레이션을 어떻게 설계해야 하는지'에 대한 깊은 이해를 얻었습니다.
## 🔬 근본 원인 (Root Cause)
단순히 UI로 그리는 것에만 집중하면, 시스템이 **규칙(Ruleset)**과 **물리 법칙(Physics Law)**을 따르는 '가상 세계'의 느낌을 놓치기 쉽습니다.
## ✅ 해결책 (The Solution)
게임 로직을 `gameWorker.js`에 완전히 분리하여, 모든 변화를 수학적 함수(`checkCollision`, `movePiece`)로 처리하고 그 결과를 상태(State)에 반영했습니다. 이는 곧 **"규칙이 물리 법칙처럼 작동하는 시스템"** 설계의 성공적인 예시입니다.
## 💡 교훈 (Lesson Learned)
> **"모든 시뮬레이션은 '물리적 규칙'을 수학적으로 정의하고, 그 규칙을 절대 우회할 수 없도록 강제해야 한다."**
> 이를 통해 우리는 단순한 게임을 넘어, 자율주행이나 물리 엔진에 적용 가능한 고수준의 시스템 모델링 능력을 갖추게 되었습니다.
## 🔗 관련 키워드
`Simulation Design`, `Physics Engine`, `Ruleset Enforcement`, `Systemic Modeling`
---
+1
View File
@@ -0,0 +1 @@
{}
+1
View File
@@ -0,0 +1 @@
{}
+33
View File
@@ -0,0 +1,33 @@
{
"file-explorer": true,
"global-search": true,
"switcher": true,
"graph": true,
"backlink": true,
"canvas": true,
"outgoing-link": true,
"tag-pane": true,
"footnotes": false,
"properties": true,
"page-preview": true,
"daily-notes": true,
"templates": true,
"note-composer": true,
"command-palette": true,
"slash-command": false,
"editor-status": true,
"bookmarks": true,
"markdown-importer": false,
"zk-prefixer": false,
"random-note": false,
"outline": true,
"word-count": true,
"slides": false,
"audio-recorder": false,
"workspaces": false,
"file-recovery": true,
"publish": false,
"sync": true,
"bases": true,
"webviewer": false
}
+22
View File
@@ -0,0 +1,22 @@
{
"collapse-filter": true,
"search": "",
"showTags": false,
"showAttachments": false,
"hideUnresolved": false,
"showOrphans": true,
"collapse-color-groups": true,
"colorGroups": [],
"collapse-display": true,
"showArrow": false,
"textFadeMultiplier": 0,
"nodeSizeMultiplier": 1,
"lineSizeMultiplier": 1,
"collapse-forces": true,
"centerStrength": 0.518713248970312,
"repelStrength": 10,
"linkStrength": 1,
"linkDistance": 250,
"scale": 0.08317427835927536,
"close": false
}
+187
View File
@@ -0,0 +1,187 @@
{
"main": {
"id": "59f0bd68c638b9ae",
"type": "split",
"children": [
{
"id": "6e3e7f0212dd6d2e",
"type": "tabs",
"children": [
{
"id": "5e19c94f304a33d1",
"type": "leaf",
"state": {
"type": "graph",
"state": {},
"icon": "lucide-git-fork",
"title": "그래프 뷰"
}
}
]
}
],
"direction": "vertical"
},
"left": {
"id": "b20f341b7d225db0",
"type": "split",
"children": [
{
"id": "76facd68bdc37a30",
"type": "tabs",
"children": [
{
"id": "697d93dc46e83f99",
"type": "leaf",
"state": {
"type": "file-explorer",
"state": {
"sortOrder": "alphabetical",
"autoReveal": false
},
"icon": "lucide-folder-closed",
"title": "파일 탐색기"
}
},
{
"id": "14386382787eb545",
"type": "leaf",
"state": {
"type": "search",
"state": {
"query": "",
"matchingCase": false,
"explainSearch": false,
"collapseAll": false,
"extraContext": false,
"sortOrder": "alphabetical"
},
"icon": "lucide-search",
"title": "검색"
}
},
{
"id": "6544f7f2d2bdb927",
"type": "leaf",
"state": {
"type": "bookmarks",
"state": {},
"icon": "lucide-bookmark",
"title": "북마크"
}
}
]
}
],
"direction": "horizontal",
"width": 300
},
"right": {
"id": "eb1afd59f22726e4",
"type": "split",
"children": [
{
"id": "cff2bf89b29bbdad",
"type": "tabs",
"children": [
{
"id": "a06f05e29da92edb",
"type": "leaf",
"state": {
"type": "backlink",
"state": {
"collapseAll": false,
"extraContext": false,
"sortOrder": "alphabetical",
"showSearch": false,
"searchQuery": "",
"backlinkCollapsed": false,
"unlinkedCollapsed": true
},
"icon": "links-coming-in",
"title": "백링크"
}
},
{
"id": "461414a74ff42c5f",
"type": "leaf",
"state": {
"type": "outgoing-link",
"state": {
"linksCollapsed": false,
"unlinkedCollapsed": true
},
"icon": "links-going-out",
"title": "나가는 링크"
}
},
{
"id": "2c463caabad51324",
"type": "leaf",
"state": {
"type": "tag",
"state": {
"sortOrder": "frequency",
"useHierarchy": true,
"showSearch": false,
"searchQuery": ""
},
"icon": "lucide-tags",
"title": "태그"
}
},
{
"id": "e863614ec11ec6c0",
"type": "leaf",
"state": {
"type": "all-properties",
"state": {
"sortOrder": "frequency",
"showSearch": false,
"searchQuery": ""
},
"icon": "lucide-archive",
"title": "모든 속성"
}
},
{
"id": "0f1cc972aeac180a",
"type": "leaf",
"state": {
"type": "outline",
"state": {
"followCursor": false,
"showSearch": false,
"searchQuery": ""
},
"icon": "lucide-list",
"title": "개요"
}
}
]
}
],
"direction": "horizontal",
"width": 300,
"collapsed": true
},
"left-ribbon": {
"hiddenItems": {
"switcher:빠른 전환기 열기": false,
"graph:그래프 뷰 열기": false,
"canvas:새 캔버스 만들기": false,
"daily-notes:오늘의 일일 노트 열기": false,
"templates:템플릿 삽입": false,
"command-palette:명령어 팔레트 열기": false,
"bases:새 베이스 생성하기": false
}
},
"active": "5e19c94f304a33d1",
"lastOpenFiles": [
"Systemic_Simulation_Principles.md",
"DevOps_Environment_Setup.md",
"Separation_of_Concerns.md",
"Single_Source_of_Truth.md",
"WebWorker_Performance.md"
]
}
@@ -0,0 +1,24 @@
---
title: 개발 환경 및 실행 프로세스 관리 (DevOps & Setup)
category: DevOps
tags: [DevOps, Environment, CI/CD, Process Management]
created: 2026-04-20
---
# 개발 환경 및 실행 프로세스 관리
## 🎯 개요 (Overview)
코딩 완성도만큼이나 중요한 **실행 환경(Runtime Environment)**과 **설정 파일(Configuration)**의 무결성을 확보하여, '내 컴퓨터에선 되는데 왜 저기선 안 되지?'라는 문제를 해결하는 프로세스입니다.
## 🚀 필수 체크리스트 (Checklist)
- **의존성 관리**: `npm install` 등 패키지 무결성 확인.
- **물리적 파일 구조**: `index.html` 등 필수 진입점 파일 존재 확인.
- **보안 및 권한**: OS 레벨의 실행 정책(`Execution Policy`) 및 권한 설정.
## 💡 레슨 런 (Lesson Learned)
> [!NOTE]
> **"운영 환경에 대한 이해는 코딩 능력의 절반이다."**
> 논리적 로직의 완성뿐만 아니라, 그것이 실제로 구동되는 물리적 인프라 설정을 문서화하고 자동화하는 능력이 필수적입니다.
## 🔗 연결된 지식
- [[Systemic_Simulation_Principles]]
+25
View File
@@ -0,0 +1,25 @@
---
title: 시스템 아키텍처와 관심사 분리 (Separation of Concerns)
category: Software Architecture
tags: [Architecture, SoC, Modular Design, Design Pattern]
created: 2026-04-20
---
# 시스템 아키텍처와 관심사 분리 (SoC)
## 🎯 개요 (Overview)
복잡한 소프트웨어 시스템을 역할별로 구분된 독립적인 모듈로 나누어, 유지보수성과 확장성을 극대화하는 설계 철학입니다.
## 🚀 계층구조 예시 (Layering Example)
1. **Logic Engine**: 순수 비즈니스 로직 및 규칙 수행 (예: `gameWorker.js`)
2. **State Manager**: 데이터의 중앙 집중 처리 (예: `TetrisGame.jsx`)
3. **View Layer**: 사용자 인터페이스 표현 및 렌더링 (예: React Components)
## 💡 레슨 런 (Lesson Learned)
> [!IMPORTANT]
> **"코드의 경계가 명확할 때 시스템은 비로소 건강해진다."**
> 기능을 추가할 때 기존 코드를 수정하기보다 새로운 모듈을 덧붙일 수 있는 구조를 고민해야 합니다.
## 🔗 연결된 지식
- [[WebWorker_Performance]]
- [[Single_Source_of_Truth]]
+24
View File
@@ -0,0 +1,24 @@
---
title: 상태 관리의 단일 진실 공급원 (Single Source of Truth)
category: Software Architecture
tags: [State Management, Data Consistency, Redux, Architecture]
created: 2026-04-20
---
# 상태 관리의 단일 진실 공급원 (Single Source of Truth)
## 🎯 개요 (Overview)
시스템의 핵심 데이터를 중앙 집중식으로 관리하여, 데이터 불일치(Inconsistency) 현상을 원천 차단하고 예측 가능한 데이터 흐름을 확보하는 설계 원칙입니다.
## 🚀 주요 원칙 (Key Principles)
- **단일 지점 정의 (Defined at Single Point)**: 상태는 오직 한 곳에서만 정의되고 관리되어야 합니다.
- **예측 가능성 (Predictability)**: 상태 변경은 정해진 규칙(Action/Setter)을 통해서만 발생하여 디버깅을 용이하게 합니다.
## 💡 레슨 런 (Lesson Learned)
> [!TIP]
> **"상태는 오직 한 곳에서만 정의하고, 모든 로직은 그 상태를 읽고 쓰는 방식으로 동작해야 한다."**
> 코드의 파편화를 막기 위해 데이터의 책임 범위(Responsibility)를 명확히 하는 것이 대규모 프로젝트 성공의 열쇠입니다.
## 🔗 연결된 지식
- [[Separation_of_Concerns]]
- [[Domain-Driven Design (DDD)]]
@@ -0,0 +1,24 @@
---
title: 시스템 시뮬레이션 설계 원리
category: Systemic Modeling & Fun
tags: [Simulation, Physics Engine, Systemic Modeling, Ruleset]
created: 2026-04-20
---
# 시스템 시뮬레이션 설계 원리
## 🎯 개요 (Overview)
현실 세계의 물리 법칙이나 비즈니스 규칙을 수학적으로 정의하고, 이를 절대적으로 우회할 수 없는 시스템 내의 법(Law)으로 구축하는 설계 기법입니다.
## 🚀 핵심 메커니즘 (Mechanisms)
- **규칙 강제 (Ruleset Enforcement)**: 모든 상태 변화는 사전에 정의된 물리 엔진 함수(`checkCollision` 등)를 거쳐야만 합니다.
- **수학적 모델링**: 변화를 시각적 묘사가 아닌 데이터와 수식으로 먼저 증명합니다.
## 💡 레슨 런 (Lesson Learned)
> [!TIP]
> **"모든 시뮬레이션은 수학적 규칙을 절대 우회할 수 없도록 강제해야 한다."**
> 이를 통해 단순한 게임을 넘어 자율주행, 물리 엔진 등 고도의 결정론적 시스템 모델링이 가능해집니다.
## 🔗 연결된 지식
- [[WebWorker_Performance]]
- [[Separation_of_Concerns]]
+24
View File
@@ -0,0 +1,24 @@
---
title: WebWorker를 이용한 고성능 아키텍처 설계
category: Web & Performance
tags: [Web Worker, Concurrency, Performance, UI responsiveness]
created: 2026-04-20
---
# WebWorker를 이용한 고성능 아키텍처 설계
## 🎯 개요 (Overview)
실시간 상태 변화가 매우 빈번한 애플리케이션(예: 게임, 시뮬레이션)에서 UI 스레드와 복잡한 연산 로직을 분리하여 **프레임 드롭(Jank)**을 방지하는 아키텍처 설계 기법입니다.
## 🚀 주요 원칙 (Key Principles)
- **스레드 분리 (Thread Isolation)**: 무거운 계산은 백그라운드 스레드(Web Worker)에서 수행하고, 메인 스레드는 렌더링에만 집중합니다.
- **메시징 기반 통신 (Messaging Architecture)**: `postMessage``onmessage`를 통해 비동기적으로 데이터를 주고받아 결합도를 낮춥니다.
## 💡 레슨 런 (Lesson Learned)
> [!IMPORTANT]
> **"성능 병목 현상은 종종 '스레딩(Threading)'의 문제이다."**
> 복잡한 물리 계산이나 루프가 UI 응답성을 해치지 않도록, 연산 엔진을 완전히 별도의 스레드로 격리하는 것이 부드러운 UX의 핵심입니다.
## 🔗 연결된 지식
- [[Separation_of_Concerns]]
- [[Systemic_Simulation_Principles]]
+21
View File
@@ -0,0 +1,21 @@
{
"name": "tetris-game",
"version": "1.0.0",
"description": "A high-performance Tetris game using Web Workers.",
"main": "src/index.js",
"scripts": {
"start": "react-scripts start",
"build": "react-scripts build",
"test": "react-scripts test"
},
"dependencies": {
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-scripts": "5.0.1"
},
"scripts": {
"start": "react-scripts start",
"build": "react-scripts build",
"test": "react-scripts test"
}
}
+97
View File
@@ -0,0 +1,97 @@
import React, { useState, useEffect, useCallback } from 'react';
const TetrisGame = () => {
// [State Management] 전역 상태: 보드와 현재 블록 정보를 저장합니다.
const [gameState, setGameState] = useState({ board: [], piece: null });
const [workerStatus, setWorkerStatus] = useState("Initializing...");
useEffect(() => {
// 1. Web Worker 초기화 및 통신 설정
const worker = new Worker(new URL('./gameWorker.js', import.meta.url), { type: 'module' });
setWorkerStatus("Running...");
// 2. 워커로부터 메시지를 수신할 리스너 등록 (Web Worker의 핵심)
worker.onmessage = (e) => {
const data = e.data;
if (data.type === 'READY' || data.type === 'UPDATE') {
// 받은 데이터를 전역 상태로 업데이트합니다. (Single Source of Truth 원칙 준수)
setGameState({ board: data.board, piece: data.piece });
} else if (data.type === 'ERROR') {
console.error("Game Worker Error:", data.message);
}
};
// 3. 워커에 초기화 명령 전송 (Worker 시작)
worker.postMessage({ type: 'INIT' });
// Cleanup 함수: 컴포넌트 언마운트 시 워커를 종료합니다.
return () => {
worker.terminate();
};
}, []); // 마운트 시 한 번만 실행 (useEffect)
// [Game Loop] 게임 루프 관리 (핵심 성능 최적화 부분)
const handleGameLoop = useCallback(() => {
if (!gameState.piece) return;
// 1초에 1번씩 gravity step을 요청합니다.
const worker = new Worker(new URL('./gameWorker.js', import.meta.url), { type: 'module' });
worker.postMessage({ type: 'MOVE_STEP', payload: {} });
// 다음 프레임에서 다시 이 함수를 호출하여 지속적인 움직임을 만듭니다.
requestAnimationFrame(handleGameLoop);
}, [gameState.piece]); // piece가 있을 때만 루프 시작
useEffect(() => {
if (gameState.piece) {
const animationFrameId = requestAnimationFrame(handleGameLoop);
return () => cancelAnimationFrame(animationFrameId);
}
}, [gameState.piece, handleGameLoop]);
// 렌더링 로직: 게임 보드와 블록을 시각화합니다.
const renderBoard = () => {
return (
<div style={styles.board}>
{/* React는 배열의 배열을 순회하며 각 셀에 CSS 클래스를 적용하여 렌더링합니다. */}
{gameState.board.map((row, y) => (
<div key={y} style={{ display: 'flex' }}>
{row.map((cell, x) => (
<div
key={`${x}-${y}`}
style={cell > 0 ? styles.occupied : {}}
title={`(${x}, ${y})`}
></div>
))}
</div>
))}
</div>
);
};
return (
<div style={styles.container}>
<h1>Tetris Clone: High-Performance Engine</h1>
<p>Status: {workerStatus}</p>
{renderBoard()}
<button onClick={() => console.log("Game Controls Here!")} disabled={!gameState.piece}>
(이동/회전 버튼)
</button>
</div>
);
};
const styles = {
container: { padding: '20px', fontFamily: 'Arial, sans-serif' },
board: {
display: 'flex',
flexDirection: 'column',
border: '4px solid #333',
width: '250px'
},
occupied: { backgroundColor: '#ccc', border: '1px solid #aaa' }
};
export default TetrisGame;
+73
View File
@@ -0,0 +1,73 @@
/**
* @file Web Worker: Tetris Game Logic Engine (The Core Rulebook)
* 이 파일은 메인 스레드와 분리되어 실행되며, 게임의 모든 물리적 규칙을 처리합니다.
*/
let gameBoard = []; // 20x10 Grid representation
const BOARD_WIDTH = 10;
const BOARD_HEIGHT = 20;
// 초기 보드 상태 설정 (빈 공간)
function initializeBoard() {
gameBoard = Array(BOARD_HEIGHT).fill(null).map(() => Array(BOARD_WIDTH).fill(0));
}
// 블록 생성 로직 (랜덤 모양, 랜덤 위치)
function generatePiece() {
// 실제로는 다양한 T, L, I, O 등의 형태를 정의해야 함. 여기서는 단순 예시로 대체합니다.
return { shape: [/* 4x4 matrix for a piece */], color: Math.random(), x: Math.floor(Math.random() * (BOARD_WIDTH - 3)), y: 0 };
}
// 충돌 감지 로직 (Collision Detection)
function checkCollision(piece, newX, newY) {
for (let row = 0; row < piece.shape.length; row++) {
for (let col = 0; col < piece.shape[row].length; col++) {
if (piece.shape[row][col] !== 0) {
const boardX = newX + col;
const boardY = newY + row;
// 경계 체크 또는 이미 블록이 있는 경우 충돌 발생
if (boardX < 0 || boardX >= BOARD_WIDTH || boardY >= BOARD_HEIGHT || gameBoard[boardY][boardX] !== 0) {
return true; // Collision detected
}
}
}
}
return false;
}
// 게임의 핵심 로직: 한 스텝 진행 (Gravity Step)
function movePiece(dx, dy) {
let newX = piece.x + dx;
let newY = piece.y + dy;
if (!checkCollision(piece, newX, newY)) {
// 1. 상태 업데이트: 보드의 좌표와 블록을 이동시킵니다.
// 2. 충돌 체크 및 고정: 바닥 또는 다른 블록에 닿으면, 해당 위치를 게임 보드에 영구적으로 기록합니다.
// 3. 라인 제거 (Line Clearing): 가득 찬 행(Row)을 찾아 지우고 위쪽 행들을 아래로 떨어뜨립니다.
return { success: true, board: [...gameBoard], piece: {...piece} };
} else {
return { success: false, message: "Collision" };
}
}
// 메인 게임 루프 (Game Loop)
self.onmessage = function(e) {
const { type, payload } = e.data;
switch (type) {
case 'INIT':
initializeBoard();
// 초기 블록 생성 및 상태 전송
self.postMessage({ type: 'READY', board: gameBoard, piece: generatePiece() });
break;
case 'MOVE_STEP':
// 실제 게임 루프의 핵심 로직 호출
const result = movePiece(payload.dx || 0, payload.dy || 1);
self.postMessage({ type: 'UPDATE', board: result.board, piece: result.piece });
break;
case 'ROTATE':
// 블록 회전 로직 구현 (Omitted for brevity)
break;
}
};