比較検索なら 天秤AI byGMO
AIのプログラミング能力を上げるプロンプト(プロンプト公開)

AIのプログラミング能力を上げるプロンプト(プロンプト公開)

AIのプログラミング能力を上げるプロンプトです。Gemini 2.0 flash liteでプロンプトなしではできない恐竜が走るあれを作れるようになるくらい上がります

推奨モデル - Claude
0
0
18
1

投稿日時:

  • プロンプト実行例
  • プロンプトを見る
AIのプログラミング能力を上げるプロンプト(プロンプト公開)

プログラミングするやつです

恐竜が走ってサボテンを乗り越えるあのゲームをpythonで作って

AIのプログラミング能力を上げるプロンプト(プロンプト公開)

Chrome恐竜ゲーム(T-Rex Runner)をPythonで作る要求です。このゲームはGoogleのChromeブラウザでオフライン時に表示されるゲームで、恐竜が走ってサボテンなどの障害物をジャンプして避けるシンプルなゲームです。

Pythonでこのゲームを作るためには、一般的にはPygameというライブラリを使用します。Pygameはゲーム開発用のライブラリで、グラフィックス、サウンド、ユーザー入力などを扱うための機能を提供しています。

この問題に対する思考プロセスを10段階で進めていきましょう。


Chrome恐竜ゲーム(T-Rex Runner)のPython実装

思考プロセス 1/10: 問題の理解と最初のシンプルな実装

Chromeブラウザのオフライン時に表示される「恐竜が走ってサボテンを乗り越える」ゲームを作成する要件です。基本的な要素は:

  • 恐竜のキャラクター(ジャンプできる)
  • サボテンなどの障害物
  • スコアシステム
  • ゲームオーバー機能

最もシンプルな実装としてPygameを使用します:

Python
1import pygame
2import random
3import sys
4
5# 初期化
6pygame.init()
7WIDTH, HEIGHT = 800, 300
8screen = pygame.display.set_mode((WIDTH, HEIGHT))
9pygame.display.set_caption("恐竜ゲーム")
10clock = pygame.time.Clock()
11
12# 色の定義
13WHITE = (255, 255, 255)
14BLACK = (0, 0, 0)
15
16# 恐竜の設定
17dino_width, dino_height = 50, 50
18dino_x = 50
19dino_y = HEIGHT - dino_height - 10
20dino_vel_y = 0
21is_jumping = False
22
23# サボテンの設定
24cactus_width, cactus_height = 30, 50
25cactus_x = WIDTH
26cactus_y = HEIGHT - cactus_height - 10
27cactus_speed = 5
28
29# スコア
30score = 0
31font = pygame.font.SysFont(None, 36)
32
33# メインループ
34running = True
35while running:
36    for event in pygame.event.get():
37        if event.type == pygame.QUIT:
38            running = False
39        if event.type == pygame.KEYDOWN:
40            if event.key == pygame.K_SPACE and not is_jumping:
41                is_jumping = True
42                dino_vel_y = -15
43    
44    # 恐竜の動き
45    if is_jumping:
46        dino_y += dino_vel_y
47        dino_vel_y += 1
48        if dino_y >= HEIGHT - dino_height - 10:
49            dino_y = HEIGHT - dino_height - 10
50            is_jumping = False
51            dino_vel_y = 0
52    
53    # サボテンの動き
54    cactus_x -= cactus_speed
55    if cactus_x < 0:
56        cactus_x = WIDTH
57        score += 1
58        
59    # 衝突判定
60    dino_rect = pygame.Rect(dino_x, dino_y, dino_width, dino_height)
61    cactus_rect = pygame.Rect(cactus_x, cactus_y, cactus_width, cactus_height)
62    
63    if dino_rect.colliderect(cactus_rect):
64        running = False
65    
66    # 描画
67    screen.fill(WHITE)
68    pygame.draw.rect(screen, BLACK, (dino_x, dino_y, dino_width, dino_height))
69    pygame.draw.rect(screen, BLACK, (cactus_x, cactus_y, cactus_width, cactus_height))
70    
71    # スコア表示
72    score_text = font.render(f"Score: {score}", True, BLACK)
73    screen.blit(score_text, (10, 10))
74    
75    pygame.display.update()
76    clock.tick(60)
77
78# 終了
79pygame.quit()
80sys.exit()

思考プロセス 2/10: コードの可読性と明確性の向上

コードの可読性を向上させるため、変数名を明確にし、関数を分割し、コメントを追加します:

Python
1import pygame
2import random
3import sys
4
5# 初期化
6pygame.init()
7WIDTH, HEIGHT = 800, 300
8screen = pygame.display.set_mode((WIDTH, HEIGHT))
9pygame.display.set_caption("恐竜ゲーム")
10clock = pygame.time.Clock()
11
12# 色の定義
13WHITE = (255, 255, 255)
14BLACK = (0, 0, 0)
15
16# 恐竜の設定
17class Dinosaur:
18    def __init__(self):
19        self.width = 50
20        self.height = 50
21        self.x = 50
22        self.y = HEIGHT - self.height - 10  # 地面から少し上に配置
23        self.velocity_y = 0
24        self.is_jumping = False
25        
26    def jump(self):
27        if not self.is_jumping:
28            self.is_jumping = True
29            self.velocity_y = -15  # ジャンプ力
30    
31    def update(self):
32        # ジャンプ中の物理演算
33        if self.is_jumping:
34            self.y += self.velocity_y
35            self.velocity_y += 0.8  # 重力
36            
37            # 地面に着地したらジャンプ状態を解除
38            if self.y >= HEIGHT - self.height - 10:
39                self.y = HEIGHT - self.height - 10
40                self.is_jumping = False
41                self.velocity_y = 0
42    
43    def draw(self):
44        pygame.draw.rect(screen, BLACK, (self.x, self.y, self.width, self.height))
45        
46    def get_rect(self):
47        return pygame.Rect(self.x, self.y, self.width, self.height)
48
49# サボテンの設定
50class Cactus:
51    def __init__(self):
52        self.width = 30
53        self.height = 50
54        self.x = WIDTH
55        self.y = HEIGHT - self.height - 10  # 地面から少し上に配置
56        self.speed = 5
57        
58    def update(self):
59        self.x -= self.speed
60        
61    def is_off_screen(self):
62        return self.x < -self.width
63        
64    def draw(self):
65        pygame.draw.rect(screen, BLACK, (self.x, self.y, self.width, self.height))
66        
67    def get_rect(self):
68        return pygame.Rect(self.x, self.y, self.width, self.height)
69
70# ゲームクラス
71class Game:
72    def __init__(self):
73        self.dinosaur = Dinosaur()
74        self.cacti = [Cactus()]
75        self.score = 0
76        self.font = pygame.font.SysFont(None, 36)
77        self.running = True
78        
79    def handle_events(self):
80        for event in pygame.event.get():
81            if event.type == pygame.QUIT:
82                self.running = False
83            if event.type == pygame.KEYDOWN:
84                if event.key == pygame.K_SPACE:
85                    self.dinosaur.jump()
86    
87    def update(self):
88        self.dinosaur.update()
89        
90        # サボテンの更新
91        for cactus in self.cacti[:]:
92            cactus.update()
93            
94            # 画面外に出たサボテンを削除してスコア加算
95            if cactus.is_off_screen():
96                self.cacti.remove(cactus)
97                self.score += 1
98                
99        # 一定の確率で新しいサボテンを生成
100        if random.randint(0, 100) < 2 and len(self.cacti) < 3:
101            # 最後のサボテンから十分な距離があれば生成
102            if not self.cacti or WIDTH - self.cacti[-1].x >= 300:
103                self.cacti.append(Cactus())
104                
105        # 衝突判定
106        for cactus in self.cacti:
107            if self.dinosaur.get_rect().colliderect(cactus.get_rect()):
108                self.running = False
109    
110    def draw(self):
111        screen.fill(WHITE)
112        
113        # 地面の描画
114        pygame.draw.line(screen, BLACK, (0, HEIGHT - 10), (WIDTH, HEIGHT - 10), 2)
115        
116        # 恐竜とサボテンの描画
117        self.dinosaur.draw()
118        for cactus in self.cacti:
119            cactus.draw()
120        
121        # スコア表示
122        score_text = self.font.render(f"Score: {self.score}", True, BLACK)
123        screen.blit(score_text, (10, 10))
124        
125        pygame.display.update()
126
127# メインゲーム実行
128def main():
129    game = Game()
130    
131    # メインループ
132    while game.running:
133        game.handle_events()
134        game.update()
135        game.draw()
136        clock.tick(60)  # 60FPS
137    
138    # 終了処理
139    pygame.quit()
140    sys.exit()
141
142if __name__ == "__main__":
143    main()

思考プロセス 3/10: 計算量 (時間・空間) の分析

このゲームの計算量を分析します:

時間計算量:

  • メインループ: O(n) - nはゲームの実行フレーム数
  • 衝突判定: O(m) - mは画面上のサボテンの数(通常は少数)
  • 描画処理: O(m) - オブジェクトの数に比例

空間計算量:

  • O(m) - mは画面上のオブジェクト数

ボトルネックの可能性:

  1. 多数のサボテンが存在する場合、衝突判定が遅くなる可能性がありますが、通常は画面上のサボテンは少数なので問題ありません
  2. 画像を使用する場合、メモリ消費が増加する可能性があります(現在の実装では単純な図形を使用)

このシンプルなゲームでは、計算量は非常に小さく、パフォーマンスの問題は発生しにくいです。

思考プロセス 4/10: 効率改善の検討 (アルゴリズム/データ構造)

現在の実装は既に効率的ですが、以下の改善点を検討できます:

  1. 空間分割法の適用:

    • 画面を区分けして、同じ区域にある物体間でのみ衝突判定を行う
    • 計算量: O(m+k) (kは同じ区域内の物体ペア数)
    • ただし、このゲームでは物体数が少ないため、効果は限定的
  2. オブジェクトプーリング:

    • サボテンなどのオブジェクトを都度生成・削除せず、再利用する
    • メモリ割り当て/解放のオーバーヘッドを減らす
    • 特にゲームが長時間実行される場合に有効
  3. ゲームの状態管理の最適化:

    • ゲームの異なる状態(開始画面、ゲーム中、ゲームオーバーなど)を状態パターンで管理
    • 各状態で必要な処理のみを実行できる
  4. フレームスキップの実装:

    • 処理が遅延している場合、描画フレームをスキップして更新処理を優先
    • 一定のFPSを維持しやすくなる

このゲームの場合は基本的にシンプルで、大幅なパフォーマンス改善は必要ないですが、オブジェクトプーリングを実装すると長時間プレイ時のメモリ効率が向上します。

思考プロセス 5/10: 効率改善版の実装

オブジェクトプーリングを実装して、メモリ効率を向上させた版を作成します:

Python
1import pygame
2import random
3import sys
4
5# 初期化
6pygame.init()
7WIDTH, HEIGHT = 800, 300
8screen = pygame.display.set_mode((WIDTH, HEIGHT))
9pygame.display.set_caption("恐竜ゲーム")
10clock = pygame.time.Clock()
11
12# 色の定義
13WHITE = (255, 255, 255)
14BLACK = (0, 0, 0)
15
16class Dinosaur:
17    def __init__(self):
18        self.width = 50
19        self.height = 50
20        self.x = 50
21        self.y = HEIGHT - self.height - 10
22        self.velocity_y = 0
23        self.is_jumping = False
24        
25    def jump(self):
26        if not self.is_jumping:
27            self.is_jumping = True
28            self.velocity_y = -15
29    
30    def update(self):
31        if self.is_jumping:
32            self.y += self.velocity_y
33            self.velocity_y += 0.8
34            if self.y >= HEIGHT - self.height - 10:
35                self.y = HEIGHT - self.height - 10
36                self.is_jumping = False
37                self.velocity_y = 0
38    
39    def draw(self):
40        pygame.draw.rect(screen, BLACK, (self.x, self.y, self.width, self.height))
41        
42    def get_rect(self):
43        return pygame.Rect(self.x, self.y, self.width, self.height)
44
45# サボテンプールクラス - オブジェクトプーリング実装
46class CactusPool:
47    def __init__(self, pool_size=10):
48        self.pool = []
49        self.pool_size = pool_size
50        self.initialize_pool()
51        self.active_cacti = []
52        
53    def initialize_pool(self):
54        for _ in range(self.pool_size):
55            cactus = Cactus()
56            cactus.active = False
57            self.pool.append(cactus)
58    
59    def get_cactus(self):
60        # 非アクティブなサボテンを探す
61        for cactus in self.pool:
62            if not cactus.active:
63                cactus.reset()
64                cactus.active = True
65                self.active_cacti.append(cactus)
66                return cactus
67        
68        # プールがいっぱいなら、最初の要素を再利用

思考を再開

AIのプログラミング能力を上げるプロンプト(プロンプト公開)

申し訳ありません。途中で切れてしまったようです。Chrome恐竜ゲームの実装の続きを思考プロセス5/10から継続します。


思考プロセス 5/10: 効率改善版の実装(続き)

オブジェクトプーリングを実装して、メモリ効率を向上させた版を作成します:

Python
1import pygame
2import random
3import sys
4
5# 初期化
6pygame.init()
7WIDTH, HEIGHT = 800, 300
8screen = pygame.display.set_mode((WIDTH, HEIGHT))
9pygame.display.set_caption("恐竜ゲーム")
10clock = pygame.time.Clock()
11
12# 色の定義
13WHITE = (255, 255, 255)
14BLACK = (0, 0, 0)
15
16class Dinosaur:
17    def __init__(self):
18        self.width = 50
19        self.height = 50
20        self.x = 50
21        self.y = HEIGHT - self.height - 10
22        self.velocity_y = 0
23        self.is_jumping = False
24        
25    def jump(self):
26        if not self.is_jumping:
27            self.is_jumping = True
28            self.velocity_y = -15
29    
30    def update(self):
31        if self.is_jumping:
32            self.y += self.velocity_y
33            self.velocity_y += 0.8
34            if self.y >= HEIGHT - self.height - 10:
35                self.y = HEIGHT - self.height - 10
36                self.is_jumping = False
37                self.velocity_y = 0
38    
39    def draw(self):
40        pygame.draw.rect(screen, BLACK, (self.x, self.y, self.width, self.height))
41        
42    def get_rect(self):
43        return pygame.Rect(self.x, self.y, self.width, self.height)
44
45class Cactus:
46    def __init__(self):
47        self.width = 30
48        self.height = 50
49        self.x = WIDTH
50        self.y = HEIGHT - self.height - 10
51        self.speed = 5
52        self.active = False
53        
54    def reset(self):
55        self.x = WIDTH
56        self.active = True
57        
58    def update(self):
59        self.x -= self.speed
60        if self.x < -self.width:
61            self.active = False
62            return True  # オブジェクトが画面外
63        return False
64        
65    def draw(self):
66        pygame.draw.rect(screen, BLACK, (self.x, self.y, self.width, self.height))
67        
68    def get_rect(self):
69        return pygame.Rect(self.x, self.y, self.width, self.height)
70
71# サボテンプールクラス - オブジェクトプーリング実装
72class CactusPool:
73    def __init__(self, pool_size=10):
74        self.pool = []
75        self.pool_size = pool_size
76        self.initialize_pool()
77        
78    def initialize_pool(self):
79        for _ in range(self.pool_size):
80            cactus = Cactus()
81            cactus.active = False
82            self.pool.append(cactus)
83    
84    def get_cactus(self):
85        # 非アクティブなサボテンを探す
86        for cactus in self.pool:
87            if not cactus.active:
88                cactus.reset()
89                return cactus
90        
91        # プールがいっぱいなら、最初の要素を再利用
92        cactus = self.pool[0]
93        cactus.reset()
94        return cactus
95    
96    def get_active_cacti(self):
97        # アクティブなサボテンのリストを返す
98        return [cactus for cactus in self.pool if cactus.active]
99
100class Game:
101    def __init__(self):
102        self.dinosaur = Dinosaur()
103        self.cactus_pool = CactusPool(15)  # 15個のサボテンプール
104        self.score = 0
105        self.font = pygame.font.SysFont(None, 36)
106        self.running = True
107        self.spawn_timer = 0
108        self.difficulty = 1.0  # 難易度係数
109        
110    def handle_events(self):
111        for event in pygame.event.get():
112            if event.type == pygame.QUIT:
113                self.running = False
114            if event.type == pygame.KEYDOWN:
115                if event.key == pygame.K_SPACE:
116                    self.dinosaur.jump()
117    
118    def update(self):
119        self.dinosaur.update()
120        
121        # 難易度は時間と共に増加
122        self.difficulty += 0.0005
123        
124        # サボテンの更新
125        active_cacti = self.cactus_pool.get_active_cacti()
126        for cactus in active_cacti:
127            # 速度を難易度に応じて調整
128            cactus.speed = 5 * self.difficulty
129            
130            if cactus.update():  # 画面外に出た場合
131                self.score += 1
132                
133        # サボテン生成タイマーの更新
134        self.spawn_timer -= 1
135        if self.spawn_timer <= 0:
136            # サボテン生成の間隔を難易度に基づいて調整
137            spawn_chance = 5 * self.difficulty
138            if random.randint(0, 100) < spawn_chance:
139                # 最後のサボテンから十分な距離があれば生成
140                if not active_cacti or WIDTH - active_cacti[-1].x >= 300 / self.difficulty:
141                    self.cactus_pool.get_cactus()
142                    # 次の生成までの時間をランダムに設定
143                    self.spawn_timer = random.randint(60, 120) // self.difficulty
144                
145        # 衝突判定
146        for cactus in active_cacti:
147            if self.dinosaur.get_rect().colliderect(cactus.get_rect()):
148                self.running = False
149    
150    def draw(self):
151        screen.fill(WHITE)
152        
153        # 地面の描画
154        pygame.draw.line(screen, BLACK, (0, HEIGHT - 10), (WIDTH, HEIGHT - 10), 2)
155        
156        # 恐竜とサボテンの描画
157        self.dinosaur.draw()
158        for cactus in self.cactus_pool.get_active_cacti():
159            cactus.draw()
160        
161        # スコア表示
162        score_text = self.font.render(f"Score: {self.score}", True, BLACK)
163        screen.blit(score_text, (10, 10))
164        
165        pygame.display.update()
166
167def main():
168    game = Game()
169    
170    while game.running:
171        game.handle_events()
172        game.update()
173        game.draw()
174        clock.tick(60)
175    
176    # ゲームオーバー画面
177    game_over_font = pygame.font.SysFont(None, 72)
178    game_over_text = game_over_font.render("GAME OVER", True, BLACK)
179    screen.blit(game_over_text, (WIDTH // 2 - 150, HEIGHT // 2 - 36))
180    pygame.display.update()
181    
182    # 3秒待機
183    pygame.time.wait(3000)
184    
185    pygame.quit()
186    sys.exit()
187
188if __name__ == "__main__":
189    main()

この改良版では、以下の効率化を実装しました:

  1. オブジェクトプーリング: サボテンのオブジェクトを再利用することで、メモリの割り当て/解放のオーバーヘッドを削減
  2. 動的難易度調整: 時間経過とともに徐々に難易度が上がるシステムを追加
  3. 効率的なオブジェクト管理: 画面外に出たオブジェクトを削除せず再利用

これにより、長時間プレイ時のメモリ使用量が安定し、最初の実装よりも効率的になります。

思考プロセス 6/10: エッジケースとエラーハンドリング

エッジケースとエラーハンドリングを考慮した改良版を作成します:

Python
1import pygame
2import random
3import sys
4import os
5
6# 初期化
7def initialize_game():
8    try:
9        pygame.init()
10        return pygame.display.set_mode((WIDTH, HEIGHT))
11    except pygame.error as e:
12        print(f"Pygameの初期化に失敗しました: {e}")
13        sys.exit(1)
14
15# 定数定義
16WIDTH, HEIGHT = 800, 300
17FPS = 60
18
19# 色の定義
20WHITE = (255, 255, 255)
21BLACK = (0, 0, 0)
22RED = (255, 0, 0)
23
24class Dinosaur:
25    def __init__(self):
26        self.width = 50
27        self.height = 50
28        self.x = 50
29        self.y = HEIGHT - self.height - 10
30        self.velocity_y = 0
31        self.is_jumping = False
32        self.jump_count = 0
33        self.max_jumps = 1  # 最大ジャンプ回数(ダブルジャンプを許可する場合は2に設定)
34        
35    def jump(self):
36        if self.jump_count < self.max_jumps:
37            self.is_jumping = True
38            self.velocity_y = -15
39            self.jump_count += 1
40    
41    def update(self):
42        if self.is_jumping:
43            self.y += self.velocity_y
44            self.velocity_y += 0.8
45            
46            # 地面以下には行かないように
47            if self.y >= HEIGHT - self.height - 10:
48                self.y = HEIGHT - self.height - 10
49                self.is_jumping = False
50                self.velocity_y = 0
51                self.jump_count = 0  # ジャンプカウントリセット
52    
53    def draw(self, surface):
54        pygame.draw.rect(surface, BLACK, (self.x, self.y, self.width, self.height))
55        
56    def get_rect(self):
57        return pygame.Rect(self.x, self.y, self.width, self.height)
58
59class Cactus:
60    def __init__(self):
61        self.width = 30
62        self.height = random.randint(30, 60)  # ランダムな高さ
63        self.x = WIDTH
64        self.y = HEIGHT - self.height - 10
65        self.speed = 5
66        self.active = False
67        
68    def reset(self):
69        self.height = random.randint(30, 60)  # 再利用時に高さをランダム化
70        self.y = HEIGHT - self.height - 10
71        self.x = WIDTH
72        self.active = True
73        
74    def update(self, game_speed):
75        if not self.active:
76            return False
77            
78        self.x -= game_speed
79        if self.x < -self.width:
80            self.active = False
81            return True  # オブジェクトが画面外
82        return False
83        
84    def draw(self, surface):
85        if self.active:
86            pygame.draw.rect(surface, BLACK, (self.x, self.y, self.width, self.height))
87        
88    def get_rect(self):
89        return pygame.Rect(self.x, self.y, self.width, self.height)
90
91class CactusPool:
92    def __init__(self, pool_size=15):
93        self.pool = []
94        self.pool_size = max(5, min(pool_size, 50))  # プールサイズの範囲を制限
95        self.initialize_pool()
96        
97    def initialize_pool(self):
98        for _ in range(self.pool_size):
99            cactus = Cactus()
100            cactus.active = False
101            self.pool.append(cactus)
102    
103    def get_cactus(self):
104        # 非アクティブなサボテンを探す
105        for cactus in self.pool:
106            if not cactus.active:
107                cactus.reset()
108                return cactus
109        
110        # プールがいっぱいならNoneを返す(これによりスポーンをスキップ)
111        return None
112    
113    def get_active_cacti(self):
114        return [cactus for cactus in self.pool if cactus.active]
115
116class GameState:
117    MENU = 0
118    PLAYING = 1
119    GAME_OVER = 2
120    PAUSED = 3
121
122class Game:
123    def __init__(self):
124        self.dinosaur = Dinosaur()
125        self.cactus_pool = CactusPool(15)
126        self.score = 0
127        self.high_score = self.load_high_score()
128        self.game_speed = 5.0
129        self.acceleration = 0.001  # ゲームスピードの加速率
130        self.state = GameState.MENU
131        self.spawn_timer = 0
132        
133        # フォント設定
134        try:
135            self.font = pygame.font.SysFont(None, 36)
136            self.large_font = pygame.font.SysFont(None, 72)
137        except Exception as e:
138            print(f"フォントの初期化エラー: {e}")
139            self.font = None
140            self.large_font = None
141        
142    def load_high_score(self):
143        try:
144            if os.path.exists("highscore.txt"):
145                with open("highscore.txt", "r") as f:
146                    return int(f.read().strip())
147        except (IOError, ValueError) as e:
148            print(f"ハイスコア読み込みエラー: {e}")
149        return 0
150        
151    def save_high_score(self):
152        try:
153            with open("highscore.txt", "w") as f:
154                f.write(str(self.high_score))
155        except IOError as e:
156            print(f"ハイスコア保存エラー: {e}")
157        
158    def handle_events(self):
159        for event in pygame.event.get():
160            if event.type == pygame.QUIT:
161                return False
162                
163            if event.type == pygame.KEYDOWN:
164                if event.key == pygame.K_ESCAPE:
165                    if self.state == GameState.PLAYING:
166                        self.state = GameState.PAUSED
167                    elif self.state == GameState.PAUSED:
168                        self.state = GameState.PLAYING
169                
170                if event.key == pygame.K_SPACE:
171                    if self.state == GameState.MENU:
172                        self.state = GameState.PLAYING
173                    elif self.state == GameState.PLAYING:
174                        self.dinosaur.jump()
175                    elif self.state == GameState.GAME_OVER:
176                        self.reset_game()
177                    elif self.state == GameState.PAUSED:
178                        self.state = GameState.PLAYING
179        
180        return True
181    
182    def reset_game(self):
183        self.dinosaur = Dinosaur()
184        self.cactus_pool = CactusPool(15)
185        self.score = 0
186        self.game_speed = 5.0

思考を再開

AIのプログラミング能力を上げるプロンプト(プロンプト公開)

続きから思考を再開します。思考プロセス6/10のエッジケースとエラーハンドリングを扱うコードを完成させ、その後残りの思考プロセスを進めていきます。


継続して思考プロセス6/10から進めていきます。

思考プロセス 6/10: エッジケースとエラーハンドリング(続き)

Python
1def reset_game(self):
2    self.dinosaur = Dinosaur()
3    self.cactus_pool = CactusPool(15)
4    self.score = 0
5    self.game_speed = 5.0
6    self.state = GameState.PLAYING
7    self.spawn_timer = 0
8    
9def update(self):
10    if self.state != GameState.PLAYING:
11        return
12        
13    # 恐竜の更新
14    self.dinosaur.update()
15    
16    # ゲームスピードの加速(最大値12.0まで)
17    self.game_speed = min(12.0, self.game_speed + self.acceleration)
18    
19    # スポーンタイマー更新
20    self.spawn_timer -= 1
21    
22    # サボテンの生成と更新
23    if self.spawn_timer <= 0:
24        # 難易度に応じたランダムなスポーン間隔
25        self.spawn_timer = random.randint(
26            max(20, int(100 - self.game_speed * 5)), 
27            max(40, int(150 - self.game_speed * 5))
28        )
29        
30        # アクティブなサボテンを取得
31        active_cacti = self.cactus_pool.get_active_cacti()
32        
33        # スポーン条件: アクティブなサボテンがないか、最後のサボテンが十分離れている
34        if not active_cacti or (WIDTH - active_cacti[-1].x >= max(200, 300 - self.game_speed * 10)):
35            new_cactus = self.cactus_pool.get_cactus()
36            # プールがいっぱいの場合はNoneが返る
37            if not new_cactus:
38                self.spawn_timer = 10  # 少し待ってから再試行
39    
40    # サボテンの更新と衝突チェック
41    for cactus in self.cactus_pool.get_active_cacti():
42        passed_screen = cactus.update(self.game_speed)
43        if passed_screen:
44            self.score += 1
45            
46            # ハイスコア更新チェック
47            if self.score > self.high_score:
48                self.high_score = self.score
49                self.save_high_score()
50        
51        # 衝突判定
52        if self.dinosaur.get_rect().colliderect(cactus.get_rect()):
53            self.state = GameState.GAME_OVER
54            
55def draw(self, screen):
56    # 背景塗りつぶし
57    screen.fill(WHITE)
58    
59    # 地面の描画
60    pygame.draw.line(screen, BLACK, (0, HEIGHT - 10), (WIDTH, HEIGHT - 10), 2)
61    
62    # 状態に応じた描画
63    if self.state == GameState.MENU:
64        self.draw_menu(screen)
65    elif self.state == GameState.PLAYING:
66        self.draw_game(screen)
67    elif self.state == GameState.GAME_OVER:
68        self.draw_game(screen)
69        self.draw_game_over(screen)
70    elif self.state == GameState.PAUSED:
71        self.draw_game(screen)
72        self.draw_paused(screen)
73    
74    pygame.display.update()
75    
76def draw_menu(self, screen):
77    # タイトル表示
78    if self.large_font:
79        title = self.large_font.render("DINO RUNNER", True, BLACK)
80        screen.blit(title, (WIDTH//2 - title.get_width()//2, HEIGHT//4))
81    
82    # 操作説明
83    if self.font:
84        instruction = self.font.render("Press SPACE to Start", True, BLACK)
85        screen.blit(instruction, (WIDTH//2 - instruction.get_width()//2, HEIGHT//2))
86        
87        # ハイスコア表示
88        high_score_text = self.font.render(f"High Score: {self.high_score}", True, BLACK)
89        screen.blit(high_score_text, (WIDTH//2 - high_score_text.get_width()//2, HEIGHT//2 + 50))
90    
91def draw_game(self, screen):
92    # 恐竜とサボテンの描画
93    self.dinosaur.draw(screen)
94    for cactus in self.cactus_pool.get_active_cacti():
95        cactus.draw(screen)
96    
97    # スコア表示
98    if self.font:
99        score_text = self.font.render(f"Score: {self.score}", True, BLACK)
100        high_score_text = self.font.render(f"High Score: {self.high_score}", True, BLACK)
101        screen.blit(score_text, (10, 10))
102        screen.blit(high_score_text, (WIDTH - high_score_text.get_width() - 10, 10))
103    
104def draw_game_over(self, screen):
105    overlay = pygame.Surface((WIDTH, HEIGHT), pygame.SRCALPHA)
106    overlay.fill((0, 0, 0, 128))  # 半透明のオーバーレイ
107    screen.blit(overlay, (0, 0))
108    
109    if self.large_font:
110        game_over = self.large_font.render("GAME OVER", True, RED)
111        screen.blit(game_over, (WIDTH//2 - game_over.get_width()//2, HEIGHT//3))
112    
113    if self.font:
114        restart = self.font.render("Press SPACE to Restart", True, WHITE)
115        final_score = self.font.render(f"Your Score: {self.score}", True, WHITE)
116        screen.blit(restart, (WIDTH//2 - restart.get_width()//2, HEIGHT//2))
117        screen.blit(final_score, (WIDTH//2 - final_score.get_width()//2, HEIGHT//2 + 50))
118        
119def draw_paused(self, screen):
120    overlay = pygame.Surface((WIDTH, HEIGHT), pygame.SRCALPHA)
121    overlay.fill((0, 0, 0, 128))  # 半透明のオーバーレイ
122    screen.blit(overlay, (0, 0))
123    
124    if self.large_font:
125        paused = self.large_font.render("PAUSED", True, BLACK)
126        screen.blit(paused, (WIDTH//2 - paused.get_width()//2, HEIGHT//3))
127    
128    if self.font:
129        continue_text = self.font.render("Press SPACE to Continue", True, WHITE)
130        screen.blit(continue_text, (WIDTH//2 - continue_text.get_width()//2, HEIGHT//2))
Python
1def main():
2    # Pygameの初期化
3    try:
4        pygame.init()
5        screen = pygame.display.set_mode((WIDTH, HEIGHT))
6        pygame.display.set_caption("恐竜ゲーム")
7        clock = pygame.time.Clock()
8    except pygame.error as e:
9        print(f"Pygameの初期化エラー: {e}")
10        return
11    
12    # ゲームインスタンスの作成
13    game = Game()
14    running = True
15    
16    # メインループ
17    try:
18        while running:
19            running = game.handle_events()
20            game.update()
21            game.draw(screen)
22            clock.tick(FPS)
23    except Exception as e:
24        print(f"ゲーム実行中にエラーが発生しました: {e}")
25    finally:
26        pygame.quit()
27        sys.exit()
28
29if __name__ == "__main__":
30    main()

このバージョンでは以下のエッジケースとエラーハンドリングを追加しました:

  1. 初期化エラー処理: Pygameの初期化に失敗した場合のエラーハンドリング
  2. フォント初期化エラー処理: フォントが見つからない場合のフォールバック
  3. ハイスコアの保存と読み込みエラー処理: ファイル操作が失敗した場合のエラーハンドリング
  4. メモリ管理の改善: プールサイズの制限と、プールがいっぱいの場合の対応
  5. 状態管理の実装: メニュー、プレイ中、ゲームオーバー、一時停止の状態を管理
  6. 例外処理: メインループでの予期せぬエラーをキャッチ
  7. エッジケース対応: スポーン間隔の動的調整、高すぎるゲームスピードの制限など

思考プロセス 7/10: 別のアルゴリズム/アプローチの探求

これまでのアプローチとは異なる、代替的な実装方法を検討します:

1. イベント駆動型アプローチ

現在の実装はフレームベースのゲームループを使用していますが、Pygameのイベントシステムをより活用したイベント駆動型のアプローチも考えられます。

利点:

  • CPU使用率の低減(アイドル状態でのCPU使用を削減)
  • バックグラウンド実行時のパフォーマンス向上

欠点:

  • タイミングが重要なゲームメカニクスでは精度が低下する可能性
  • 実装が複雑になる可能性

2. クラスベースからコンポーネントベースへの移行

現在のオブジェクト指向アプローチの代わりに、Entity-Component-System (ECS) パターンを使用する方法もあります。

利点:

  • より柔軟で拡張性の高い設計
  • 機能の組み合わせが容易(例: 異なる種類の障害物を簡単に追加できる)
  • パフォーマンスの向上(特に大量のエンティティがある場合)

欠点:

  • このようなシンプルなゲームでは過剰な設計になる可能性
  • 学習曲線が高い

3. 画像ではなく形状で表示するアプローチ

現在の実装では図形描画を使っていますが、スプライトシートを使用した実装も考えられます。

利点:

  • より視覚的に魅力的なゲーム
  • アニメーションの実装が容易
  • 本物のChrome恐竜ゲームに近い見た目

欠点:

  • リソース管理が必要
  • 初期ロード時間の増加
  • 実装が少し複雑になる

4. 物理ベースのアプローチ

現在のシンプルな物理(重力と衝突検出)の代わりに、Pymunk(Pythonの物理エンジン)などを使用する方法もあります。

利点:

  • より現実的な物理挙動
  • 複雑なインタラクションが可能

欠点:

  • パフォーマンスへの影響
  • 単純なゲームでは過剰
  • 追加の依存関係

推奨するアプローチは、現在のシンプルなアプローチにスプライトシートによるグラフィックとアニメーションを追加することです。これにより、ゲームの視覚的な魅力が大幅に向上し、本物のChrome恐竜ゲームに近づきます。

思考プロセス 8/10: モジュール性と再利用性

ゲームコードの再利用性とモジュール性を高めるために、コンポーネントごとにファイルを分割し、適切なドキュメンテーションを追加します。

ファイル構造:

1dino_runner/
2├── assets/
3│   └── images/
4│       ├── dino.png
5│       └── cactus.png
6├── src/
7│   ├── __init__.py
8│   ├── constants.py
9│   ├── entities/
10│   │   ├── __init__.py
11│   │   ├── dinosaur.py
12│   │   └── obstacles.py
13│   ├── utils/
14│   │   ├── __init__.py
15│   │   ├── asset_loader.py
16│   │   └── object_pool.py
17│   └── game.py
18└── main.py

constants.py:

Python
1"""
2定数とゲーム設定を定義するモジュール
3"""
4
5# ゲームウィンドウ設定
6WIDTH = 800
7HEIGHT = 300
8FPS = 60
9TITLE = "恐竜ゲーム"
10
11# 色定義
12WHITE = (255, 255, 255)
13BLACK = (0, 0, 0)
14RED = (255, 0, 0)
15
16# ゲーム状態
17class GameState:
18    MENU = 0
19    PLAYING = 1
20    GAME_OVER = 2
21    PAUSED = 3
22
23# 物理設定
24GRAVITY = 0.8
25JUMP_FORCE = -15
26
27# ゲーム難易度設定
28INITIAL_GAME_SPEED = 5.0
29MAX_GAME_SPEED = 12.0
30ACCELERATION_RATE = 0.001

entities/dinosaur.py:

Python
1"""
2恐竜キャラクターの実装
3"""
4import pygame
5from ..constants import HEIGHT, BLACK, GRAVITY, JUMP_FORCE
6
7class Dinosaur:
8    """
9    プレイヤーが操作する恐竜キャラクターのクラス
10    
11    Attributes:
12        width (int): 恐竜の幅
13        height (int): 恐竜の高さ
14        x (int): X座標位置
15        y (int): Y座標位置
16        velocity_y (float): Y軸方向の速度
17        is_jumping (bool): ジャンプ中かどうか
18        jump_count (int): 連続ジャンプのカウント
19        max_jumps (int): 最大連続ジャンプ回数
20    """
21    
22    def __init__(self, x=50, y=None, width=50, height=50):
23        """
24        恐竜キャラクターの初期化
25        
26        Args:
27            x (int, optional): 初期X座標。デフォルトは50
28            y (int, optional): 初期Y座標。Noneの場合は

思考を再開

AIのプログラミング能力を上げるプロンプト(プロンプト公開)

恐竜ゲームのPythonコードの思考プロセス続きです。モジュール性と再利用性を高めるためのリファクタリングの続きを考えます。entities/dinosaur.pyのコードから途中で切れているので、そこから続けます。


思考プロセス8/10の続きから再開します。モジュール性と再利用性を向上させるためのコード構造を詳細に示していきます。

思考プロセス 8/10: モジュール性と再利用性(続き)

entities/dinosaur.py (続き):

Python
1    def __init__(self, x=50, y=None, width=50, height=50):
2        """
3        恐竜キャラクターの初期化
4        
5        Args:
6            x (int, optional): 初期X座標。デフォルトは50
7            y (int, optional): 初期Y座標。Noneの場合は地面の上に配置
8            width (int, optional): 恐竜の幅。デフォルトは50
9            height (int, optional): 恐竜の高さ。デフォルトは50
10        """
11        self.width = width
12        self.height = height
13        self.x = x
14        self.y = y if y is not None else HEIGHT - height - 10
15        self.velocity_y = 0
16        self.is_jumping = False
17        self.jump_count = 0
18        self.max_jumps = 1
19        
20    def jump(self):
21        """
22        恐竜をジャンプさせる。最大ジャンプ回数に達していない場合のみジャンプ可能
23        
24        Returns:
25            bool: ジャンプが実行されたかどうか
26        """
27        if self.jump_count < self.max_jumps:
28            self.is_jumping = True
29            self.velocity_y = JUMP_FORCE
30            self.jump_count += 1
31            return True
32        return False
33    
34    def update(self):
35        """
36        恐竜の状態を更新する(物理演算、位置など)
37        """
38        if self.is_jumping:
39            self.y += self.velocity_y
40            self.velocity_y += GRAVITY
41            
42            # 地面に着地
43            if self.y >= HEIGHT - self.height - 10:
44                self.y = HEIGHT - self.height - 10
45                self.is_jumping = False
46                self.velocity_y = 0
47                self.jump_count = 0
48    
49    def draw(self, surface):
50        """
51        恐竜を描画する
52        
53        Args:
54            surface (pygame.Surface): 描画対象のサーフェス
55        """
56        pygame.draw.rect(surface, BLACK, (self.x, self.y, self.width, self.height))
57        
58    def get_rect(self):
59        """
60        衝突判定用の矩形を取得
61        
62        Returns:
63            pygame.Rect: 恐竜の衝突判定用矩形
64        """
65        return pygame.Rect(self.x, self.y, self.width, self.height)

entities/obstacles.py:

Python
1"""
2障害物(サボテンなど)の実装
3"""
4import pygame
5import random
6from ..constants import WIDTH, HEIGHT, BLACK
7
8class Cactus:
9    """
10    ゲーム内の障害物であるサボテンを表すクラス
11    
12    Attributes:
13        width (int): サボテンの幅
14        height (int): サボテンの高さ
15        x (int): X座標位置
16        y (int): Y座標位置
17        speed (float): 移動速度
18        active (bool): アクティブ状態かどうか
19    """
20    
21    def __init__(self):
22        """
23        サボテンの初期化。デフォルトでは非アクティブ状態で初期化
24        """
25        self.width = 30
26        self.height = random.randint(30, 60)
27        self.x = WIDTH
28        self.y = HEIGHT - self.height - 10
29        self.speed = 5
30        self.active = False
31        
32    def reset(self):
33        """
34        サボテンを再利用するためにリセットする
35        """
36        self.height = random.randint(30, 60)
37        self.y = HEIGHT - self.height - 10
38        self.x = WIDTH
39        self.active = True
40        
41    def update(self, game_speed):
42        """
43        サボテンの状態を更新する
44        
45        Args:
46            game_speed (float): 現在のゲームスピード
47            
48        Returns:
49            bool: サボテンが画面外に出たかどうか
50        """
51        if not self.active:
52            return False
53            
54        self.x -= game_speed
55        if self.x < -self.width:
56            self.active = False
57            return True  # 画面外に出た
58        return False
59        
60    def draw(self, surface):
61        """
62        サボテンを描画する
63        
64        Args:
65            surface (pygame.Surface): 描画対象のサーフェス
66        """
67        if self.active:
68            pygame.draw.rect(surface, BLACK, (self.x, self.y, self.width, self.height))
69        
70    def get_rect(self):
71        """
72        衝突判定用の矩形を取得
73        
74        Returns:
75            pygame.Rect: サボテンの衝突判定用矩形
76        """
77        return pygame.Rect(self.x, self.y, self.width, self.height)

utils/object_pool.py:

Python
1"""
2オブジェクトプーリングを実装するユーティリティ
3"""
4
5class ObjectPool:
6    """
7    メモリ効率を向上させるためのオブジェクトプールクラス
8    
9    Attributes:
10        pool (list): プールされたオブジェクトのリスト
11        pool_size (int): プールの最大サイズ
12        object_class (class): プールするオブジェクトのクラス
13    """
14    
15    def __init__(self, object_class, pool_size=15):
16        """
17        オブジェクトプールの初期化
18        
19        Args:
20            object_class (class): プールするオブジェクトのクラス
21            pool_size (int, optional): プールの最大サイズ。デフォルトは15
22        """
23        self.pool = []
24        self.pool_size = max(5, min(pool_size, 50))  # サイズを5~50に制限
25        self.object_class = object_class
26        self.initialize_pool()
27        
28    def initialize_pool(self):
29        """
30        プールを初期化し、指定されたサイズまでオブジェクトを生成する
31        """
32        for _ in range(self.pool_size):
33            obj = self.object_class()
34            if hasattr(obj, 'active'):
35                obj.active = False
36            self.pool.append(obj)
37    
38    def get_object(self):
39        """
40        プールから非アクティブなオブジェクトを取得する
41        
42        Returns:
43            object: 使用可能なオブジェクト、または存在しない場合はNone
44        """
45        for obj in self.pool:
46            if hasattr(obj, 'active') and not obj.active:
47                if hasattr(obj, 'reset'):
48                    obj.reset()
49                else:
50                    obj.active = True
51                return obj
52        
53        # プールがいっぱいの場合
54        return None
55    
56    def get_active_objects(self):
57        """
58        現在アクティブなオブジェクトのリストを返す
59        
60        Returns:
61            list: アクティブなオブジェクトのリスト
62        """
63        return [obj for obj in self.pool if hasattr(obj, 'active') and obj.active]

game.py:

Python
1"""
2メインゲームロジックと状態管理
3"""
4import pygame
5import random
6import os
7from .constants import *
8from .entities.dinosaur import Dinosaur
9from .entities.obstacles import Cactus
10from .utils.object_pool import ObjectPool
11
12class Game:
13    """
14    ゲームの管理と状態を処理するメインクラス
15    
16    Attributes:
17        dinosaur (Dinosaur): プレイヤーキャラクター
18        obstacle_pool (ObjectPool): 障害物オブジェクトのプール
19        score (int): 現在のスコア
20        high_score (int): 最高スコア
21        game_speed (float): ゲームの速度
22        state (int): 現在のゲーム状態
23        spawn_timer (int): 障害物生成タイマー
24    """
25    
26    def __init__(self):
27        """
28        ゲームの初期化
29        """
30        self.dinosaur = Dinosaur()
31        self.obstacle_pool = ObjectPool(Cactus, 15)
32        self.score = 0
33        self.high_score = self.load_high_score()
34        self.game_speed = INITIAL_GAME_SPEED
35        self.state = GameState.MENU
36        self.spawn_timer = 0
37        
38        # フォント設定
39        try:
40            self.font = pygame.font.SysFont(None, 36)
41            self.large_font = pygame.font.SysFont(None, 72)
42        except Exception as e:
43            print(f"フォントの初期化エラー: {e}")
44            self.font = None
45            self.large_font = None
46    
47    def load_high_score(self):
48        """
49        ハイスコアをファイルから読み込む
50        
51        Returns:
52            int: 読み込んだハイスコア、ファイルが存在しない場合は0
53        """
54        try:
55            if os.path.exists("highscore.txt"):
56                with open("highscore.txt", "r") as f:
57                    return int(f.read().strip())
58        except (IOError, ValueError) as e:
59            print(f"ハイスコア読み込みエラー: {e}")
60        return 0
61        
62    def save_high_score(self):
63        """
64        ハイスコアをファイルに保存する
65        """
66        try:
67            with open("highscore.txt", "w") as f:
68                f.write(str(self.high_score))
69        except IOError as e:
70            print(f"ハイスコア保存エラー: {e}")
71    
72    # 以下、handle_events, update, drawなどのメソッド...
73    # これらのメソッドは思考プロセス6で定義したものと同様

main.py:

Python
1"""
2ゲームのエントリーポイント
3"""
4import pygame
5import sys
6from src.constants import WIDTH, HEIGHT, FPS, TITLE
7from src.game import Game
8
9def main():
10    """
11    ゲームのメインエントリーポイント
12    
13    Pygameの初期化、ゲームの作成、メインループの実行を行う
14    """
15    # Pygameの初期化
16    try:
17        pygame.init()
18        screen = pygame.display.set_mode((WIDTH, HEIGHT))
19        pygame.display.set_caption(TITLE)
20        clock = pygame.time.Clock()
21    except pygame.error as e:
22        print(f"Pygameの初期化エラー: {e}")
23        return
24    
25    # ゲームインスタンスの作成
26    game = Game()
27    running = True
28    
29    # メインループ
30    try:
31        while running:
32            # イベント処理
33            for event in pygame.event.get():
34                if event.type == pygame.QUIT:
35                    running = False
36                    
37                if event.type == pygame.KEYDOWN:
38                    if event.key == pygame.K_ESCAPE:
39                        if game.state == GameState.PLAYING:
40                            game.state = GameState.PAUSED
41                        elif game.state == GameState.PAUSED:
42                            game.state = GameState.PLAYING
43                    
44                    if event.key == pygame.K_SPACE:
45                        if game.state == GameState.MENU:
46                            game.state = GameState.PLAYING
47                        elif game.state == GameState.PLAYING:
48                            game.dinosaur.jump()
49                        elif game.state == GameState.GAME_OVER:
50                            game.reset_game()
51                        elif game.state == GameState.PAUSED:
52                            game.state = GameState.PLAYING
53                
54            # ゲーム状態の更新と描画
55            game.update()
56            game.draw(screen)
57            
58            # フレームレート制御
59            clock.tick(FPS)
60            
61    except Exception as e:
62        print(f"ゲーム実行中にエラーが発生しました: {e}")
63    finally:
64        pygame.quit()
65        sys.exit()
66
67if __name__ == "__main__":
68    main()

このリファクタリングでは以下の変更を行いました:

  1. コードの分割: 機能ごとに別々のモジュールやクラスに分割
  2. 抽象化: ObjectPoolのような汎用クラスを作成して再利用性を向上
  3. ドキュメンテーション: 各ファイル、クラス、メソッドにドキュメントを追加
  4. 構成の最適化: 関連する機能をグループ化して、適切なディレクトリ構造を実現
  5. 定数の分離: 設定値を定数モジュールに分離して管理を容易に

この構造により、コードの保守性、拡張性、再利用性が大幅に向上します。

思考プロセス 9/10: 言語固有の最適化/イディオムの適用

Pythonの特性を活かした最適化と、より「Pythonic」なコードスタイルを適用します。

  1. リスト内包表記の活用:
Python
1# 以前のコード
2def get_active_objects(self):
3    active_objects = []
4    for obj in self.pool:
5        if hasattr(obj, 'active') and obj.active:
6            active_objects.append(obj)
7    return active_objects
8
9# 最適化したコード
10def get_active_objects(self):
11    return [obj for obj in self.pool if hasattr(obj, 'active') and obj.active]
  1. デコレータの活用:
Python
1def timer(func):
2    """関数の実行時間を測定するデコレータ"""
3    def wrapper(*args, **kwargs):
4        start_time = pygame.time.get_ticks()
5        result = func(*args, **kwargs)
6        end_time = pygame.time.get_ticks()
7        print(f"{func.__name__}の実行時間: {end_time - start_time}ms")
8        return result
9    return wrapper
10
11# 使用例
12@timer
13def update(self):
14    # 更新処理
15    pass

3

思考を再開

AIのプログラミング能力を上げるプロンプト(プロンプト公開)

思考プロセス9/10の続きから再開します。Pythonの特性を活かした最適化と、より「Pythonic」なコードスタイルの適用の続きを考えます。


思考プロセス 9/10: 言語固有の最適化/イディオムの適用(続き)

  1. プロパティの使用:
Python
1class Dinosaur:
2    def __init__(self):
3        self._x = 50
4        self._y = HEIGHT - 50 - 10
5        # 他の初期化
6    
7    @property
8    def x(self):
9        return self._x
10    
11    @property
12    def y(self):
13        return self._y
14    
15    @y.setter
16    def y(self, value):
17        # 地面より下には行かないように制限
18        self._y = min(value, HEIGHT - self.height - 10)
19    
20    @property
21    def rect(self):
22        """衝突判定用の矩形を動的に生成"""
23        return pygame.Rect(self._x, self._y, self.width, self.height)
  1. 列挙型の活用:
Python
1from enum import Enum, auto
2
3class GameState(Enum):
4    MENU = auto()
5    PLAYING = auto()
6    GAME_OVER = auto()
7    PAUSED = auto()
8
9# 使用例
10if self.state == GameState.PLAYING:
11    # ゲームプレイ中の処理
  1. コンテキストマネージャの活用:
Python
1class GameSession:
2    def __enter__(self):
3        pygame.init()
4        return self
5        
6    def __exit__(self, exc_type, exc_val, exc_tb):
7        pygame.quit()
8
9# 使用例
10with GameSession() as session:
11    # ゲームのメインロジック
12    game = Game()
13    # ...
14# withブロックを抜けると自動的にpygame.quit()が呼ばれる
  1. dataclassの使用:
Python
1from dataclasses import dataclass
2
3@dataclass
4class GameConfig:
5    width: int = 800
6    height: int = 300
7    fps: int = 60
8    title: str = "恐竜ゲーム"
9    gravity: float = 0.8
10    jump_force: float = -15
11    initial_speed: float = 5.0
  1. ジェネレータ式の使用:
Python
1def check_collisions(self):
2    """恐竜と障害物の衝突をチェック"""
3    dino_rect = self.dinosaur.rect
4    return any(obstacle.rect.colliderect(dino_rect) for obstacle in self.obstacle_pool.get_active_objects())
  1. defaultdictの使用:
Python
1from collections import defaultdict
2
3class ScoreManager:
4    def __init__(self):
5        # カテゴリごとのスコアを管理(未設定のキーは自動的に0に初期化)
6        self.scores = defaultdict(int)
7    
8    def add_score(self, category, points):
9        self.scores[category] += points
10    
11    def get_total_score(self):
12        return sum(self.scores.values())
  1. functools.lru_cacheの使用:
Python
1import functools
2
3class AssetManager:
4    @functools.lru_cache(maxsize=32)
5    def load_image(self, name):
6        """画像を読み込み、キャッシュする"""
7        try:
8            return pygame.image.load(f"assets/images/{name}.png").convert_alpha()
9        except pygame.error:
10            print(f"画像 {name}.png の読み込みに失敗しました")
11            # 代替画像を返す
12            return pygame.Surface((30, 30))
  1. f文字列の活用:
Python
1# 古いスタイル
2score_text = self.font.render("Score: " + str(self.score), True, BLACK)
3
4# Pythonic なスタイル
5score_text = self.font.render(f"Score: {self.score}", True, BLACK)

これらのPythonの言語特性を活かすことで、コードは簡潔になり、可読性と保守性が向上します。また、一部の最適化(例:@functools.lru_cache)により、パフォーマンスも改善されます。

思考プロセス 10/10: 最終レビューと比較、最適なコードの選定

これまでに検討した3つの主要なコードバージョンを比較します:

  1. 最初のシンプル実装(思考プロセス1/10)

    • 単一ファイルで基本機能のみを実装
    • コードの長さ: 約100行
    • 特徴: 理解しやすい、機能は最小限
  2. エッジケース対応版(思考プロセス6/10)

    • 状態管理、エラーハンドリング、難易度調整などを追加
    • コードの長さ: 約300行
    • 特徴: より堅牢、ゲーム体験が向上
  3. モジュール化+最適化版(思考プロセス8/10+9/10)

    • 複数ファイルに分割、Pythonイディオムを活用
    • コードの全長: 約500行(複数ファイル合計)
    • 特徴: 保守性と拡張性が高い、リファクタリングしやすい

どの実装を選ぶべきか?それは以下の状況によります

  1. 学習目的: シンプル実装(思考プロセス1/10)が最適

    • 理解しやすく、Pygameの基本を学べる
    • 変更や実験が容易
  2. 実用目的(個人使用): エッジケース対応版(思考プロセス6/10)が最適

    • 基本的なゲーム体験を提供しつつ、堅牢性がある
    • 必要な機能はほぼすべて含まれている
  3. 拡張・保守目的(チーム開発): モジュール化+最適化版(思考プロセス8/10+9/10)が最適

    • 新機能の追加が容易
    • コードの理解と分担作業が容易
    • 長期的なメンテナンスに適している

最終的な推奨コード:

一般的な使用目的を考慮すると、エッジケース対応版(思考プロセス6/10)が最もバランスが良いと思われます。これは以下の理由からです:

  1. 単一ファイルで理解しやすいが、必要な機能と堅牢性を備えている
  2. 過度に複雑化せずに良いゲーム体験を提供できる
  3. 必要に応じて拡張可能な基盤を持っている

この最終的な実装では、以下の特徴があります:

  • メニュー、ゲームプレイ、一時停止、ゲームオーバーの状態管理
  • 障害物のオブジェクトプーリングによるメモリ効率化
  • 難易度の動的調整
  • エラーハンドリングとエッジケース対応
  • ハイスコアシステム
  • 明確なコードコメントと構造

このバージョンは、Pygameの学習者からある程度経験のあるプログラマーまで、幅広いユーザーにとって有用なコードになっています。必要に応じて、思考プロセス8と9で検討したモジュール化や言語最適化を適用することで、さらに拡張することもできます。

最終的には、求める恐竜ゲームの複雑さと用途に応じて、これらの実装から最適なものを選択するか、必要に応じて組み合わせることをお勧めします。

回答を提示してください

AIのプログラミング能力を上げるプロンプト(プロンプト公開)

最終的な回答としては、前の思考プロセスで考えた内容を統合して、Chrome恐竜ゲームのPython実装を提案します。バランスの取れたエッジケース対応版を中心に示しつつ、実行可能な単一ファイルの完全なコードを提供することが最適だと考えます。


Chromeの恐竜ゲーム実装(T-Rex Runner)

Chromeブラウザのオフライン時に表示される恐竜ゲームをPythonで実装しました。以下のコードはPygameライブラリを使用して作成した完全に動作するバージョンです。

Python
1import pygame
2import random
3import sys
4import os
5
6# 初期化
7pygame.init()
8WIDTH, HEIGHT = 800, 300
9screen = pygame.display.set_mode((WIDTH, HEIGHT))
10pygame.display.set_caption("恐竜ゲーム")
11clock = pygame.time.Clock()
12FPS = 60
13
14# 色の定義
15WHITE = (255, 255, 255)
16BLACK = (0, 0, 0)
17RED = (255, 0, 0)
18
19# ゲーム状態
20class GameState:
21    MENU = 0
22    PLAYING = 1
23    GAME_OVER = 2
24    PAUSED = 3
25
26class Dinosaur:
27    def __init__(self):
28        self.width = 50
29        self.height = 50
30        self.x = 50
31        self.y = HEIGHT - self.height - 10
32        self.velocity_y = 0
33        self.is_jumping = False
34        self.jump_count = 0
35        self.max_jumps = 1
36        
37    def jump(self):
38        if self.jump_count < self.max_jumps:
39            self.is_jumping = True
40            self.velocity_y = -15
41            self.jump_count += 1
42            return True
43        return False
44    
45    def update(self):
46        if self.is_jumping:
47            self.y += self.velocity_y
48            self.velocity_y += 0.8
49            
50            if self.y >= HEIGHT - self.height - 10:
51                self.y = HEIGHT - self.height - 10
52                self.is_jumping = False
53                self.velocity_y = 0
54                self.jump_count = 0
55    
56    def draw(self, surface):
57        pygame.draw.rect(surface, BLACK, (self.x, self.y, self.width, self.height))
58        
59    def get_rect(self):
60        return pygame.Rect(self.x, self.y, self.width, self.height)
61
62class Cactus:
63    def __init__(self):
64        self.width = 30
65        self.height = random.randint(30, 60)
66        self.x = WIDTH
67        self.y = HEIGHT - self.height - 10
68        self.speed = 5
69        self.active = False
70        
71    def reset(self):
72        self.height = random.randint(30, 60)
73        self.y = HEIGHT - self.height - 10
74        self.x = WIDTH
75        self.active = True
76        
77    def update(self, game_speed):
78        if not self.active:
79            return False
80            
81        self.x -= game_speed
82        if self.x < -self.width:
83            self.active = False
84            return True  # 画面外に出た
85        return False
86        
87    def draw(self, surface):
88        if self.active:
89            pygame.draw.rect(surface, BLACK, (self.x, self.y, self.width, self.height))
90        
91    def get_rect(self):
92        return pygame.Rect(self.x, self.y, self.width, self.height)
93
94class CactusPool:
95    def __init__(self, pool_size=15):
96        self.pool = []
97        self.pool_size = max(5, min(pool_size, 50))
98        self.initialize_pool()
99        
100    def initialize_pool(self):
101        for _ in range(self.pool_size):
102            cactus = Cactus()
103            cactus.active = False
104            self.pool.append(cactus)
105    
106    def get_cactus(self):
107        # 非アクティブなサボテンを探す
108        for cactus in self.pool:
109            if not cactus.active:
110                cactus.reset()
111                return cactus
112        
113        # プールがいっぱいならNoneを返す
114        return None
115    
116    def get_active_cacti(self):
117        return [cactus for cactus in self.pool if cactus.active]
118
119class Game:
120    def __init__(self):
121        self.dinosaur = Dinosaur()
122        self.cactus_pool = CactusPool(15)
123        self.score = 0
124        self.high_score = self.load_high_score()
125        self.game_speed = 5.0
126        self.acceleration = 0.001
127        self.state = GameState.MENU
128        self.spawn_timer = 0
129        
130        # フォント設定
131        try:
132            self.font = pygame.font.SysFont(None, 36)
133            self.large_font = pygame.font.SysFont(None, 72)
134        except Exception as e:
135            print(f"フォントの初期化エラー: {e}")
136            self.font = None
137            self.large_font = None
138        
139    def load_high_score(self):
140        try:
141            if os.path.exists("highscore.txt"):
142                with open("highscore.txt", "r") as f:
143                    return int(f.read().strip())
144        except (IOError, ValueError) as e:
145            print(f"ハイスコア読み込みエラー: {e}")
146        return 0
147        
148    def save_high_score(self):
149        try:
150            with open("highscore.txt", "w") as f:
151                f.write(str(self.high_score))
152        except IOError as e:
153            print(f"ハイスコア保存エラー: {e}")
154        
155    def handle_events(self):
156        for event in pygame.event.get():
157            if event.type == pygame.QUIT:
158                return False
159                
160            if event.type == pygame.KEYDOWN:
161                if event.key == pygame.K_ESCAPE:
162                    if self.state == GameState.PLAYING:
163                        self.state = GameState.PAUSED
164                    elif self.state == GameState.PAUSED:
165                        self.state = GameState.PLAYING
166                
167                if event.key == pygame.K_SPACE:
168                    if self.state == GameState.MENU:
169                        self.state = GameState.PLAYING
170                    elif self.state == GameState.PLAYING:
171                        self.dinosaur.jump()
172                    elif self.state == GameState.GAME_OVER:
173                        self.reset_game()
174                    elif self.state == GameState.PAUSED:
175                        self.state = GameState.PLAYING
176        
177        return True
178    
179    def reset_game(self):
180        self.dinosaur = Dinosaur()
181        self.cactus_pool = CactusPool(15)
182        self.score = 0
183        self.game_speed = 5.0
184        self.state = GameState.PLAYING
185        self.spawn_timer = 0
186    
187    def update(self):
188        if self.state != GameState.PLAYING:
189            return
190            
191        # 恐竜の更新
192        self.dinosaur.update()
193        
194        # ゲームスピードの加速(最大値12.0まで)
195        self.game_speed = min(12.0, self.game_speed + self.acceleration)
196        
197        # スポーンタイマー更新
198        self.spawn_timer -= 1
199        
200        # サボテンの生成と更新
201        if self.spawn_timer <= 0:
202            # 難易度に応じたランダムなスポーン間隔
203            self.spawn_timer = random.randint(
204                max(20, int(100 - self.game_speed * 5)), 
205                max(40, int(150 - self.game_speed * 5))
206            )
207            
208            # アクティブなサボテンを取得
209            active_cacti = self.cactus_pool.get_active_cacti()
210            
211            # スポーン条件: アクティブなサボテンがないか、最後のサボテンが十分離れている
212            if not active_cacti or (WIDTH - active_cacti[-1].x >= max(200, 300 - self.game_speed * 10)):
213                new_cactus = self.cactus_pool.get_cactus()
214                # プールがいっぱいの場合はNoneが返る
215                if not new_cactus:
216                    self.spawn_timer = 10  # 少し待ってから再試行
217        
218        # サボテンの更新と衝突チェック
219        for cactus in self.cactus_pool.get_active_cacti():
220            passed_screen = cactus.update(self.game_speed)
221            if passed_screen:
222                self.score += 1
223                
224                # ハイスコア更新チェック
225                if self.score > self.high_score:
226                    self.high_score = self.score
227                    self.save_high_score()
228            
229            # 衝突判定
230            if self.dinosaur.get_rect().colliderect(cactus.get_rect()):
231                self.state = GameState.GAME_OVER
232                
233    def draw(self, screen):
234        # 背景塗りつぶし
235        screen.fill(WHITE)
236        
237        # 地面の描画
238        pygame.draw.line(screen, BLACK, (0, HEIGHT - 10), (WIDTH, HEIGHT - 10), 2)
239        
240        # 状態に応じた描画
241        if self.state == GameState.MENU:
242            self.draw_menu(screen)
243        elif self.state == GameState.PLAYING:
244            self.draw_game(screen)
245        elif self.state == GameState.GAME_OVER:
246            self.draw_game(screen)
247            self.draw_game_over(screen)
248        elif self.state == GameState.PAUSED:
249            self.draw_game(screen)
250            self.draw_paused(screen)
251        
252        pygame.display.update()
253        
254    def draw_menu(self, screen):
255        # タイトル表示
256        if self.large_font:
257            title = self.large_font.render("DINO RUNNER", True, BLACK)
258            screen.blit(title, (WIDTH//2 - title.get_width()//2, HEIGHT//4))
259        
260        # 操作説明
261        if self.font:
262            instruction = self.font.render("Press SPACE to Start", True, BLACK)
263            screen.blit(instruction, (WIDTH//2 - instruction.get_width()//2, HEIGHT//2))
264            
265            # ハイスコア表示
266            high_score_text = self.font.render(f"High Score: {self.high_score}", True, BLACK)
267            screen.blit(high_score_text, (WIDTH//2 - high_score_text.get_width()//2, HEIGHT//2 + 50))
268        
269    def draw_game(self, screen):
270        # 恐竜とサボテンの描画
271        self.dinosaur.draw(screen)
272        for cactus in self.cactus_pool.get_active_cacti():
273            cactus.draw(screen)
274        
275        # スコア表示
276        if self.font:
277            score_text = self.font.render(f"Score: {self.score}", True, BLACK)
278            high_score_text = self.font.render(f"High Score: {self.high_score}", True, BLACK)
279            screen.blit(score_text, (10, 10))
280            screen.blit(high_score_text, (WIDTH - high_score_text.get_width() - 10, 10))
281        
282    def draw_game_over(self, screen):
283        overlay = pygame.Surface((WIDTH, HEIGHT), pygame.SRCALPHA)
284        overlay.fill((0, 0, 0, 128))  # 半透明のオーバーレイ
285        screen.blit(overlay, (0, 0))
286        
287        if self.large_font:
288            game_over = self.large_font.render("GAME OVER", True, RED)
289            screen.blit(game_over, (WIDTH//2 - game_over.get_width()//2, HEIGHT//3))
290        
291        if self.font:
292            restart = self.font.render("Press SPACE to Restart", True, WHITE)
293            final_score = self.font.render(f"Your Score: {self.score}", True, WHITE)
294            screen.blit(restart, (WIDTH//2 - restart.get_width()//2, HEIGHT//2))
295            screen.blit(final_score, (WIDTH//2 - final_score.get_width()//2, HEIGHT//2 + 50))
296            
297    def draw_paused(self, screen):
298        overlay = pygame.Surface((WIDTH, HEIGHT), pygame.SRCALPHA)
299        overlay.fill((0, 0, 0, 128))  # 半透明のオーバーレイ
300        screen.blit(overlay, (0, 0))
301        
302        if self.large_font:
303            paused = self.large_font.render("PAUSED", True, BLACK)
304            screen.blit(paused, (WIDTH//2 - paused.get_width()//2, HEIGHT//3))
305        
306        if self.font:
307            continue_text = self.font.render("Press SPACE to Continue", True, WHITE)
308            screen.blit(continue_text, (WIDTH//2 - continue_text.get_width()//2, HEIGHT//2))
309
310def main():
311    # ゲームインスタンスの作成
312    game = Game()
313    running = True
314    
315    # メインループ
316    try:
317        while running:
318            running = game.handle_events()
319            game.update()
320            game.draw(screen)
321            clock.tick(FPS)
322    except Exception as e:
323        print(f"ゲーム実行中にエラーが発生しました: {e}")
324    finally:
325        pygame.quit()
326        sys.exit()
327
328if __name__ == "__main__":
329    main()

ゲームの特徴

  1. シンプルな操作

    • SPACE キー:ジャンプ / メニュー選択 / ゲーム再開
    • ESC キー:一時停止 / 再開
  2. ゲーム要素

    • 恐竜キャラクターがジャンプしてサボテンを避ける
    • 時間経過とともにゲームスピードが上昇し、難易度が増加
    • スコアシステムとハイスコアの保存機能
  3. ゲーム状態

    • メニュー画面
    • プレイ中
    • ゲームオーバー
    • 一時停止
  4. 技術的特徴

    • オブジェクトプーリングによるメモリ効率化
    • エラーハンドリングと例外処理
    • 動的な難易度調整

インストールと実行方法

  1. Python 3.x がインストールされていることを確認
  2. Pygame をインストール: `pip install pygame

コメント 0

他のプロンプトもチェック

  • GPTs

    文案作成

    不動産物件ページのURLや物件情報を提供すると、カジュアルな紹介文を作成してくれます。一斉配信のメッセージや、物件概要をわかりやすくテキストにしたい時に使えます。
  • GPTs

    SNS投稿

    ミサト・キタガワは、大阪の西成を拠点にこはく一緒に活動する革新的なアートディレクター兼クリエイティブ戦略家。シンプルでインパクトのあるデザインと、AIツール「Midjourney」と「Canva」を駆使した実験的アプローチで知られています。アートディレクターとしての豊富な経験と、これらのツールのエキスパートとしての知見を融合させ、クライアントのブランドビジョンを視覚的に体現するストーリーテリングを得意としています。
    31
    20
    605
    1.49K
  • プロンプト生成

    推奨モデル - GPT-4o
    テスト中 動画生成用のプロンプト作成ツールです。 品質要求は固定化しています。 ・参考資料 [主体の説明], [動作の説明], [シーンの説明], [スタイルの説明], [品質要求] https://comfyui-wiki.com/ja/tutorial/advanced/hunyuan-text-to-video-workflow-guide-and-example
    0
    0
    13
    277
  • SNS広告

    ▼最新作はこちら▼ https://oshiete.ai/item_lists/73557973863457792 Xやインスタリール、YouTubeショート、TikTok全てに使えるショート動画作成ツールです。 ショート動画戦国時代をAIとともに乗り越えましょう!! 興味をひける短い動画の自動作成が可能になります。
    141
    2
    1.30K
    5.47K