๐ŸŽฎ g5se ๋ฏธ๋‹ˆ ๊ฒŒ์ž„ ์„ผํ„ฐ - ๋ธŒ๋ผ์šฐ์ € ์•„์ผ€์ด๋“œ ๋ชจ์Œ - ๋ฐ”์ด๋ธŒ์ฝ”๋”ฉ ๋ ˆ์‹œํ”ผ
์ž…๋ฌธ PHP g5se AI: Claude

๐ŸŽฎ g5se ๋ฏธ๋‹ˆ ๊ฒŒ์ž„ ์„ผํ„ฐ - ๋ธŒ๋ผ์šฐ์ € ์•„์ผ€์ด๋“œ ๋ชจ์Œ

๋ฆฌํฌ์ง€ํ† ๋ฆฌ๋ช… g5se-browser-arcade
์กฐํšŒ์ˆ˜ 57 0๊ฑด ์ œ์ถœ

๋ฌธ์ œ ์„ค๋ช…

๐ŸŽฏ ํ”„๋กœ์ ํŠธ ๊ฐœ์š”

g5se ์œ„์—์„œ ๋™์ž‘ํ•˜๋Š” ๊ฐ€๋ฒผ์šด ๋ธŒ๋ผ์šฐ์ € ๊ฒŒ์ž„ ๋ชจ์Œ ํŽ˜์ด์ง€๋ฅผ ๋งŒ๋“ญ๋‹ˆ๋‹ค. ์—ฌ๋Ÿฌ ๋ฏธ๋‹ˆ ๊ฒŒ์ž„์„ ํ•œ ๊ณณ์— ๋ชจ์•„๋‘๊ณ , ๊ฐ ๊ฒŒ์ž„์˜ ์ตœ๊ณ  ๊ธฐ๋ก์„ SQLite DB์— ์ €์žฅํ•ฉ๋‹ˆ๋‹ค. ์‚ฌ์šฉ์ž๋Š” ๊ฒŒ์ž„ ๋ชฉ๋ก์„ ๋ณด๊ณ  ์›ํ•˜๋Š” ๊ฒŒ์ž„์„ ์„ ํƒํ•ด์„œ ํ”Œ๋ ˆ์ดํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๐Ÿ“‹ ํ•„์ˆ˜ ๊ธฐ๋Šฅ

1. ๊ฒŒ์ž„ ๋ชฉ๋ก ๋ฉ”์ธ ํŽ˜์ด์ง€

  • ์นด๋“œ ๊ทธ๋ฆฌ๋“œ ๋ ˆ์ด์•„์›ƒ์œผ๋กœ ๊ฒŒ์ž„ ๋ชฉ๋ก ํ‘œ์‹œ
  • ๊ฐ ์นด๋“œ: ๊ฒŒ์ž„ ์ œ๋ชฉ, ๊ฐ„๋‹จํ•œ ์„ค๋ช…, ์ธ๋„ค์ผ ์•„์ด์ฝ˜(์ด๋ชจ์ง€), ์ตœ๊ณ  ๊ธฐ๋ก
  • ์นด๋“œ ํด๋ฆญ ์‹œ ํ•ด๋‹น ๊ฒŒ์ž„ ํŽ˜์ด์ง€๋กœ ์ด๋™
  • modern shell ์ ์šฉ์œผ๋กœ ์‚ฌ์ดํŠธ nav/footer ํ†ต์ผ

2. ๊ฒŒ์ž„ 1: ์ˆซ์ž ๋งž์ถ”๊ธฐ (Number Guess)

  • 1~100 ์‚ฌ์ด ๋žœ๋ค ์ˆซ์ž๋ฅผ ๋งž์ถ”๋Š” ๊ฒŒ์ž„
  • ์ž…๋ ฅ ํ›„ "Up" ๋˜๋Š” "Down" ํžŒํŠธ ์ œ๊ณต
  • ์‹œ๋„ ํšŸ์ˆ˜ ์นด์šดํŠธ
  • ์ •๋‹ต ์‹œ ์‹œ๋„ ํšŸ์ˆ˜๋ฅผ DB์— ์ €์žฅ (์ตœ์†Œ ์‹œ๋„ ํšŸ์ˆ˜๊ฐ€ ์ตœ๊ณ  ๊ธฐ๋ก)
  • "๋‹ค์‹œ ํ•˜๊ธฐ" ๋ฒ„ํŠผ์œผ๋กœ ๊ฒŒ์ž„ ๋ฆฌ์…‹

3. ๊ฒŒ์ž„ 2: ์ƒ‰๊น” ๊ธฐ์–ตํ•˜๊ธฐ (Color Memory)

  • 4๊ฐœ์˜ ์ƒ‰๊น” ๋ฒ„ํŠผ(๋นจ๊ฐ•, ํŒŒ๋ž‘, ๋…ธ๋ž‘, ์ดˆ๋ก)
  • ๋žœ๋ค ์ˆœ์„œ๋กœ ์ƒ‰๊น”์ด ๊นœ๋นก์ด๋ฉฐ ํŒจํ„ด ํ‘œ์‹œ
  • ์‚ฌ์šฉ์ž๊ฐ€ ๊ฐ™์€ ์ˆœ์„œ๋กœ ํด๋ฆญํ•ด์•ผ ํ•จ
  • ๋ผ์šด๋“œ๋งˆ๋‹ค ํŒจํ„ด ๊ธธ์ด +1
  • ์‹คํŒจ ์‹œ ๋ผ์šด๋“œ ์ˆ˜๋ฅผ DB์— ์ €์žฅ (์ตœ๋Œ€ ๋ผ์šด๋“œ๊ฐ€ ์ตœ๊ณ  ๊ธฐ๋ก)

4. ๊ฒŒ์ž„ 3: ๋ฐ˜์‘์†๋„ ํ…Œ์ŠคํŠธ (Reaction Speed)

  • "์ค€๋น„" ํ™”๋ฉด โ†’ ๋žœ๋ค ๋”œ๋ ˆ์ด ํ›„ "ํด๋ฆญ!" ํ™”๋ฉด์œผ๋กœ ์ „ํ™˜
  • ํ™”๋ฉด์ด ๋ฐ”๋€Œ๋Š” ์ˆœ๊ฐ„๋ถ€ํ„ฐ ํด๋ฆญ๊นŒ์ง€ ๊ฑธ๋ฆฐ ์‹œ๊ฐ„(ms) ์ธก์ •
  • 3ํšŒ ์ธก์ • ํ›„ ํ‰๊ท  ๋ฐ˜์‘์†๋„๋ฅผ DB์— ์ €์žฅ (์ตœ์†Œ ์‹œ๊ฐ„์ด ์ตœ๊ณ  ๊ธฐ๋ก)

5. ์ตœ๊ณ  ๊ธฐ๋ก ๊ด€๋ฆฌ

  • ๊ฐ ๊ฒŒ์ž„๋ณ„๋กœ ์ตœ๊ณ  ๊ธฐ๋ก 1๊ฐœ๋งŒ ์œ ์ง€ (๊ฐฑ์‹  ์‹œ UPDATE)
  • ๋ฉ”์ธ ํŽ˜์ด์ง€ ์นด๋“œ์— ์ตœ๊ณ  ๊ธฐ๋ก ํ‘œ์‹œ
  • ๊ฒŒ์ž„ ํŽ˜์ด์ง€์—๋„ ํ˜„์žฌ ์ตœ๊ณ  ๊ธฐ๋ก ํ‘œ์‹œ

๐ŸŽจ ๋””์ž์ธ ์š”๊ตฌ์‚ฌํ•ญ

  • modern shell์˜ CSS ๋ณ€์ˆ˜(--m-surface, --m-text, --m-shadow ๋“ฑ) ํ™œ์šฉ์œผ๋กœ ๋‹คํฌ๋ชจ๋“œ ์ž๋™ ๋Œ€์‘
  • ๊ฒŒ์ž„ ์นด๋“œ๋Š” hover ์‹œ ์‚ด์ง ๋– ์˜ค๋ฅด๋Š” ํšจ๊ณผ
  • ๊ฒŒ์ž„ ํ”Œ๋ ˆ์ด ์˜์—ญ์€ ์ค‘์•™ ์ •๋ ฌ, ์ตœ๋Œ€ ๋„ˆ๋น„ 600px
  • ๋ฒ„ํŠผ์€ ํผ์งํ•˜๊ณ  ํ„ฐ์น˜ํ•˜๊ธฐ ํŽธํ•œ ํฌ๊ธฐ(์ตœ์†Œ 48px ๋†’์ด)
  • ๊ฒŒ์ž„๋ณ„ ์‹œ๊ฐ์  ์ •์ฒด์„ฑ: ์ˆซ์ž ๋งž์ถ”๊ธฐ(๋ณด๋ผ), ์ƒ‰๊น” ๊ธฐ์–ต(๋ฌด์ง€๊ฐœ), ๋ฐ˜์‘์†๋„(์ฃผํ™ฉ) ๋“ฑ ๊ฐ•์กฐ ์ƒ‰์ƒ ์‚ฌ์šฉ ๊ฐ€๋Šฅ

๐Ÿ—„๏ธ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ์Šคํ‚ค๋งˆ

CREATE TABLE IF NOT EXISTS game_records (
  game_id TEXT PRIMARY KEY,  -- 'number_guess', 'color_memory', 'reaction_speed'
  best_score INTEGER NOT NULL,
  updated_at TEXT DEFAULT CURRENT_TIMESTAMP
);

๐Ÿš€ ๋ณด๋„ˆ์Šค ๊ธฐ๋Šฅ (์„ ํƒ)

  • ๊ฒŒ์ž„ 4 ์ถ”๊ฐ€: ํƒ€์ดํ•‘ ์†๋„ ํ…Œ์ŠคํŠธ (์ฃผ์–ด์ง„ ๋ฌธ์žฅ์„ ์–ผ๋งˆ๋‚˜ ๋นจ๋ฆฌ ์ •ํ™•ํžˆ ํƒ€์ดํ•‘ํ•˜๋Š”์ง€)
  • ์• ๋‹ˆ๋ฉ”์ด์…˜ ํšจ๊ณผ (์ •๋‹ต ์‹œ confetti, ์˜ค๋‹ต ์‹œ shake)
  • ์‚ฌ์šด๋“œ ํšจ๊ณผ (๋ฒ„ํŠผ ํด๋ฆญ, ์ •๋‹ต/์˜ค๋‹ต ์†Œ๋ฆฌ)
  • ๋žญํ‚น ์‹œ์Šคํ…œ (ํšŒ์› ์—ฐ๋™ ์‹œ ์‚ฌ์šฉ์ž๋ณ„ ๊ธฐ๋ก ์ €์žฅ)
  • ๊ณต์œ  ๊ธฐ๋Šฅ ("๋‚ด ๊ธฐ๋ก: X์ดˆ!" SNS ๊ณต์œ  ํ…์ŠคํŠธ ์ƒ์„ฑ)

๐Ÿ“ฆ ๊ธฐ์ˆ  ์Šคํƒ

  • g5se (๊ทธ๋ˆ„๋ณด๋“œ5 SE) - PHP ๊ธฐ๋ฐ˜ CMS
  • SQLite - ๊ฒŒ์ž„ ๊ธฐ๋ก ์ €์žฅ (๋ชจ๋“ˆ ์ „์šฉ DB ํŒŒ์ผ)
  • ์ˆœ์ˆ˜ JavaScript - ๊ฒŒ์ž„ ๋กœ์ง & ์ธํ„ฐ๋ž™์…˜
  • CSS3 - ์• ๋‹ˆ๋ฉ”์ด์…˜ & ๋ ˆ์ด์•„์›ƒ
  • modern shell - ์‚ฌ์ดํŠธ ํ†ต์ผ UI

์ œ์•ฝ ์กฐ๊ฑด

  • โ€ข g5se ์„ค์น˜๋ณธ ์œ„์— ๋ชจ๋“ˆ๋กœ ์ถ”๊ฐ€ (์ƒˆ ํ”„๋กœ์ ํŠธ ์ƒ์„ฑ ์•„๋‹˜)
  • โ€ข ํด๋” ๊ธฐ๋ฐ˜ ์ž๋™ ๋ผ์šฐํŒ… ์‚ฌ์šฉ: app/modules/arcade/ ํ•˜์œ„์— ํŽ˜์ด์ง€ ๊ตฌ์„ฑ
  • โ€ข ๋ผ์šฐํŠธ ์ˆ˜๋™ ๋“ฑ๋ก ๊ธˆ์ง€ (ํด๋” ๊ตฌ์กฐ๊ฐ€ ๊ณง URL)
  • โ€ข modern shell ํ•„์ˆ˜ ์ ์šฉ (_head.inc.php + m-shell + _nav.inc.php + m-container + _footer.inc.php + tail.sub.php)
  • โ€ข CSS ๋ณ€์ˆ˜(--m-surface, --m-text ๋“ฑ) ํ™œ์šฉ์œผ๋กœ ๋‹คํฌ๋ชจ๋“œ ์ž๋™ ๋Œ€์‘
  • โ€ข g5se ๋ฉ”์ธ DB ์ ˆ๋Œ€ ๊ฑด๋“œ๋ฆฌ์ง€ ๋ง ๊ฒƒ - ๋ชจ๋“ˆ ์ „์šฉ SQLite ํŒŒ์ผ ์‚ฌ์šฉ (G5_DATA_PATH/modules/arcade.sqlite)
  • โ€ข ์™ธ๋ถ€ ๋นŒ๋“œ ๋„๊ตฌ(npm/webpack) ์‚ฌ์šฉ ๊ธˆ์ง€
  • โ€ข CDN ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ์‚ฌ์šฉ ์ตœ์†Œํ™” (์ˆœ์ˆ˜ JS/CSS ๊ถŒ์žฅ)
  • โ€ข prepared statement๋กœ SQL ์ธ์ ์…˜ ๋ฐฉ์ง€
  • โ€ข ์‚ฌ์šฉ์ž ์ž…๋ ฅ์€ htmlspecialchars()๋กœ ์ด์Šค์ผ€์ดํ”„
  • โ€ข ๋ชจ๋“  ๊ฒฝ๋กœ๋Š” ์ƒ๋Œ€๊ฒฝ๋กœ(./) ์‚ฌ์šฉ
  • โ€ข ์ง„์ž… ๊ฐ€๋“œ ์žฌ์ •์˜ ๊ธˆ์ง€ (๋ฃจํŠธ index.php๊ฐ€ ์ด๋ฏธ ์ฒ˜๋ฆฌ)
  • โ€ข require/include๋Š” ๋ฐ˜๋“œ์‹œ ๊ธ€๋กœ๋ฒŒ ์Šค์ฝ”ํ”„์—์„œ๋งŒ (ํ•จ์ˆ˜/๋ฉ”์„œ๋“œ ์•ˆ ๊ธˆ์ง€)

ํ”„๋กฌํ”„ํŠธ ๋ ˆ์‹œํ”ผ

์•„๋ž˜ ํ”„๋กฌํ”„ํŠธ๋ฅผ ์ˆœ์„œ๋Œ€๋กœ AI์—๊ฒŒ ๋ณด๋‚ด๋ฉด ๋ฉ๋‹ˆ๋‹ค. ๋ณต์‚ฌ ๋ฒ„ํŠผ์„ ๋ˆŒ๋Ÿฌ ๋ฐ”๋กœ ์‚ฌ์šฉํ•˜์„ธ์š”.

1
Step 1
g5se๊ฐ€ ์„ค์น˜๋œ ๋””๋ ‰ํ„ฐ๋ฆฌ(๋ฃจํŠธ์— `index.php`ยท`app/`์ด ์žˆ๋Š” ๊ณณ)์—์„œ ์ž‘์—…์„ ์‹œ์ž‘ํ•ฉ๋‹ˆ๋‹ค. (g5se ์„ค์น˜๋Š” https://github.com/gnuboard/g5se ์ฐธ๊ณ )

์ด์ œ ๊ฒŒ์ž„ ์„ผํ„ฐ ๋ชจ๋“ˆ์˜ ๋ฉ”์ธ ํŽ˜์ด์ง€๋ฅผ ๋งŒ๋“ค๊ฒ ์Šต๋‹ˆ๋‹ค.

**1๋‹จ๊ณ„: ํด๋” ๊ตฌ์กฐ ์ƒ์„ฑ ๋ฐ ๋ฉ”์ธ ํŽ˜์ด์ง€ ํŒŒ์ผ ์ƒ์„ฑ**

```bash
mkdir -p app/modules/arcade
```

**2๋‹จ๊ณ„: app/modules/arcade/index.php ํŒŒ์ผ ์ƒ์„ฑ**

์•„๋ž˜ ๋‚ด์šฉ์œผ๋กœ `app/modules/arcade/index.php` ํŒŒ์ผ์„ ๋งŒ๋“ค์–ด์ฃผ์„ธ์š”:

```php
<?php
include_once('./_common.php');

// ๊ฒŒ์ž„ ๋ชฉ๋ก ์ •์˜
$games = [
    [
        'id' => 'number_guess',
        'title' => '๐Ÿ”ข ์ˆซ์ž ๋งž์ถ”๊ธฐ',
        'description' => '1~100 ์‚ฌ์ด ์ˆซ์ž๋ฅผ ์ตœ์†Œ ์‹œ๋„๋กœ ๋งž์ถฐ๋ณด์„ธ์š”!',
        'icon' => '๐ŸŽฏ',
        'url' => '/arcade/number-guess'
    ],
    [
        'id' => 'color_memory',
        'title' => '๐ŸŒˆ ์ƒ‰๊น” ๊ธฐ์–ตํ•˜๊ธฐ',
        'description' => '๊นœ๋นก์ด๋Š” ์ƒ‰๊น” ํŒจํ„ด์„ ๊ธฐ์–ตํ•˜๊ณ  ๋”ฐ๋ผํ•ด๋ณด์„ธ์š”!',
        'icon' => '๐Ÿง ',
        'url' => '/arcade/color-memory'
    ],
    [
        'id' => 'reaction_speed',
        'title' => 'โšก ๋ฐ˜์‘์†๋„ ํ…Œ์ŠคํŠธ',
        'description' => 'ํ™”๋ฉด์ด ๋ฐ”๋€Œ๋Š” ์ˆœ๊ฐ„ ์–ผ๋งˆ๋‚˜ ๋นจ๋ฆฌ ํด๋ฆญํ•  ์ˆ˜ ์žˆ๋‚˜์š”?',
        'icon' => 'โฑ๏ธ',
        'url' => '/arcade/reaction-speed'
    ]
];

// DB ์—ฐ๊ฒฐ ๋ฐ ์ตœ๊ณ  ๊ธฐ๋ก ์กฐํšŒ
@mkdir(G5_DATA_PATH.'/modules', 0707, true);
$db = new PDO('sqlite:'.G5_DATA_PATH.'/modules/arcade.sqlite');
$db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);

// ํ…Œ์ด๋ธ” ์ƒ์„ฑ
$db->exec("CREATE TABLE IF NOT EXISTS game_records (
    game_id TEXT PRIMARY KEY,
    best_score INTEGER NOT NULL,
    updated_at TEXT DEFAULT CURRENT_TIMESTAMP
)");

// ๊ฐ ๊ฒŒ์ž„์˜ ์ตœ๊ณ  ๊ธฐ๋ก ์กฐํšŒ
$stmt = $db->prepare("SELECT game_id, best_score FROM game_records");
$stmt->execute();
$records = [];
while ($row = $stmt->fetch(PDO::FETCH_ASSOC)) {
    $records[$row['game_id']] = $row['best_score'];
}

require_once(G5_THEME_PATH.'/modern/_head.inc.php');
include_once('./head.sub.php');
?>
<style>
.arcade-header {
    text-align: center;
    margin-bottom: 48px;
}
.arcade-header h1 {
    font-size: 2.5rem;
    font-weight: 700;
    margin-bottom: 12px;
    color: var(--m-text);
}
.arcade-header p {
    font-size: 1.125rem;
    color: var(--m-text-muted);
}
.game-grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
    gap: 24px;
    max-width: 1000px;
    margin: 0 auto;
}
.game-card {
    background: var(--m-surface);
    border-radius: var(--m-radius-lg);
    padding: 32px 24px;
    text-align: center;
    box-shadow: var(--m-shadow);
    transition: transform 0.2s, box-shadow 0.2s;
    cursor: pointer;
    text-decoration: none;
    color: var(--m-text);
    display: block;
}
.game-card:hover {
    transform: translateY(-4px);
    box-shadow: 0 8px 24px rgba(0,0,0,0.12);
}
.game-icon {
    font-size: 4rem;
    margin-bottom: 16px;
}
.game-title {
    font-size: 1.5rem;
    font-weight: 700;
    margin-bottom: 8px;
}
.game-description {
    font-size: 0.875rem;
    color: var(--m-text-muted);
    margin-bottom: 16px;
    line-height: 1.5;
}
.game-record {
    display: inline-block;
    background: rgba(99, 102, 241, 0.1);
    color: #6366f1;
    padding: 6px 12px;
    border-radius: 12px;
    font-size: 0.875rem;
    font-weight: 600;
}
</style>

<div class="m-shell">
    <?php require G5_THEME_PATH.'/modern/_nav.inc.php'; ?>
    <main class="m-container" style="padding: 48px 20px;">
        <div class="arcade-header">
            <h1>๐ŸŽฎ ๋ฏธ๋‹ˆ ๊ฒŒ์ž„ ์„ผํ„ฐ</h1>
            <p>๋ธŒ๋ผ์šฐ์ €์—์„œ ์ฆ๊ธฐ๋Š” ๊ฐ„๋‹จํ•œ ์•„์ผ€์ด๋“œ ๊ฒŒ์ž„ ๋ชจ์Œ</p>
        </div>
        
        <div class="game-grid">
            <?php foreach ($games as $game): ?>
                <a href="<?php echo htmlspecialchars($game['url']); ?>" class="game-card">
                    <div class="game-icon"><?php echo $game['icon']; ?></div>
                    <div class="game-title"><?php echo htmlspecialchars($game['title']); ?></div>
                    <div class="game-description"><?php echo htmlspecialchars($game['description']); ?></div>
                    <?php if (isset($records[$game['id']])): ?>
                        <div class="game-record">
                            <?php 
                            if ($game['id'] === 'number_guess') {
                                echo '์ตœ์†Œ ์‹œ๋„: '.$records[$game['id']].'ํšŒ';
                            } elseif ($game['id'] === 'color_memory') {
                                echo '์ตœ๊ณ  ๋ผ์šด๋“œ: '.$records[$game['id']];
                            } elseif ($game['id'] === 'reaction_speed') {
                                echo '์ตœ๊ณ  ๊ธฐ๋ก: '.$records[$game['id']].'ms';
                            }
                            ?>
                        </div>
                    <?php else: ?>
                        <div class="game-record" style="background: rgba(156, 163, 175, 0.1); color: var(--m-text-muted);">
                            ๊ธฐ๋ก ์—†์Œ
                        </div>
                    <?php endif; ?>
                </a>
            <?php endforeach; ?>
        </div>
    </main>
    <?php require G5_THEME_PATH.'/modern/_footer.inc.php'; ?>
</div>

<?php include_once('./tail.sub.php'); ?>
```

์ด ํŒŒ์ผ์„ ์ƒ์„ฑํ•˜๊ณ  ๋ธŒ๋ผ์šฐ์ €์—์„œ `/arcade` ๊ฒฝ๋กœ๋กœ ์ ‘์†ํ•˜๋ฉด ๊ฒŒ์ž„ ๋ชฉ๋ก ํŽ˜์ด์ง€๊ฐ€ ํ‘œ์‹œ๋ฉ๋‹ˆ๋‹ค.

๊ธฐ๋Œ€ ๊ฒฐ๊ณผ: - app/modules/arcade/index.php ํŒŒ์ผ ์ƒ์„ฑ ์™„๋ฃŒ - ๋ธŒ๋ผ์šฐ์ €์—์„œ /arcade ์ ‘์† ์‹œ ๊ฒŒ์ž„ ์„ผํ„ฐ ๋ฉ”์ธ ํŽ˜์ด์ง€ ํ‘œ์‹œ - 3๊ฐœ์˜ ๊ฒŒ์ž„ ์นด๋“œ๊ฐ€ ๊ทธ๋ฆฌ๋“œ๋กœ ๋ฐฐ์น˜๋จ - ๊ฐ ์นด๋“œ์— ๊ฒŒ์ž„ ์•„์ด์ฝ˜, ์ œ๋ชฉ, ์„ค๋ช… ํ‘œ์‹œ - SQLite DB ์—ฐ๊ฒฐ ๋ฐ game_records ํ…Œ์ด๋ธ” ์ž๋™ ์ƒ์„ฑ - ์ตœ๊ณ  ๊ธฐ๋ก์ด ์žˆ์œผ๋ฉด ์นด๋“œ์— ํ‘œ์‹œ, ์—†์œผ๋ฉด '๊ธฐ๋ก ์—†์Œ' ํ‘œ์‹œ - modern shell ์ ์šฉ์œผ๋กœ ์‚ฌ์ดํŠธ nav/footer ์ผ๊ด€์„ฑ ํ™•๋ณด - ๋‹คํฌ๋ชจ๋“œ ์ „ํ™˜ ์‹œ ์ƒ‰์ƒ ์ž๋™ ๋Œ€์‘

2
Step 2
์ด์ œ ์ฒซ ๋ฒˆ์งธ ๊ฒŒ์ž„์ธ "์ˆซ์ž ๋งž์ถ”๊ธฐ"๋ฅผ ๋งŒ๋“ค๊ฒ ์Šต๋‹ˆ๋‹ค.

**1๋‹จ๊ณ„: ํด๋” ์ƒ์„ฑ**

```bash
mkdir -p app/modules/arcade/number-guess
```

**2๋‹จ๊ณ„: app/modules/arcade/number-guess/index.php ํŒŒ์ผ ์ƒ์„ฑ**

์•„๋ž˜ ๋‚ด์šฉ์œผ๋กœ ํŒŒ์ผ์„ ๋งŒ๋“ค์–ด์ฃผ์„ธ์š”:

```php
<?php
include_once('./_common.php');

// AJAX ์š”์ฒญ ์ฒ˜๋ฆฌ
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
    header('Content-Type: application/json');
    $input = json_decode(file_get_contents('php://input'), true);
    
    if (isset($input['action']) && $input['action'] === 'save_record') {
        $attempts = (int)$input['attempts'];
        
        @mkdir(G5_DATA_PATH.'/modules', 0707, true);
        $db = new PDO('sqlite:'.G5_DATA_PATH.'/modules/arcade.sqlite');
        $db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
        
        // ๊ธฐ์กด ๊ธฐ๋ก ์กฐํšŒ
        $stmt = $db->prepare("SELECT best_score FROM game_records WHERE game_id = ?");
        $stmt->execute(['number_guess']);
        $existing = $stmt->fetch(PDO::FETCH_ASSOC);
        
        $is_new_record = false;
        if (!$existing || $attempts < $existing['best_score']) {
            $stmt = $db->prepare(
                "INSERT OR REPLACE INTO game_records (game_id, best_score, updated_at) 
                 VALUES (?, ?, datetime('now'))"
            );
            $stmt->execute(['number_guess', $attempts]);
            $is_new_record = true;
        }
        
        echo json_encode(['success' => true, 'is_new_record' => $is_new_record]);
        exit;
    }
}

// ์ตœ๊ณ  ๊ธฐ๋ก ์กฐํšŒ
@mkdir(G5_DATA_PATH.'/modules', 0707, true);
$db = new PDO('sqlite:'.G5_DATA_PATH.'/modules/arcade.sqlite');
$stmt = $db->prepare("SELECT best_score FROM game_records WHERE game_id = ?");
$stmt->execute(['number_guess']);
$record = $stmt->fetch(PDO::FETCH_ASSOC);
$best_score = $record ? $record['best_score'] : null;

require_once(G5_THEME_PATH.'/modern/_head.inc.php');
include_once('./head.sub.php');
?>
<style>
.game-container {
    max-width: 600px;
    margin: 0 auto;
    text-align: center;
}
.game-header {
    margin-bottom: 32px;
}
.game-header h1 {
    font-size: 2rem;
    font-weight: 700;
    margin-bottom: 8px;
    color: var(--m-text);
}
.game-header .subtitle {
    color: var(--m-text-muted);
    font-size: 1rem;
}
.record-badge {
    display: inline-block;
    background: rgba(139, 92, 246, 0.1);
    color: #8b5cf6;
    padding: 8px 16px;
    border-radius: 12px;
    font-weight: 600;
    margin-top: 12px;
}
.game-area {
    background: var(--m-surface);
    border-radius: var(--m-radius-lg);
    padding: 48px 32px;
    box-shadow: var(--m-shadow);
}
.game-status {
    font-size: 1.25rem;
    font-weight: 600;
    margin-bottom: 24px;
    color: var(--m-text);
    min-height: 32px;
}
.hint {
    font-size: 1.5rem;
    font-weight: 700;
    margin-bottom: 24px;
    min-height: 40px;
}
.hint.up { color: #ef4444; }
.hint.down { color: #3b82f6; }
.hint.correct { color: #10b981; }
.input-group {
    display: flex;
    gap: 12px;
    justify-content: center;
    margin-bottom: 24px;
}
.input-group input {
    width: 120px;
    padding: 12px 16px;
    font-size: 1.25rem;
    text-align: center;
    border: 2px solid rgba(139, 92, 246, 0.3);
    border-radius: 8px;
    background: var(--m-surface);
    color: var(--m-text);
}
.input-group input:focus {
    outline: none;
    border-color: #8b5cf6;
}
.btn {
    padding: 12px 32px;
    font-size: 1rem;
    font-weight: 600;
    border: none;
    border-radius: 8px;
    cursor: pointer;
    transition: transform 0.2s;
}
.btn:hover { transform: scale(1.05); }
.btn-primary {
    background: #8b5cf6;
    color: white;
}
.btn-secondary {
    background: rgba(156, 163, 175, 0.2);
    color: var(--m-text);
}
.stats {
    display: flex;
    gap: 24px;
    justify-content: center;
    margin-top: 24px;
    font-size: 0.875rem;
    color: var(--m-text-muted);
}
.back-link {
    display: inline-block;
    margin-top: 24px;
    color: var(--m-text-muted);
    text-decoration: none;
}
.back-link:hover { text-decoration: underline; }
</style>

<div class="m-shell">
    <?php require G5_THEME_PATH.'/modern/_nav.inc.php'; ?>
    <main class="m-container" style="padding: 48px 20px;">
        <div class="game-container">
            <div class="game-header">
                <h1>๐Ÿ”ข ์ˆซ์ž ๋งž์ถ”๊ธฐ</h1>
                <div class="subtitle">1~100 ์‚ฌ์ด์˜ ์ˆซ์ž๋ฅผ ๋งž์ถฐ๋ณด์„ธ์š”!</div>
                <?php if ($best_score): ?>
                    <div class="record-badge">์ตœ์†Œ ์‹œ๋„ ๊ธฐ๋ก: <?php echo $best_score; ?>ํšŒ</div>
                <?php endif; ?>
            </div>
            
            <div class="game-area">
                <div class="game-status" id="status">๊ฒŒ์ž„์„ ์‹œ์ž‘ํ•˜๋ ค๋ฉด ์•„๋ž˜ ๋ฒ„ํŠผ์„ ํด๋ฆญํ•˜์„ธ์š”</div>
                <div class="hint" id="hint"></div>
                
                <div id="game-controls" style="display: none;">
                    <div class="input-group">
                        <input type="number" id="guess-input" min="1" max="100" placeholder="1-100">
                        <button class="btn btn-primary" onclick="makeGuess()">ํ™•์ธ</button>
                    </div>
                    <div class="stats">
                        <div>์‹œ๋„ ํšŸ์ˆ˜: <strong id="attempts">0</strong></div>
                        <div>๋ฒ”์œ„: <strong id="range">1 ~ 100</strong></div>
                    </div>
                </div>
                
                <button class="btn btn-primary" id="start-btn" onclick="startGame()">๊ฒŒ์ž„ ์‹œ์ž‘</button>
                <button class="btn btn-secondary" id="reset-btn" style="display: none;" onclick="resetGame()">๋‹ค์‹œ ํ•˜๊ธฐ</button>
            </div>
            
            <a href="/arcade" class="back-link">โ† ๊ฒŒ์ž„ ์„ผํ„ฐ๋กœ ๋Œ์•„๊ฐ€๊ธฐ</a>
        </div>
    </main>
    <?php require G5_THEME_PATH.'/modern/_footer.inc.php'; ?>
</div>

<script>
let targetNumber = 0;
let attempts = 0;
let minRange = 1;
let maxRange = 100;

function startGame() {
    targetNumber = Math.floor(Math.random() * 100) + 1;
    attempts = 0;
    minRange = 1;
    maxRange = 100;
    
    document.getElementById('status').textContent = '์ˆซ์ž๋ฅผ ์ž…๋ ฅํ•˜๊ณ  ํ™•์ธ ๋ฒ„ํŠผ์„ ๋ˆ„๋ฅด์„ธ์š”';
    document.getElementById('hint').textContent = '';
    document.getElementById('attempts').textContent = '0';
    document.getElementById('range').textContent = '1 ~ 100';
    document.getElementById('guess-input').value = '';
    
    document.getElementById('start-btn').style.display = 'none';
    document.getElementById('game-controls').style.display = 'block';
    document.getElementById('reset-btn').style.display = 'none';
    document.getElementById('guess-input').focus();
}

function makeGuess() {
    const input = document.getElementById('guess-input');
    const guess = parseInt(input.value);
    
    if (!guess || guess < 1 || guess > 100) {
        alert('1์—์„œ 100 ์‚ฌ์ด์˜ ์ˆซ์ž๋ฅผ ์ž…๋ ฅํ•˜์„ธ์š”!');
        return;
    }
    
    attempts++;
    document.getElementById('attempts').textContent = attempts;
    
    const hint = document.getElementById('hint');
    if (guess === targetNumber) {
        hint.textContent = '๐ŸŽ‰ ์ •๋‹ต์ž…๋‹ˆ๋‹ค!';
        hint.className = 'hint correct';
        document.getElementById('status').textContent = `${attempts}๋ฒˆ ๋งŒ์— ๋งž์ถ”์…จ์Šต๋‹ˆ๋‹ค!`;
        document.getElementById('game-controls').style.display = 'none';
        document.getElementById('reset-btn').style.display = 'inline-block';
        
        // ๊ธฐ๋ก ์ €์žฅ
        fetch('/arcade/number-guess', {
            method: 'POST',
            headers: { 'Content-Type': 'application/json' },
            body: JSON.stringify({ action: 'save_record', attempts })
        })
        .then(res => res.json())
        .then(data => {
            if (data.is_new_record) {
                setTimeout(() => {
                    alert('๐Ÿ† ์‹ ๊ธฐ๋ก ๋‹ฌ์„ฑ!');
                }, 500);
            }
        });
    } else if (guess > targetNumber) {
        hint.textContent = 'โฌ‡๏ธ DOWN';
        hint.className = 'hint down';
        maxRange = Math.min(maxRange, guess - 1);
    } else {
        hint.textContent = 'โฌ†๏ธ UP';
        hint.className = 'hint up';
        minRange = Math.max(minRange, guess + 1);
    }
    
    document.getElementById('range').textContent = `${minRange} ~ ${maxRange}`;
    input.value = '';
    input.focus();
}

function resetGame() {
    startGame();
}

// Enter ํ‚ค๋กœ ์ œ์ถœ
document.addEventListener('DOMContentLoaded', () => {
    document.getElementById('guess-input').addEventListener('keypress', (e) => {
        if (e.key === 'Enter') makeGuess();
    });
});
</script>

<?php include_once('./tail.sub.php'); ?>
```

์ด ํŒŒ์ผ์„ ์ƒ์„ฑํ•˜๊ณ  ๋ธŒ๋ผ์šฐ์ €์—์„œ `/arcade/number-guess` ๊ฒฝ๋กœ๋กœ ์ ‘์†ํ•˜๋ฉด ์ˆซ์ž ๋งž์ถ”๊ธฐ ๊ฒŒ์ž„์„ ํ”Œ๋ ˆ์ดํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๊ธฐ๋Œ€ ๊ฒฐ๊ณผ: - app/modules/arcade/number-guess/index.php ํŒŒ์ผ ์ƒ์„ฑ ์™„๋ฃŒ - /arcade/number-guess ์ ‘์† ์‹œ ๊ฒŒ์ž„ ํŽ˜์ด์ง€ ํ‘œ์‹œ - "๊ฒŒ์ž„ ์‹œ์ž‘" ๋ฒ„ํŠผ ํด๋ฆญ ์‹œ 1~100 ๋žœ๋ค ์ˆซ์ž ์ƒ์„ฑ - ์‚ฌ์šฉ์ž ์ž…๋ ฅ ํ›„ UP/DOWN ํžŒํŠธ ์ œ๊ณต - ์ •๋‹ต ์‹œ ์‹œ๋„ ํšŸ์ˆ˜ ํ‘œ์‹œ ๋ฐ DB ์ €์žฅ - ์‹ ๊ธฐ๋ก ๋‹ฌ์„ฑ ์‹œ ์•Œ๋ฆผ ํ‘œ์‹œ - "๋‹ค์‹œ ํ•˜๊ธฐ" ๋ฒ„ํŠผ์œผ๋กœ ๊ฒŒ์ž„ ๋ฆฌ์…‹ - ์ตœ๊ณ  ๊ธฐ๋ก์ด ํŽ˜์ด์ง€ ์ƒ๋‹จ์— ํ‘œ์‹œ๋จ - ๋ฒ”์œ„๊ฐ€ ์ ์  ์ขํ˜€์ง€๋ฉฐ ํ‘œ์‹œ๋จ - Enter ํ‚ค๋กœ ์ œ์ถœ ๊ฐ€๋Šฅ

3
Step 3
์ด์ œ ๋‘ ๋ฒˆ์งธ ๊ฒŒ์ž„์ธ "์ƒ‰๊น” ๊ธฐ์–ตํ•˜๊ธฐ"๋ฅผ ๋งŒ๋“ค๊ฒ ์Šต๋‹ˆ๋‹ค.

**1๋‹จ๊ณ„: ํด๋” ์ƒ์„ฑ**

```bash
mkdir -p app/modules/arcade/color-memory
```

**2๋‹จ๊ณ„: app/modules/arcade/color-memory/index.php ํŒŒ์ผ ์ƒ์„ฑ**

์•„๋ž˜ ๋‚ด์šฉ์œผ๋กœ ํŒŒ์ผ์„ ๋งŒ๋“ค์–ด์ฃผ์„ธ์š”:

```php
<?php
include_once('./_common.php');

// AJAX ์š”์ฒญ ์ฒ˜๋ฆฌ
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
    header('Content-Type: application/json');
    $input = json_decode(file_get_contents('php://input'), true);
    
    if (isset($input['action']) && $input['action'] === 'save_record') {
        $round = (int)$input['round'];
        
        @mkdir(G5_DATA_PATH.'/modules', 0707, true);
        $db = new PDO('sqlite:'.G5_DATA_PATH.'/modules/arcade.sqlite');
        $db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
        
        $stmt = $db->prepare("SELECT best_score FROM game_records WHERE game_id = ?");
        $stmt->execute(['color_memory']);
        $existing = $stmt->fetch(PDO::FETCH_ASSOC);
        
        $is_new_record = false;
        if (!$existing || $round > $existing['best_score']) {
            $stmt = $db->prepare(
                "INSERT OR REPLACE INTO game_records (game_id, best_score, updated_at) 
                 VALUES (?, ?, datetime('now'))"
            );
            $stmt->execute(['color_memory', $round]);
            $is_new_record = true;
        }
        
        echo json_encode(['success' => true, 'is_new_record' => $is_new_record]);
        exit;
    }
}

// ์ตœ๊ณ  ๊ธฐ๋ก ์กฐํšŒ
@mkdir(G5_DATA_PATH.'/modules', 0707, true);
$db = new PDO('sqlite:'.G5_DATA_PATH.'/modules/arcade.sqlite');
$stmt = $db->prepare("SELECT best_score FROM game_records WHERE game_id = ?");
$stmt->execute(['color_memory']);
$record = $stmt->fetch(PDO::FETCH_ASSOC);
$best_score = $record ? $record['best_score'] : null;

require_once(G5_THEME_PATH.'/modern/_head.inc.php');
include_once('./head.sub.php');
?>
<style>
.game-container {
    max-width: 600px;
    margin: 0 auto;
    text-align: center;
}
.game-header {
    margin-bottom: 32px;
}
.game-header h1 {
    font-size: 2rem;
    font-weight: 700;
    margin-bottom: 8px;
    color: var(--m-text);
}
.game-header .subtitle {
    color: var(--m-text-muted);
    font-size: 1rem;
}
.record-badge {
    display: inline-block;
    background: linear-gradient(135deg, #f093fb 0%, #f5576c 100%);
    color: white;
    padding: 8px 16px;
    border-radius: 12px;
    font-weight: 600;
    margin-top: 12px;
}
.game-area {
    background: var(--m-surface);
    border-radius: var(--m-radius-lg);
    padding: 48px 32px;
    box-shadow: var(--m-shadow);
}
.game-status {
    font-size: 1.25rem;
    font-weight: 600;
    margin-bottom: 24px;
    color: var(--m-text);
    min-height: 32px;
}
.color-buttons {
    display: grid;
    grid-template-columns: repeat(2, 1fr);
    gap: 16px;
    max-width: 400px;
    margin: 0 auto 32px;
}
.color-btn {
    aspect-ratio: 1;
    border: none;
    border-radius: 16px;
    cursor: pointer;
    transition: transform 0.1s, opacity 0.3s;
    font-size: 2rem;
}
.color-btn:hover:not(:disabled) {
    transform: scale(1.05);
}
.color-btn:disabled {
    cursor: not-allowed;
}
.color-btn.flash {
    opacity: 1 !important;
    transform: scale(1.1);
}
.btn {
    padding: 12px 32px;
    font-size: 1rem;
    font-weight: 600;
    border: none;
    border-radius: 8px;
    cursor: pointer;
    transition: transform 0.2s;
}
.btn:hover { transform: scale(1.05); }
.btn-primary {
    background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
    color: white;
}
.btn-secondary {
    background: rgba(156, 163, 175, 0.2);
    color: var(--m-text);
}
.stats {
    display: flex;
    gap: 24px;
    justify-content: center;
    margin-top: 24px;
    font-size: 0.875rem;
    color: var(--m-text-muted);
}
.back-link {
    display: inline-block;
    margin-top: 24px;
    color: var(--m-text-muted);
    text-decoration: none;
}
.back-link:hover { text-decoration: underline; }
</style>

<div class="m-shell">
    <?php require G5_THEME_PATH.'/modern/_nav.inc.php'; ?>
    <main class="m-container" style="padding: 48px 20px;">
        <div class="game-container">
            <div class="game-header">
                <h1>๐ŸŒˆ ์ƒ‰๊น” ๊ธฐ์–ตํ•˜๊ธฐ</h1>
                <div class="subtitle">๊นœ๋นก์ด๋Š” ์ƒ‰๊น” ์ˆœ์„œ๋ฅผ ๊ธฐ์–ตํ•˜๊ณ  ๋”ฐ๋ผํ•ด๋ณด์„ธ์š”!</div>
                <?php if ($best_score): ?>
                    <div class="record-badge">์ตœ๊ณ  ๋ผ์šด๋“œ: <?php echo $best_score; ?></div>
                <?php endif; ?>
            </div>
            
            <div class="game-area">
                <div class="game-status" id="status">๊ฒŒ์ž„์„ ์‹œ์ž‘ํ•˜๋ ค๋ฉด ์•„๋ž˜ ๋ฒ„ํŠผ์„ ํด๋ฆญํ•˜์„ธ์š”</div>
                
                <div class="color-buttons" id="color-buttons" style="opacity: 0.5;">
                    <button class="color-btn" data-color="red" style="background: #ef4444;" disabled>๐Ÿ”ด</button>
                    <button class="color-btn" data-color="blue" style="background: #3b82f6;" disabled>๐Ÿ”ต</button>
                    <button class="color-btn" data-color="yellow" style="background: #fbbf24;" disabled>๐ŸŸก</button>
                    <button class="color-btn" data-color="green" style="background: #10b981;" disabled>๐ŸŸข</button>
                </div>
                
                <div class="stats">
                    <div>๋ผ์šด๋“œ: <strong id="round">0</strong></div>
                    <div>ํŒจํ„ด ๊ธธ์ด: <strong id="pattern-length">0</strong></div>
                </div>
                
                <button class="btn btn-primary" id="start-btn" onclick="startGame()">๊ฒŒ์ž„ ์‹œ์ž‘</button>
                <button class="btn btn-secondary" id="reset-btn" style="display: none;" onclick="resetGame()">๋‹ค์‹œ ํ•˜๊ธฐ</button>
            </div>
            
            <a href="/arcade" class="back-link">โ† ๊ฒŒ์ž„ ์„ผํ„ฐ๋กœ ๋Œ์•„๊ฐ€๊ธฐ</a>
        </div>
    </main>
    <?php require G5_THEME_PATH.'/modern/_footer.inc.php'; ?>
</div>

<script>
const colors = ['red', 'blue', 'yellow', 'green'];
let pattern = [];
let userPattern = [];
let round = 0;
let isPlaying = false;

function startGame() {
    pattern = [];
    round = 0;
    document.getElementById('start-btn').style.display = 'none';
    document.getElementById('reset-btn').style.display = 'none';
    nextRound();
}

function nextRound() {
    round++;
    userPattern = [];
    
    // ๋žœ๋ค ์ƒ‰๊น” ์ถ”๊ฐ€
    const randomColor = colors[Math.floor(Math.random() * colors.length)];
    pattern.push(randomColor);
    
    document.getElementById('round').textContent = round;
    document.getElementById('pattern-length').textContent = pattern.length;
    document.getElementById('status').textContent = 'ํŒจํ„ด์„ ๊ธฐ์–ตํ•˜์„ธ์š”...';
    
    // ๋ฒ„ํŠผ ๋น„ํ™œ์„ฑํ™”
    setButtonsEnabled(false);
    
    // ํŒจํ„ด ์žฌ์ƒ
    playPattern();
}

function playPattern() {
    let index = 0;
    const interval = setInterval(() => {
        if (index >= pattern.length) {
            clearInterval(interval);
            document.getElementById('status').textContent = '์ด์ œ ๋”ฐ๋ผํ•ด๋ณด์„ธ์š”!';
            setButtonsEnabled(true);
            return;
        }
        
        flashButton(pattern[index]);
        index++;
    }, 800);
}

function flashButton(color) {
    const btn = document.querySelector(`[data-color="${color}"]`);
    btn.classList.add('flash');
    setTimeout(() => btn.classList.remove('flash'), 400);
}

function setButtonsEnabled(enabled) {
    const buttons = document.querySelectorAll('.color-btn');
    const container = document.getElementById('color-buttons');
    buttons.forEach(btn => btn.disabled = !enabled);
    container.style.opacity = enabled ? '1' : '0.5';
}

function handleColorClick(color) {
    if (!isPlaying) return;
    
    flashButton(color);
    userPattern.push(color);
    
    // ํ˜„์žฌ๊นŒ์ง€ ์ž…๋ ฅ์ด ์˜ฌ๋ฐ”๋ฅธ์ง€ ํ™•์ธ
    const currentIndex = userPattern.length - 1;
    if (userPattern[currentIndex] !== pattern[currentIndex]) {
        // ์‹คํŒจ
        gameOver();
        return;
    }
    
    // ํŒจํ„ด์„ ๋ชจ๋‘ ๋งž์ท„๋Š”์ง€ ํ™•์ธ
    if (userPattern.length === pattern.length) {
        // ์„ฑ๊ณต - ๋‹ค์Œ ๋ผ์šด๋“œ
        document.getElementById('status').textContent = 'โœ… ์ •๋‹ต! ๋‹ค์Œ ๋ผ์šด๋“œ...';
        setButtonsEnabled(false);
        setTimeout(() => nextRound(), 1500);
    }
}

function gameOver() {
    isPlaying = false;
    setButtonsEnabled(false);
    document.getElementById('status').textContent = `๊ฒŒ์ž„ ์˜ค๋ฒ„! ${round}๋ผ์šด๋“œ๊นŒ์ง€ ์„ฑ๊ณต`;
    document.getElementById('reset-btn').style.display = 'inline-block';
    
    // ๊ธฐ๋ก ์ €์žฅ
    fetch('/arcade/color-memory', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({ action: 'save_record', round })
    })
    .then(res => res.json())
    .then(data => {
        if (data.is_new_record) {
            setTimeout(() => {
                alert('๐Ÿ† ์‹ ๊ธฐ๋ก ๋‹ฌ์„ฑ!');
            }, 500);
        }
    });
}

function resetGame() {
    startGame();
}

// ๋ฒ„ํŠผ ํด๋ฆญ ์ด๋ฒคํŠธ ๋“ฑ๋ก
document.addEventListener('DOMContentLoaded', () => {
    document.querySelectorAll('.color-btn').forEach(btn => {
        btn.addEventListener('click', () => {
            if (!btn.disabled) {
                handleColorClick(btn.dataset.color);
            }
        });
    });
});

// ๊ฒŒ์ž„ ์‹œ์ž‘ ์‹œ ํ”Œ๋ž˜๊ทธ ์„ค์ •
function startGame() {
    isPlaying = true;
    pattern = [];
    round = 0;
    document.getElementById('start-btn').style.display = 'none';
    document.getElementById('reset-btn').style.display = 'none';
    nextRound();
}
</script>

<?php include_once('./tail.sub.php'); ?>
```

์ด ํŒŒ์ผ์„ ์ƒ์„ฑํ•˜๊ณ  ๋ธŒ๋ผ์šฐ์ €์—์„œ `/arcade/color-memory` ๊ฒฝ๋กœ๋กœ ์ ‘์†ํ•˜๋ฉด ์ƒ‰๊น” ๊ธฐ์–ตํ•˜๊ธฐ ๊ฒŒ์ž„์„ ํ”Œ๋ ˆ์ดํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๊ธฐ๋Œ€ ๊ฒฐ๊ณผ: - app/modules/arcade/color-memory/index.php ํŒŒ์ผ ์ƒ์„ฑ ์™„๋ฃŒ - /arcade/color-memory ์ ‘์† ์‹œ ๊ฒŒ์ž„ ํŽ˜์ด์ง€ ํ‘œ์‹œ - 4๊ฐœ์˜ ์ƒ‰๊น” ๋ฒ„ํŠผ(๋นจ๊ฐ•, ํŒŒ๋ž‘, ๋…ธ๋ž‘, ์ดˆ๋ก) ๊ทธ๋ฆฌ๋“œ ๋ฐฐ์น˜ - ๊ฒŒ์ž„ ์‹œ์ž‘ ์‹œ ๋žœ๋ค ์ƒ‰๊น” ํŒจํ„ด์ด ์ˆœ์ฐจ์ ์œผ๋กœ ๊นœ๋นก์ž„ - ์‚ฌ์šฉ์ž๊ฐ€ ๊ฐ™์€ ์ˆœ์„œ๋กœ ํด๋ฆญํ•ด์•ผ ํ•จ - ์ •๋‹ต ์‹œ ๋‹ค์Œ ๋ผ์šด๋“œ๋กœ ์ง„ํ–‰ (ํŒจํ„ด ๊ธธ์ด +1) - ์˜ค๋‹ต ์‹œ ๊ฒŒ์ž„ ์˜ค๋ฒ„ ๋ฐ ๊ธฐ๋ก ์ €์žฅ - ์‹ ๊ธฐ๋ก ๋‹ฌ์„ฑ ์‹œ ์•Œ๋ฆผ ํ‘œ์‹œ - ํ˜„์žฌ ๋ผ์šด๋“œ์™€ ํŒจํ„ด ๊ธธ์ด ์‹ค์‹œ๊ฐ„ ํ‘œ์‹œ - ์ตœ๊ณ  ๋ผ์šด๋“œ ๊ธฐ๋ก์ด ํŽ˜์ด์ง€ ์ƒ๋‹จ์— ํ‘œ์‹œ๋จ

์ œ์ถœ๋œ ์ž‘ํ’ˆ (0)

๋กœ๊ทธ์ธ ํ›„ ์ œ์ถœ

์•„์ง ์ œ์ถœ๋œ ์ž‘ํ’ˆ์ด ์—†์Šต๋‹ˆ๋‹ค. ์ฒซ ๋ฒˆ์งธ ๋„์ „์ž๊ฐ€ ๋˜์–ด๋ณด์„ธ์š”!

๋Œ“๊ธ€ (0)

๋กœ๊ทธ์ธ ํ›„ ๋Œ“๊ธ€์„ ๋‚จ๊ธธ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
์•„์ง ๋Œ“๊ธ€์ด ์—†์Šต๋‹ˆ๋‹ค. ์ฒซ ๋ฒˆ์งธ ๋Œ“๊ธ€์„ ๋‚จ๊ฒจ๋ณด์„ธ์š”!