🎮

Amazon Q CLI でVibe Codingしてゲームを作ってみた

に公開

この記事はAmazon Q CLI でゲームを作ろう Tシャツキャンペーン のチャレンジ記事です。

開発環境

PC(M4 Macbook Pro)
Python3(Brew install)
PyGame(pip install)
Amazon Q CLI(User Guideを参考)

ゲーム

「作ってみた」なのでシンプルなトランプゲームにしました。
内容としては画面中央に裏向きで並ぶ2枚のトランプを選び、めくって数字勝負をするものです。
高い数字のカードを引き当てればスコアが伸びて「Next」ボタンで次の挑戦へ。外すとゲームオーバー。
シンプルですがはまりやすいゲームです。

プロンプト

Amazon Q CLIへ入力するプロンプトは下記となります。

プロンプト
You are an expert Python game developer.

TASK  
Write one runnable Python-3 script with Pygame that implements this “Higher Card” mini-game.

1. ✦ Window  
   • 800 × 600 px, green-felt background.

2. ✦ Cards  
   • Two rectangles (120 × 160) side-by-side, centered.  
   • At the start of each round they are face-down (solid blue, white border, centered “?”).  
   • When flipped face-up they show **only the rank text** (“2”–“10”, “J”, “Q”, “K”, “A”) in blue.  
   • No suit symbols or extra graphics.

3. ✦ Gameplay flow  
   a. Wait for a left-click on either card.  
   b. Immediately flip **both** cards face-up.  
   c. If the chosen card’s value is higher → **do NOT auto-advance**.  
      • Display a centered “Next” button directly **below the bottom edge of the cards**.  
      • Clicking that button starts a fresh face-down round (score + 1).  
   d. If the chosen card’s value is lower or a tie → enter **Game Over state** (see §4).

4. ✦ Game Over state  
   • Leave the revealed cards on screen.  
   • Centered under the cards: large “Game Over!” text.  
   • Under that, a “Restart” button.  
   • Clicking “Restart” resets the score to 0 and begins a new face-down round.  
   • Window close still exits; no keyboard shortcuts are required.

5. ✦ UI elements  
   • Top-left persistent label: “Correct Guesses: <n>”.  
   • Center-top instruction “Click on the higher card!” appears only while waiting for the first click of each round.

6. ✦ Code quality  
   • Organize with a `Game` class and helper methods.  
   • Use constants for colors, sizes, etc.  
   • Clear inline comments; follow PEP-8 spacing.  
   • Depend only on Pygame and the Python standard library.

OUTPUT  
Return **only** the full Python script—no explanations, no extra text.  

プロンプトの日本語訳は以下のとおりです。

日本語訳
あなたは Python ゲーム開発のエキスパートです。

【タスク】  
Pygame を使い、次の仕様の「ハイヤーカード」ミニゲームを 1 本の Python-3 スクリプトとして実装してください。

1. ✦ ウィンドウ  
   • 800×600 px、背景は緑のフェルト。

2. ✦ カード  
   • 120×160 の矩形 2 枚を中央に横並び。  
   • ラウンド開始時は裏向き(青塗り+白枠+中央に “?”)。  
   • 表向きでは **ランク文字のみ**(“2”〜“10”/J/Q/K/A)を青色で表示。  
   • 絵柄やスートは一切描かない。

3. ✦ ゲーム進行  
   a. プレイヤーがカードを 1 枚クリック。  
   b. ただちに両カードを表向きに反転。  
   c. 選んだカードが高ければ **自動で次ラウンドへ進まず**、  
      • **カードの下端直下**に中央揃えで「Next」ボタンを表示。  
      • ボタンがクリックされたらスコアを +1 し、新ラウンド(裏向き)へ。  
   d. 低い(または同値)場合は **Game Over 状態**へ(§4)。

4. ✦ Game Over 状態  
   • 表になったカードをそのまま表示。  
   • カードの直下に大きく中央で “Game Over!” と表示。  
   • さらにその下に「Restart」ボタンを表示。  
   • Restart をクリックするとスコアを 0 にリセットし、新しいラウンドを開始。  
   • ウィンドウを閉じれば終了。キーボード操作は不要。

5. ✦ UI  
   • 左上に「Correct Guesses: <n>」を常時表示。  
   • ラウンド待機中のみ、画面上部中央に “Click on the higher card!” を表示。

6. ✦ コード品質  
   • `Game` クラスと補助メソッドで構造化。  
   • 色・サイズ等は定数化。  
   • 主要部にコメント、PEP-8 準拠。  
   • 依存は Pygame と標準ライブラリのみ。

【出力形式】  
説明文は一切書かず、完成した Python スクリプトだけを返してください。  

Amazon Q CLI でVibe Coding

Macのターミナルを起動後q chatでAmazon Q CLIを立ち上げます。

Amazon Q CLI
% q chat

    ⢠⣶⣶⣦⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⣤⣶⣿⣿⣿⣶⣦⡀⠀
 ⠀⠀⠀⣾⡿⢻⣿⡆⠀⠀⠀⢀⣄⡄⢀⣠⣤⣤⡀⢀⣠⣤⣤⡀⠀⠀⢀⣠⣤⣤⣤⣄⠀⠀⢀⣤⣤⣤⣤⣤⣤⡀⠀⠀⣀⣤⣤⣤⣀⠀⠀⠀⢠⣤⡀⣀⣤⣤⣄⡀⠀⠀⠀⠀⠀⠀⢠⣿⣿⠋⠀⠀⠀⠙⣿⣿⡆
 ⠀⠀⣼⣿⠇⠀⣿⣿⡄⠀⠀⢸⣿⣿⠛⠉⠻⣿⣿⠛⠉⠛⣿⣿⠀⠀⠘⠛⠉⠉⠻⣿⣧⠀⠈⠛⠛⠛⣻⣿⡿⠀⢀⣾⣿⠛⠉⠻⣿⣷⡀⠀⢸⣿⡟⠛⠉⢻⣿⣷⠀⠀⠀⠀⠀⠀⣼⣿⡏⠀⠀⠀⠀⠀⢸⣿⣿
 ⠀⢰⣿⣿⣤⣤⣼⣿⣷⠀⠀⢸⣿⣿⠀⠀⠀⣿⣿⠀⠀⠀⣿⣿⠀⠀⢀⣴⣶⣶⣶⣿⣿⠀⠀⠀⣠⣾⡿⠋⠀⠀⢸⣿⣿⠀⠀⠀⣿⣿⡇⠀⢸⣿⡇⠀⠀⢸⣿⣿⠀⠀⠀⠀⠀⠀⢹⣿⣇⠀⠀⠀⠀⠀⢸⣿⡿
 ⢀⣿⣿⠋⠉⠉⠉⢻⣿⣇⠀⢸⣿⣿⠀⠀⠀⣿⣿⠀⠀⠀⣿⣿⠀⠀⣿⣿⡀⠀⣠⣿⣿⠀⢀⣴⣿⣋⣀⣀⣀⡀⠘⣿⣿⣄⣀⣠⣿⣿⠃⠀⢸⣿⡇⠀⠀⢸⣿⣿⠀⠀⠀⠀⠀⠀⠈⢿⣿⣦⣀⣀⣀⣴⣿⡿⠃
 ⠚⠛⠋⠀⠀⠀⠀⠘⠛⠛⠀⠘⠛⠛⠀⠀⠀⠛⠛⠀⠀⠀⠛⠛⠀⠀⠙⠻⠿⠟⠋⠛⠛⠀⠘⠛⠛⠛⠛⠛⠛⠃⠀⠈⠛⠿⠿⠿⠛⠁⠀⠀⠘⠛⠃⠀⠀⠘⠛⠛⠀⠀⠀⠀⠀⠀⠀⠀⠙⠛⠿⢿⣿⣿⣋⠀⠀
 ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⠛⠿⢿⡧

╭─────────────────────────────── Did you know? ────────────────────────────────╮
│                                                                              │
│      You can use /editor to edit your prompt with a vim-like experience      │
│                                                                              │
╰──────────────────────────────────────────────────────────────────────────────╯

/help all commands  •  ctrl + j new lines  •  ctrl + s fuzzy search
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
🤖 You are chatting with claude-4-sonnet

今回はClaude 4 Sonnetで開発をするためモデルを明示的に指定しました。

> /model

✔ Select a model for this chat session · claude-4-sonnet (active)

 Using claude-4-sonnet

プロンプトを貼り付けます

Amazon Q CLI
>You are an expert Python game developer.

TASK  
Write one runnable Python-3 script with Pygame that implements this “Higher Card” mini-game.

1. ✦ Window  
   • 800 × 600 px, green-felt background.

2. ✦ Cards  
   • Two rectangles (120 × 160) side-by-side, centered.  
   • At the start of each round they are face-down (solid blue, white border, centered “?”).  
   • When flipped face-up they show **only the rank text** (“2”–“10”, “J”, “Q”, “K”, “A”) in blue.  
   • No suit symbols or extra graphics.

3. ✦ Gameplay flow  
   a. Wait for a left-click on either card.  
   b. Immediately flip **both** cards face-up.  
   c. If the chosen card’s value is higher → **do NOT auto-advance**.  
      • Display a centered “Next” button directly **below the bottom edge of the cards**.  
      • Clicking that button starts a fresh face-down round (score + 1).  
   d. If the chosen card’s value is lower or a tie → enter **Game Over state** (see §4).

4. ✦ Game Over state  
   • Leave the revealed cards on screen.  
   • Centered under the cards: large “Game Over!” text.  
   • Under that, a “Restart” button.  
   • Clicking “Restart” resets the score to 0 and begins a new face-down round.  
   • Window close still exits; no keyboard shortcuts are required.

5. ✦ UI elements  
   • Top-left persistent label: “Correct Guesses: <n>”.  
   • Center-top instruction “Click on the higher card!” appears only while waiting for the first click of each round.

6. ✦ Code quality  
   • Organize with a `Game` class and helper methods.  
   • Use constants for colors, sizes, etc.  
   • Clear inline comments; follow PEP-8 spacing.  
   • Depend only on Pygame and the Python standard library.

OUTPUT  
Return **only** the full Python script—no explanations, no extra text.  

プロンプトを入力するとAmazon Q CLIがソースコードを生成してくれました

生成されたコード
import pygame
import random
import sys

# Initialize Pygame
pygame.init()

# Constants
WINDOW_WIDTH = 800
WINDOW_HEIGHT = 600
CARD_WIDTH = 120
CARD_HEIGHT = 160
CARD_SPACING = 40

# Colors
GREEN_FELT = (34, 139, 34)
WHITE = (255, 255, 255)
BLUE = (0, 0, 255)
BLACK = (0, 0, 0)
GRAY = (128, 128, 128)

# Card values and their numeric equivalents
CARD_RANKS = ['2', '3', '4', '5', '6', '7', '8', '9', '10', 'J', 'Q', 'K', 'A']
CARD_VALUES = {rank: i + 2 for i, rank in enumerate(CARD_RANKS)}

class Game:
    def __init__(self):
        self.screen = pygame.display.set_mode((WINDOW_WIDTH, WINDOW_HEIGHT))
        pygame.display.set_caption("Higher Card Game")
        self.clock = pygame.time.Clock()
        self.font = pygame.font.Font(None, 36)
        self.large_font = pygame.font.Font(None, 48)
        
        # Game state
        self.score = 0
        self.game_state = "waiting"  # "waiting", "revealed", "game_over"
        self.left_card = None
        self.right_card = None
        self.chosen_card = None
        
        # UI elements
        self.next_button_rect = None
        self.restart_button_rect = None
        
        self.new_round()
    
    def new_round(self):
        """Start a new round with face-down cards"""
        self.left_card = random.choice(CARD_RANKS)
        self.right_card = random.choice(CARD_RANKS)
        self.game_state = "waiting"
        self.chosen_card = None
    
    def get_card_rects(self):
        """Calculate card positions"""
        total_width = 2 * CARD_WIDTH + CARD_SPACING
        start_x = (WINDOW_WIDTH - total_width) // 2
        card_y = (WINDOW_HEIGHT - CARD_HEIGHT) // 2
        
        left_rect = pygame.Rect(start_x, card_y, CARD_WIDTH, CARD_HEIGHT)
        right_rect = pygame.Rect(start_x + CARD_WIDTH + CARD_SPACING, card_y, CARD_WIDTH, CARD_HEIGHT)
        
        return left_rect, right_rect
    
    def draw_card(self, rect, rank=None, face_up=False):
        """Draw a single card"""
        # Draw card background
        pygame.draw.rect(self.screen, BLUE, rect)
        pygame.draw.rect(self.screen, WHITE, rect, 3)
        
        if face_up and rank:
            # Draw rank text
            text = self.font.render(rank, True, BLUE)
            text_rect = text.get_rect(center=rect.center)
            # Fill background with white first
            pygame.draw.rect(self.screen, WHITE, rect.inflate(-6, -6))
            pygame.draw.rect(self.screen, WHITE, rect, 3)
            self.screen.blit(text, text_rect)
        else:
            # Draw question mark for face-down card
            text = self.font.render("?", True, WHITE)
            text_rect = text.get_rect(center=rect.center)
            self.screen.blit(text, text_rect)
    
    def draw_button(self, text, x, y, width=120, height=40):
        """Draw a button and return its rect"""
        button_rect = pygame.Rect(x - width//2, y, width, height)
        pygame.draw.rect(self.screen, GRAY, button_rect)
        pygame.draw.rect(self.screen, BLACK, button_rect, 2)
        
        button_text = self.font.render(text, True, BLACK)
        text_rect = button_text.get_rect(center=button_rect.center)
        self.screen.blit(button_text, text_rect)
        
        return button_rect
    
    def handle_card_click(self, pos):
        """Handle clicking on a card"""
        if self.game_state != "waiting":
            return
        
        left_rect, right_rect = self.get_card_rects()
        
        if left_rect.collidepoint(pos):
            self.chosen_card = "left"
        elif right_rect.collidepoint(pos):
            self.chosen_card = "right"
        else:
            return
        
        # Reveal both cards
        self.game_state = "revealed"
        
        # Check if chosen card is higher
        chosen_value = CARD_VALUES[self.left_card if self.chosen_card == "left" else self.right_card]
        other_value = CARD_VALUES[self.right_card if self.chosen_card == "left" else self.left_card]
        
        if chosen_value > other_value:
            # Correct guess - show Next button
            pass
        else:
            # Wrong guess or tie - game over
            self.game_state = "game_over"
    
    def handle_next_click(self):
        """Handle clicking the Next button"""
        self.score += 1
        self.new_round()
    
    def handle_restart_click(self):
        """Handle clicking the Restart button"""
        self.score = 0
        self.new_round()
    
    def draw(self):
        """Draw the entire game"""
        self.screen.fill(GREEN_FELT)
        
        # Draw score
        score_text = self.font.render(f"Correct Guesses: {self.score}", True, WHITE)
        self.screen.blit(score_text, (10, 10))
        
        # Draw instruction text (only when waiting)
        if self.game_state == "waiting":
            instruction_text = self.font.render("Click on the higher card!", True, WHITE)
            instruction_rect = instruction_text.get_rect(centerx=WINDOW_WIDTH//2, y=50)
            self.screen.blit(instruction_text, instruction_rect)
        
        # Draw cards
        left_rect, right_rect = self.get_card_rects()
        
        face_up = self.game_state in ["revealed", "game_over"]
        self.draw_card(left_rect, self.left_card, face_up)
        self.draw_card(right_rect, self.right_card, face_up)
        
        # Draw buttons based on game state
        if self.game_state == "revealed":
            chosen_value = CARD_VALUES[self.left_card if self.chosen_card == "left" else self.right_card]
            other_value = CARD_VALUES[self.right_card if self.chosen_card == "left" else self.left_card]
            
            if chosen_value > other_value:
                # Show Next button
                button_y = max(left_rect.bottom, right_rect.bottom) + 20
                self.next_button_rect = self.draw_button("Next", WINDOW_WIDTH//2, button_y)
        
        elif self.game_state == "game_over":
            # Show Game Over text and Restart button
            game_over_text = self.large_font.render("Game Over!", True, WHITE)
            game_over_rect = game_over_text.get_rect(centerx=WINDOW_WIDTH//2, 
                                                   y=max(left_rect.bottom, right_rect.bottom) + 20)
            self.screen.blit(game_over_text, game_over_rect)
            
            button_y = game_over_rect.bottom + 20
            self.restart_button_rect = self.draw_button("Restart", WINDOW_WIDTH//2, button_y)
    
    def run(self):
        """Main game loop"""
        running = True
        
        while running:
            for event in pygame.event.get():
                if event.type == pygame.QUIT:
                    running = False
                
                elif event.type == pygame.MOUSEBUTTONDOWN:
                    if event.button == 1:  # Left click
                        pos = event.pos
                        
                        if self.game_state == "waiting":
                            self.handle_card_click(pos)
                        
                        elif self.game_state == "revealed":
                            if self.next_button_rect and self.next_button_rect.collidepoint(pos):
                                self.handle_next_click()
                        
                        elif self.game_state == "game_over":
                            if self.restart_button_rect and self.restart_button_rect.collidepoint(pos):
                                self.handle_restart_click()
            
            self.draw()
            pygame.display.flip()
            self.clock.tick(60)
        
        pygame.quit()
        sys.exit()

if __name__ == "__main__":
    game = Game()
    game.run()

Amazon Q CLIで生成したコードをhigher_card_game.pyとして保存後、Amazon Q CLIを終了

Amazon Q CLI
/quit

動作確認

pythonコマンドでhigher_card_game.pyを実行します。

python
python higher_card_game.py

実行後、別画面でゲームが表示されました。

スタート画面

どちらのカードを選択して数字が大きいほうを選択すると【NEXT】ボタンが表示されます。

当たった時の画面

数字が小さいほうを選択するとゲームオーバーとなります。
プロンプト通りのゲームができていることを確認しました。

外れた時の画面

まとめ

Amazon Q CLIでVibe Codingをしたことがなかったので大変勉強になりました。

Discussion