見出し画像

ローカルLLMでコード生成能力を測る第3弾DeepSeek編

DeepSeek-R1-Distill-Qwen-14B-Japanese

次は噂の、DeepSeekに日本語教育を施したものです。
これは、コード生成用のLLMではないですが、どんな結果になるのか、楽しみです。

まずは、コード生成用のプロンプト作成

JavaScript,css,htmlを用いて、Webで動くブロック崩しゲームを作りたい。 
これをAIで作成させるためのプロンプトを組み立てて欲しい。

Deep Seekの回答は、少し考えていましたが、結果は以下の通り。

JavaScriptブロック崩しゲーム開発プロンプト:

1. 基本要件:
- HTML5 Canvasを使用せずにdivベースで実装
- 800x600ピクセルのプレイヤーエリア(余白あり)
- パドル: 水平移動可能な長方形(左右キー操作)

2. コンポーネント構造:
- プレイヤー表示用コンテナ
- ボール: 15pxサイズの円形
- ブロック: 3x3グリッド(色別配置)
- ゲームオーバー判定

3. 必須機能:
A) 動的ゲームループ:
- スムーズな60FPSアニメーション(requestAnimationFrame使用)
- ボール速度制御機構(スコアに応じて加速)

B) 物理演算:
- パドル衝突検出
- X/Y方向のボール反射計算
- 壁面バウンド

C) ゲームロジック:
1. 初期化: ブロック配置(3行×6列)
2. スコアシステム: 連続ヒット加算
3. 難易度調整: ボール速度自動増速

D) UI要素:
- スコア表示(左上)
- ライフ残り表示(右上)
- 動的難易度インジケータ

4. 技術要件:
- モバイル対応キーボード操作
- レスポンシブデザイン
- コメント付き拡張性あるコード構造
- 拡張可能なゲームステート管理

5. 必須数値パラメータ:
ボール初期速度: 6px/frame
重力値: 0.2(Y方向加速度)
パドル幅: 100px
ブロック配置間隔: 30px

うん、まずまずの出来です。
Canvasを使用しない縛りを、勝手に儲けるなんてやる気あるなー。
続いて、このプロンプトを投げた、結果できたコードは以下の通りです。
Macのリソース状況は、使用メモリ38GB程度で、GPUの使用率も80-90%程度です。
思考時間1分とのことでしたが、CPUファンが周り始め、本体が熱くなりました。

<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <title>Block Breaker</title>
    <style>
        body {
            display: flex;
            justify-content: center;
            align-items: center;
            min-height: 100vh;
            margin: 0;
            background-color: #f0f0f0;
            font-family: Arial, sans-serif;
        }

        .game-container {
            width: 800px;
            height: 600px;
            border: 2px solid #333;
            background-color: white;
            position: relative;
            box-sizing: border-box;
        }

        .score-board {
            position: absolute;
            top: -40px;
            left: 0;
            right: 0;
            display: flex;
            justify-content: space-between;
            font-size: 24px;
            padding: 0 15px;
            background-color: white;
        }

        .ball {
            width: 30px;
            height: 30px;
            background-color: #ff4444;
            border-radius: 50%;
            position: absolute;
            bottom: 50px;
            left: 385px;
        }

        .paddle {
            width: 100px;
            height: 20px;
            background-color: #66cc99;
            border-radius: 3px;
            position: absolute;
            bottom: 20px;
            left: 385px;
        }

        .block {
            width: 70px;
            height: 40px;
            position: absolute;
            border: 1px solid #66cc99;
            background-color: rgba(102, 204, 153, 0.8);
            box-sizing: border-box;
        }
    </style>
</head>
<body>
    <div class="game-container">
        <div class="score-board">
            <span id="score">Score: 0</span>
            <span id="lives">Lives: 3</span>
        </div>
        <div class="ball" data-speed-x="6" data-speed-y="-4"></div>
        <div class="paddle" data-width="100"></div>
    </div>

<script>
class BlockBreaker {
    constructor() {
        this.container = document.querySelector('.game-container');
        this.ball = document.querySelector('.ball');
        this.paddle = document.querySelector('.paddle');
        this.scoreBoard = document.querySelectorAll('.score-board span');
        this.lives = 3;
        this.score = 0;
        this.gameLoop();
    }

    gameLoop() {
        const ball = this.ball;
        let speedX = parseFloat(ball.dataset.speedX);
        let speedY = parseFloat(ball.dataset.speedY);

        // ボールの位置更新
        const { left, top } = ball.getBoundingClientRect();
        ball.style.left = `${left + speedX}px`;
        ball.style.top = `${top + speedY}px`;

        // パドルとの衝突判定
        const paddleRect = this.paddle.getBoundingClientRect();
        if (left - paddleRect.right < 0 &&
            left - paddleRect.left > -this.paddle.dataset.width) {
            speedY *= -1;
        }

        // 境界チェック
        if (top < 0 || top + ball.offsetHeight > this.container.clientHeight) {
            speedY = -speedY;
        }
        if (left < 0 || left + ball.offsetWidth > this.container.clientWidth) {
            if (lives <= 1) lives = 0; // ゲームオーバー判定
        }

        // ボール速度調整(難易度)
        speedX *= 1.02;
        speedY *= 1.02;

        ball.dataset.speedX = speedX;
        ball.dataset.speedY = speedY;

        requestAnimationFrame(this.gameLoop.bind(this));
    }
}

// ゲーム初期化
const game = new BlockBreaker();

// パドル移動イベントリスナー
document.addEventListener('mousemove', (e) => {
    const containerRect = game.container.getBoundingClientRect();
    const newLeft = e.clientX - containerRect.left;
    
    if (newLeft < 0) newLeft = 0;
    if (newLeft + 100 > containerRect.width) newLeft = containerRect.width - 100;

    game.paddle.style.left = `${newLeft}px`;
});

// ゲーム開始
document.addEventListener('click', () => {
    game.ball.style.display = 'block';
});
</script>
</body>
</html>

一つのファイルにまとまっているのは、ChatGPTと同じです。
実行結果は、以下です。

パドルは左右にマウスで素早く動きます。
動きはスムーズですが、ブロックとボールが見当たりません。
うーん、残念。
でも、賢そうなので以下の指令を追加で出しました。

このコードでは、ブロックとボールが表示されません。
修正した完全なコードを提示してください。

結果のコードが以下です。

<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <title>Block Breaker</title>
    <style>
        body {
            display: flex;
            justify-content: center;
            align-items: center;
            min-height: 100vh;
            margin: 0;
            background-color: #f0f0f0;
            font-family: Arial, sans-serif;
        }

        .game-container {
            position: relative;
            width: 800px;
            height: 600px;
            border: 2px solid #333;
            overflow: hidden;
        }

        .block {
            position: absolute;
            background-color: #4CAF50;
            border-radius: 5px;
            transform-origin: center;
        }

        .ball {
            width: 15px;
            height: 15px;
            background-color: #f44336;
            border-radius: 50%;
            position: absolute;
            transform-origin: center;
        }

        .score-board {
            text-align: center;
            color: white;
            font-size: 24px;
            margin-bottom: 20px;
        }
    </style>
</head>
<body>
    <div class="game-container">
        <div class="blocks"></div>
        <div class="ball" id="ball"></div>
    </div>

    <div class="score-board">
        <h1>ブロック崩し</h1>
        <p>Score: <span id="score">0</span></p>
        <p>Lives: <span id="lives">3</span></p>
    </div>

    <script>
        class BlockBreaker {
            constructor() {
                this.container = document.querySelector('.game-container');
                this.ball = document.getElementById('ball');
                this.blocks = document.querySelector('.blocks');
                this.scoreElement = document.getElementById('score');
                this.livesElement = document.getElementById('lives');
                this.speedX = 5;
                this.speedY = -5;

                this.initBlocks();
                this.gameStart();
            }

            initBlocks() {
                const blocksPerRow = 10;
                const blockWidth = (this.container.offsetWidth / blocksPerRow) - 4; // 余白分を考慮
                const startHeight = 80;

                for (let row = 0; row < 3; row++) {
                    for (let col = 0; col < blocksPerRow; col++) {
                        const block = document.createElement('div');
                        block.className = 'block';
                        block.style.width = `${blockWidth}px`;
                        block.style.height = '20px';
                        
                        // X座標計算
                        const x = col * (blockWidth + 4) + 2; // 余白分を考慮
                        // Y座標計算(3行目は高さ調整)
                        const y = row === 0 ? startHeight : (startHeight - 100);
                        
                        block.style.left = x + 'px';
                        block.style.top = y + 'px';
                        block.dataset.row = row;
                        block.dataset.col = col;

                        this.blocks.appendChild(block);

                        // ブロック破壊時のイベントリスナー
                        block.addEventListener('animationend', () => {
                            this.removeBlock(block);
                        });
                    }
                }
            }

            gameStart() {
                const _this = this;
                document.addEventListener('mousemove', (e) => {
                    const containerRect = _this.container.getBoundingClientRect();
                    const newX = e.clientX - containerRect.left;

                    // パドルの横位置制限
                    if (newX < 0) newX = 0;
                    if (newX > containerRect.width - 100) newX = containerRect.width - 100;

                    this.paddleLeft = newX;
                });

                requestAnimationFrame(() => {
                    _this.update();
                });
            }

            update() {
                const containerWidth = this.container.offsetWidth;
                const containerHeight = this.container.offsetHeight;

                // ボールの位置更新
                const ballRect = this.ball.getBoundingClientRect();
                const paddleRect = document.querySelector('.paddle').getBoundingClientRect();

                // パドルとの衝突判定
                if (
                    ballRect.top < paddleRect.bottom &&
                    ballRect.right > paddleRect.left &&
                    ballRect.left < paddleRect.right &&
                    ballRect.bottom > paddleRect.top
                ) {
                    this.speedY = -this.speedY;
                }

                // 境界チェックとリセット
                if (ballRect.left <= 0 || ballRect.right >= containerWidth) {
                    this.speedX = -this.speedX;
                }
                if (ballRect.top <= 0) {
                    this.speedY = -this.speedY;
                }
                if (ballRect.bottom >= containerHeight + 15) { // ゲームオーバー判定
                    this.lives--;
                    this.createNewBall();
                }

                // ブロックとの衝突判定
                const blocks = document.querySelectorAll('.block');
                for (let block of blocks) {
                    const blockRect = block.getBoundingClientRect();
                    
                    if (
                        ballRect.right > blockRect.left &&
                        ballRect.left < blockRect.right &&
                        ballRect.bottom > blockRect.top &&
                        ballRect.top < blockRect.bottom
                    ) {
                        this.speedX = (blockRect.left - ballRect.left) > 0 ? -this.speedX : this.speedX;
                        this.speedY = (blockRect.top - ballRect.bottom) > 0 ? -this.speedY : this.speedY;

                        // ブロック削除
                        block.style.animation = 'slideUp 0.3s';
                        const score = parseInt(this.scoreElement.textContent);
                        this.scoreElement.textContent = score + 10;
                        
                        setTimeout(() => {
                            this.removeBlock(block);
                        }, 300);
                    }
                }

                // ボールの移動
                this.ball.style.left = (ballRect.left + this.speedX) + 'px';
                this.ball.style.top = (ballRect.top + this.speedY) + 'px';

                requestAnimationFrame(() => {
                    this.update();
                });
            }

            createNewBall() {
                const ballRect = document.getElementById('ball').getBoundingClientRect();
                if (this.lives > 0) {
                    this.ball.style.left = (containerWidth / 2 - 7.5) + 'px';
                    this.ball.style.top = 60 + 'px'; // 再開位置
                    this.speedX = 5;
                    this.speedY = -5;
                } else if (this.lives === 0) {
                    this.ball.remove();
                    alert('ゲームオーバー! スコア: ' + this.scoreElement.textContent);
                    window.location.reload();
                }
            }

            removeBlock(block) {
                block.parentElement.removeChild(block);
            }

            // パドルの描画(簡易版)
            drawPaddle() {
                const paddle = document.createElement('div');
                paddle.className = 'paddle';
                paddle.style.width = '100px';
                paddle.style.height = '20px';
                paddle.style.backgroundColor = '#4CAF50';
                paddle.style.position = 'absolute';
                this.container.appendChild(paddle);
            }
        }

        // ゲームの初期化
        const game = new BlockBreaker();
    </script>
</body>
</html>

このコードの実行結果は以下の通りです。

あれ、残念ながら、左右に動いていたパドルが消えてしまいました。
指示通り、ブロックと、ボールは表示されましたが。。。。
コードでは、3段ブロックが描かれていますが、実際は1段のみ。
ラストチャンスで、もう一度修正を依頼しました。
思考中、MacBookがだいぶ熱くなってきました。

今度は、パドルが消えました。
そのため、左右に移動もできないです。
また、ブロックが1段しか表示されないです。
ボールが動きません。
これらの問題を修正した、完全なコードを提示してください。

出てきた、コードはpythonでした。(Python/Pyglet)
自分の得意分野で勝負するつもりかな?

import pyglet
from pyglet import clock
from pyglet.window import key, mouse

# ゲームオブジェクト管理クラス
class GameObject:
    def __init__(self):
        self.objects = {}
    
    def add(self, name, obj):
        self.objects[name] = obj
    
    def get(self, name):
        return self.objects.get(name)

class Block(GameObject):
    def __init__(self, x, y, width=50, height=20):
        super().__init__()
        self.x = x
        self.y = y
        self.width = width
        self.height = height
        self.exists = True
        
    def draw(self):
        if not self.exists:
            return
        # ブロック描画ロジック(例:四角形)
        pyglet.graphics.draw(4, pyglet.gl.GL_QUADS, [
            ('v2i', [self.x, self.y, self.x + self.width, self.y,
                     self.x + self.width, self.y + self.height, 
                     self.x, self.y + self.height])
        ])

class Paddle(GameObject):
    def __init__(self, window_width, speed=5):
        super().__init__()
        self.width = 80
        self.height = 10
        self.left_edge = (window_width - self.width) // 2
        self.y = 400  # 下部に移動
        self.speed = speed
        
    def move(self, dx):
        if -self.width/2 <= dx <= (pyglet.Window().width - self.width)/2:
            self.left_edge += dx * self.speed
    
    def draw(self):
        pyglet.graphics.draw(4, pyglet.gl.GL_QUADS, [
            ('v2i', [self.left_edge, self.y,
                     self.left_edge + self.width, self.y,
                     self.left_edge + self.width, self.y - self.height,
                     self.left_edge, self.y - self.height])
        ])

class Ball(GameObject):
    def __init__(self, paddle_height=10):
        super().__init__()
        self.radius = 15
        self.x = pyglet.Window().width // 2
        self.y = paddle_height + 30
        self.dx = 0
        self.dy = -4  # 上向き
        
    def update(self, dt):
        if not hasattr(self, 'ball'): return  # 初期化チェック
        self.x += self.dx * dt
        self.y += self.dy * dt
        
        # ブロックとの衝突判定
        for block in game_objects.get('blocks').objects.values():
            if (self.x - block.x)**2 + (self.y - block.y)**2 < (block.width**2 + block.height**2):
                if block.exists:
                    self.bounce(block)
                    block.exists = False
        
        # パドルとの衝突判定
        paddle = game_objects.get('paddle').get('paddle')
        if (abs(self.x - (paddle.left_edge)) < paddle.width/2 and 
            abs(self.y - paddle.y) < 15):  # 範囲調整が必要な場合あり
            self.bounce(paddle)
        
        # 境界チェック
        if self.x <= 0 or self.x >= pyglet.Window().width:
            self.dx *= -1
        if self.y <= 0:
            game_over()
    
    def bounce(self, obj):
        dx = obj.left_edge + (obj.width/2) - self.x
        dy = obj.y - self.y
        
        if dx > 0 and abs(dx) < obj.width/2:
            self.dx = abs(dx) / dx * 3.5  # 球の反射速度計算
        else:
            self.dy *= -1
            
    def reset(self):
        self.x = pyglet.Window().width//2
        self.y = 400 + 200  # 初期位置調整が必要?
        self.dx, self.dy = 0, -4

# ゲーム管理クラス
class GameManager:
    def __init__(self):
        self.window = pyglet.Window()
        self.ball = Ball()
        game_objects.add('ball', self.ball)
        
        # ブロック生成(5列×8行)
        blocks = [Block(x, y) for x in range(0, 800, 60) 
                 for y in range(100, 420+1, 50)]
        game_objects.add('blocks', {'block'+str(i): block 
                                  for i, block in enumerate(blocks)})
        
        self.paddle = Paddle(self.window.width)
        game_objects.add('paddle', 'paddle')
        
    def reset_game(self):
        self.ball.reset()
        # ブロックを再生成(必要に応じて)
    
    def handle_input(self, dt):
        paddle = game_objects.get('paddle').get('paddle')
        if key.LEFT in pyglet.window.key.symbol_string():
            paddle.move(-1)
        if key.RIGHT in pyglet.window.key.symbol_string():
            paddle.move(1)

# ゲームループと描画
game_objects = GameObject()
game_manager = GameManager()

def update(dt):
    game_manager.handle_input(dt)
    game_manager.ball.update(dt)
    
    # 3秒間でゲームオーバー判定
    if pyglet.clock.get_fps() > 0:
        if pyglet.clock.get_fps() < 25 and not hasattr(game_manager, 'game_over'):
            game_over()

def draw():
    pyglet.gl.clear(1.0, 1.0, 1.0, 1.0)
    
    # ブロック描画
    for block in game_objects.get('blocks').objects.values():
        if block.exists:
            block.draw()
    
    # パドルとボール描画
    game_manager.paddle.draw()
    game_manager.ball.draw()

def game_over():
    pyglet.text.Label('Game Over!', font_name='Times New Roman',
                      font_size=48, x=pyglet.Window().width//2,
                      y=pyglet.Window().height//2,
                      anchor_x='center', anchor_y='center').draw()
    pyglet.clock.schedule_once(pyglet.exit, 1)

if __name__ == '__main__':
    pyglet.app.run()

このコードを評価してください。特に、ゲームオーバー時の処理やボールの衝突判定が適切かどうか。
まず、ゲームオーバー時に3秒間でFPSが25未満になる場合に発生しますが、実際にはFPSは毎フレーム変動するため、正確な判断が難しいかもしれません。また、パドルとの衝突判定ロジックが正しくない可能性があります(例えば、ボールとパドルの位置関係を正確に検出できていない)。
さらに、ボールの再初期化処理やブロックの再生も問題があるかもしれません。

他にも、以下の点について確認が必要です:
1. パドルとの衝突判定が正しくない
2. 球の弾道計算が物理的に正確でない
3. ゲームオーバー時の挙動(FPS基準)が不適切
4. ブロックを再生成していない(ゲームオーバー後にリスタートできない)
5. ボールの初期位置設定に問題あり

改善点と修正案を提示してください。
まず、ゲームオーバー判定方法について。現在はFPSで判断していますが、ボールが一定回数反射できなくなり次第で終了させるべきかもしれません。例えば、ブロックを全て破壊した場合やパドルに接触できない状態になった時などです。

また、衝突判定に関しては、球とオブジェクトの位置関係をより正確に検出する必要があります。現在の条件では、距離に基づいて判断していますが、これが正しくボールの移動方向を反映しているか確認が必要です。

パドルとの衝突判定ロジックも改善すべきです。例えば、パドルの範囲内でボールが入っているかチェックする方法がありますが、現在の計算は正確でないかもしれません。球とパドルの座標比較を再検討する必要があります。

さらに、ゲームオーバー後のリセット処理がないため、プレイヤーが再度ゲーム開始できない問題もあります。reset_gameメソッドで適切に初期化しないとリスタートできません。

これらの課題を解決するために、以下のような修正案を考えられます:
- ゲームオーバー判定をボールの移動範囲をパドルから外れた状態で行う。
- パドルとの衝突判定をより正確に行うため、球がパドルの直上にある場合に反転させるロジックを追加する。
- ボールとブロックの衝突計算方法を改善し、物理的な反射角度を適切に計算する。
- ゲームオーバー後もゲームループを継続させ、リスタート処理を追加する。

また、コード内の変数やイベントハンドリングの部分にも注意が必要です。例えば、key.LEFTとRIGHTの入力チェック方法は正しいでしょうか? 他のイベントシステム(例:モードファクトリー)を使用している場合は問題が生じる可能性があります。
</think>

このコードを詳細に評価し、改善点と修正案を提示します。

### 主要な課題とその根拠
1. **ゲームオーバー判定の不正確性**
   -FPS基準で終了(ゲームロジックでは意味不明)
   -実際にはボールがパドルから外れた状態で終了すべき

2. **衝突判定メカニズムの問題点**
   -球とブロック/パドルの位置関係判定に誤り
   -物理的な反射角度計算が不正確

3. **ゲームリスタート機能の欠如**
   -敗北後は終了するのみで再試行不可能

4. **ボールの初期位置設定不足**
   -再初期化時に正しい位置に戻らない

5. **パドル操作制限**
   -移動量計算に誤りがあり左右移動が正しく動作しない

### 改善案と修正コード
#### 1. ゲームオーバー判定の改善
```python
def game_over():
    pyglet.text.Label('Game Over!', font_name='Times New Roman',
                      font_size=48, x=pyglet.Window().width//2,
                      y=pyglet.Window().height//2,
                      anchor_x='center', anchor_y='center').draw()
    
    # ボールがパドルの上にない場合終了
    if game_manager.ball.y > pyglet.Window().height - 100:
        pyglet.clock.schedule_once(pyglet.exit, 1)

さらに、改善案も2つ出ました。
球の衝突判定改善(ブロックと球)

def calculate_reflection(body1, body2):
    # 正規化された法線ベクトル
    dx = body2.rect.x - body1.rect.x
    dy = body2.rect.y - body1.rect.y
    len_norm = math.sqrt(dx**2 + dy**2)
    
    dot_product = (body1.velocity.x * dx + 
                   body1.velocity.y * dy) / len_norm
    
    # 物理的な反射角度計算
    reflected_velocity_x = (body1.velocity.x - 2 * dot_product * dx)
    reflected_velocity_y = (body1.velocity.y - 2 * dot_product * dy)
    
    return ReflectedVector(reflected_velocity_x, reflected_velocity_y)

パドルとの衝突判定改善

class Paddle:
    def check_ball_collision(self, ball):
        if (self.rect.right - self.rect.left > ball.rect.left and
            self.rect.right > ball.rect.left and
            ball.rect.bottom > self.rect.top and
            ball.rect.top < self.rect.bottom):

            # 球のY座標がパドル中央に近いほど角度が変わる
            angle = (ball.rect.centerx - self.rect.centerx) / self.rect.width
            dy = math.tan(angle * math.pi/2)
            
            return ReflectedVector(
                ball.velocity.x,
                ball.velocity.y + dy*0.5  # 水平速度の影響を考慮
            )
        return None

class Ball:
    def update(self):
        if not self.is_moving:
            return
            
        self.rect.center += self.velocity
        # パドルとの衝突判定
        collision_result = paddle.check_ball_collision(self)
        
        if collision_result:
            self.velocity = collision_result
            self.is_moving = True

ゲームリスタート機能追加

class GameLoop(pyglet.window.Window):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.game_over = False
        self.reset()
    
    def reset(self):
        # ボールとブロックを再初期化
        ball.rect.center = (window.width//2, window.height-50)
        velocity = (random.uniform(300, 400), -150)
        
        for block in blocks:
            block.active = True
        
    def on_key_press(self, symbol, modifiers):
        if symbol == key.ESCAPE and self.game_over:
            self.reset()

ボールの初期位置設定改善

class Ball:
    def __init__(self):
        self.rect = pyglet.shapes.Circle(window.width//2, 
                                        window.height-50,
                                        radius=15)
        self.velocity = ReflectedVector(300, -150)
        self.is_moving = True
        
    def reset(self):
        self.rect.centerx = window.width//2
        self.rect.centery = window.height-50
        self.velocity.x = 300 if random.choice([True, False]) else -300
        self.velocity.y = -150

pygletgがないので、インストールして実行します。

% pip install pyglet
% python pyblock.py 
Traceback (most recent call last):
  File "pyblock.py", line 132, in <module>
    game_manager = GameManager()
  File "pyblock.py", line 106, in __init__
    self.window = pyglet.Window()
AttributeError: module 'pyglet' has no attribute 'Window'

うん、ハマっているね。

ちなみに、qwen2.5-coderで作成されたブロック崩しゲームのコード生成プロンプトを使用してみると、

あなたは、JavaScript, CSS, HTMLを使ってWeb上で動くブロック崩し(Breakout)
ゲームを作成する必要があります。以下の要件に基づいてコードを生成してください。

要件:
1. ゲーム画面のサイズは600x400ピクセルで、背景色は黒に設定してください。
2. パドル(プレイヤーのコントロール物)のサイズは100x10ピクセル、
初期位置は画面下部中央に配置します。パドルは左右に移動できます。
3. ボールのサイズは10x10ピクセルで、ゲーム開始時に上部中央からランダムな角度で落下します。
4. ブロックを複数行作成し、各ブロックは50x20ピクセルのサイズで、画面の上部に配置します。
ブロックは色付きで異なるデザインにすることも可能です。
5. ボールがブロックに当たるとブロックが消え、ゲーム終了時には全てのブロックが壊れるまで
プレイできます。
6. ゲームのスコア板を表示し、各ブロックを壊すごとに得られる点数を設定してください。

デザイン:
1. パドルとボールはシンプルな形状で描画します。
2. 各ブロックは異なる色で配置し、画面を上から下に向かって段々色が濃くなるようにする。
3. 背景に静的な星空パターンやグラデーションを追加してゲームの雰囲気を作ります。

JavaScriptの要件:
1. ボールの移動とパドルの制御は、キーボードイベント(左右の矢印キー)を使用して実装してください。
2. ボールがブロックに当たった場合、ボールの反射角を考慮に入れて速度と方向を変更するロジックを
実装してください。
3. スコアを更新し、ゲーム終了条件(全てのブロックが壊れた場合)を判定するコードを
追加してください。

CSSの要件:
1. パドル、ボール、ブロックのスタイルを定義してください。
2. 背景と要素間のマージンやパディングを適切に調整してください。

HTMLの要件:
1. ゲーム画面、スコア板を含む基本的なHTML構造を作成してください。
2. JavaScriptとCSSのリンクを正しく設定してください。

AIは以下の出力を生成する必要があります:
- 完全なHTMLファイル
- 完全なCSSファイル
- 完全なJavaScriptファイル

これらのファイルを1つのレスポンスにまとめて提供してください。
それぞれのファイルには適切なコメントが含まれていると良いでしょう。


あ、間違えてphi4で作成してしまったのが以下で、かろうじて、パドルは動くが、同時に横スクーロールが入る。
あと、ボールが出ない。
ま、phi4は会話用だかtらいいか。

仕切り直して、もう一度、DeepSeekで同様のコード生成プロンプトでコードを作成。
生成されたコードは以下の通りです。

<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <title>ブロック崩しゲーム</title>
    <link rel="stylesheet" href="style.css">
</head>
<body>
    <div class="game-container">
        <canvas id="gameCanvas" width="600" height="400"></canvas>
        <div class="score-board">Score: <span id="score">0</span></div>
    </div>
    <script src="script.js"></script>
</body>
</html>

<style>
/* CSSファイル */
.game-container {
    background-color: #1a2b3c;
    padding: 20px;
    border-radius: 10px;
}

canvas {
    background-image: linear-gradient(to bottom, 
        rgba(255,255,255,0.1), 
        rgba(255,255,255,0.3));
    border: 2px solid #fff;
    position: relative;
}

.paddle {
    width: 100px;
    height: 10px;
    background-color: #00ff88;
    box-shadow: 0 2px 5px rgba(0,255,136,0.3);
}

.ball {
    width: 10px;
    height: 10px;
    background-color: #ff4444;
    border-radius: 50%;
    box-shadow: 0 3px 6px rgba(255,68,68,0.5);
}

.block {
    width: 50px;
    height: 20px;
    border-radius: 3px;
}

.block:nth-child(1n) { background-color: #ff5722; }
.block:nth-child(2n) { background-color: #ff9800; }
.block:nth-child(3n) { background-color: #ffebee; }
.block:nth-child(4n) { background-color: #ffac33; }

.score-board {
    color: white;
    font-family: Arial, sans-serif;
    font-size: 20px;
    margin-top: 15px;
}
</style>

<script>
// JavaScriptファイル
const canvas = document.getElementById('gameCanvas');
const ctx = canvas.getContext('2d');
const paddle = { x: 250, y: 380, width: 100, height: 10 };
let ball = { x: 300, y: 40, speedX: 5, speedY: -7 };
let score = 0;
const blocks = [];
let gameWon = false;

// 初期ブロック生成
function createBlocks() {
    for (let i = 0; i < 8; i++) {
        const blockRow = [];
        for (let j = 0; j < 12; j++) {
            const blockX = j * 50 + 30;
            const blockY = i * 20 + 40;
            blocks.push({
                x: blockX,
                y: blockY,
                width: 50,
                height: 20,
                color: getBlockColor(i),
                isBroken: false
            });
        }
    }
}

function getBlockColor(row) {
    const colors = [
        '#ff5722', // 桃色
        '#ff9800', // オレンジ
        '#ffebee', // ピンク
        '#ffac33', // 黄緑
        '#c1e1ff', // 青
        '#a6d7f5'  // 紺色
    ];
    return colors[row % colors.length];
}

// ゲームループ
function gameLoop() {
    ctx.clearRect(0, 0, canvas.width, canvas.height);

    // パドル描画
    ctx.fillStyle = 'rgb(0,255,136)';
    ctx.fillRect(paddle.x, paddle.y, paddle.width, paddle.height);

    // ボール描画
    ctx.fillStyle = '#ff4444';
    ctx.beginPath();
    ctx.arc(ball.x, ball.y, 5, 0, Math.PI * 2);
    ctx.fill();

    // ブロック描画
    blocks.forEach(block => {
        if (!block.isBroken) {
            ctx.fillStyle = block.color;
            ctx.fillRect(block.x, block.y, block.width, block.height);
        }
    });

    // ボール衝突処理
    let isBounce = checkPaddleCollision() || checkBlocksCollision();
    
    if (isBounce) ball.speedY *= -1;
    else ball.speedX *= -1;

    // 移動計算
    paddle.x += ball.speedX;
    ball.x += ball.speedX;
    ball.y += ball.speedY;

    // パドル範囲制限
    if (paddle.x < 0) paddle.x = 0;
    else if (paddle.x > canvas.width - paddle.width) paddle.x = canvas.width - paddle.width;

    // 終了判定
    if (ball.y > canvas.height && !gameWon) {
        alert('Game Over! Score: ' + score);
        resetGame();
    }

    requestAnimationFrame(gameLoop);
}

function checkPaddleCollision() {
    return ball.x >= paddle.x &&
           ball.x <= paddle.x + paddle.width &&
           ball.y >= paddle.y - 10 && // 衝突範囲拡大
           ball.y <= paddle.y;
}

function checkBlocksCollision() {
    const newX = ball.x - ball.speedX;
    for (const block of blocks) {
        if (!block.isBroken && 
            ball.x > block.x &&
            ball.x < block.x + block.width &&
            ball.y > block.y &&
            ball.y < block.y + block.height) {
                block.isBroken = true;
                score += 10;
                ctx.fillStyle = 'rgba(255,68,68,0.3)';
                ctx.fillRect(block.x, block.y, block.width, block.height);
                
                if (score >= 400) gameWon = true;

                // ボール角度調整
                const angle = Math.random() * Math.PI/2 - Math.PI/4;
                ball.speedX *= Math.cos(angle);
                ball.speedY *= Math.sin(angle);

                return true;
            }
    }
    return false;
}

function resetGame() {
    gameWon = false;
    blocks.length = 0;
    createBlocks();
    paddle.x = 250;
    ball.x = 300;
    ball.y = 40;
    score = 0;
    document.getElementById('score').textContent = score;
}

document.addEventListener('keydown', (e) => {
    if (gameWon || e.key === 'ArrowRight') {
        paddle.x += 7;
    } else if (e.key === 'ArrowLeft') {
        paddle.x -= 7;
    }
});

createBlocks();
requestAnimationFrame(gameLoop);
</script>

実行して出てきた画面は以下です。

ブロックの描写は間隔がなくて、変ですね。
かろうじて、パドルは左右に動くけど、肝心のボールが出てこない。
残念でした。
Deep Seekは、不合格です。
とはいえ、14BクラスのローカルLLMなので、クラウドにあるものなら、問題なく、コード生成できると思う。

また、Deep Seekで思考中は熱くなるし、電力消費も、増大する。

結論としては、JavaScriptで簡単なゲームを作成するなら、14BクラスのローカルLLMでは、一発合格の、
qwen2.5-coder:14b
が、ずば抜けて、性能良かっです。



いいなと思ったら応援しよう!