Vercelから提供されている、UI自動生成ツールの「v0」を簡単に使ってみます。
v0について
v0はVercelが提供しているUI自動生成ツールで、入力したテキスト(プロンプト)を元にUIコードを生成します。
生成されるUIはReactベースですが、プロンプトでVanillaJSなどの指示をすれば別の形でも生成してくれるようです。
使用方法
v0のサイトにアクセスして、ログインを行います。
Vercelのアカウントがある場合はそのアカウントでログインできますが、持っていない場合はアカウント作成が必要になります。
ログイン後、実際にプロンプトを入力して生成を試してみます。
以下の内容で試してみます。
ブラウザで遊ぶことのできる、〇×ゲームを作成してもらえますか。
NPCと対戦できるようにしてください。
1分ほど待つと、回答とコードの生成が完了しました。
生成されたUIコードは、その場でプレビューすることができます。
プレビューで確認してみて問題なさそうだったので、追加で指示を行ってみます。
以下の内容を入力しました。
NPCの強さのレベルを、1~3の3段階で選択できるようにしてもらえますか。
レベル1は現在と同じくランダムでの選択、レベル3は常に最善手を選択、レベル2は最善手とランダムを半々くらいで選択するようにしてください。
しばらく待つと、機能の追加が行われました。
現在のコードを確認すると、以下のようなReactベースのコードになっています。
'use client' import { useState, useEffect } from 'react' import { Button } from "@/components/ui/button" import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card" import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select" type Player = 'X' | 'O' | null type Difficulty = 1 | 2 | 3 export default function TicTacToe() { const [board, setBoard] = useState<Player[]>(Array(9).fill(null)) const [isPlayerTurn, setIsPlayerTurn] = useState(true) const [winner, setWinner] = useState<Player | 'Draw' | null>(null) const [difficulty, setDifficulty] = useState<Difficulty>(1) const checkWinner = (squares: Player[]): Player | 'Draw' | null => { const lines = [ [0, 1, 2], [3, 4, 5], [6, 7, 8], // Rows [0, 3, 6], [1, 4, 7], [2, 5, 8], // Columns [0, 4, 8], [2, 4, 6] // Diagonals ] for (let i = 0; i < lines.length; i++) { const [a, b, c] = lines[i] if (squares[a] && squares[a] === squares[b] && squares[a] === squares[c]) { return squares[a] } } return squares.every(square => square !== null) ? 'Draw' : null } const handleClick = (index: number) => { if (board[index] || winner || !isPlayerTurn) return const newBoard = [...board] newBoard[index] = 'X' setBoard(newBoard) setIsPlayerTurn(false) const gameWinner = checkWinner(newBoard) if (gameWinner) setWinner(gameWinner) } const minimax = (board: Player[], depth: number, isMaximizing: boolean): number => { const result = checkWinner(board) if (result === 'X') return -10 + depth if (result === 'O') return 10 - depth if (result === 'Draw') return 0 if (isMaximizing) { let bestScore = -Infinity for (let i = 0; i < 9; i++) { if (board[i] === null) { board[i] = 'O' const score = minimax(board, depth + 1, false) board[i] = null bestScore = Math.max(score, bestScore) } } return bestScore } else { let bestScore = Infinity for (let i = 0; i < 9; i++) { if (board[i] === null) { board[i] = 'X' const score = minimax(board, depth + 1, true) board[i] = null bestScore = Math.min(score, bestScore) } } return bestScore } } const getBestMove = (board: Player[]): number => { let bestScore = -Infinity let bestMove = -1 for (let i = 0; i < 9; i++) { if (board[i] === null) { board[i] = 'O' const score = minimax(board, 0, false) board[i] = null if (score > bestScore) { bestScore = score bestMove = i } } } return bestMove } const getRandomMove = (board: Player[]): number => { const emptySquares = board.reduce((acc: number[], curr, index) => { if (curr === null) acc.push(index) return acc }, []) return emptySquares[Math.floor(Math.random() * emptySquares.length)] } const npcMove = () => { let moveIndex: number switch (difficulty) { case 1: moveIndex = getRandomMove(board) break case 2: moveIndex = Math.random() < 0.5 ? getBestMove(board) : getRandomMove(board) break case 3: moveIndex = getBestMove(board) break default: moveIndex = getRandomMove(board) } const newBoard = [...board] newBoard[moveIndex] = 'O' setBoard(newBoard) setIsPlayerTurn(true) const gameWinner = checkWinner(newBoard) if (gameWinner) setWinner(gameWinner) } useEffect(() => { if (!isPlayerTurn && !winner) { const timer = setTimeout(npcMove, 500) return () => clearTimeout(timer) } }, [isPlayerTurn, winner]) const resetGame = () => { setBoard(Array(9).fill(null)) setIsPlayerTurn(true) setWinner(null) } return ( <Card className="w-full max-w-md mx-auto"> <CardHeader> <CardTitle className="text-2xl font-bold text-center">〇×ゲーム</CardTitle> </CardHeader> <CardContent> <div className="mb-4"> <Select value={difficulty.toString()} onValueChange={(value) => setDifficulty(parseInt(value) as Difficulty)} > <SelectTrigger className="w-full"> <SelectValue placeholder="難易度を選択" /> </SelectTrigger> <SelectContent> <SelectItem value="1">レベル1 (ランダム)</SelectItem> <SelectItem value="2">レベル2 (中級)</SelectItem> <SelectItem value="3">レベル3 (最善手)</SelectItem> </SelectContent> </Select> </div> <div className="grid grid-cols-3 gap-2 mb-4"> {board.map((square, index) => ( <Button key={index} onClick={() => handleClick(index)} variant="outline" className="h-20 text-4xl font-bold" disabled={!!square || !!winner || !isPlayerTurn} > {square} </Button> ))} </div> <div className="text-center mb-4"> {winner ? ( <p className="text-xl font-bold"> {winner === 'Draw' ? '引き分けです!' : `${winner}の勝ちです!`} </p> ) : ( <p className="text-xl"> {isPlayerTurn ? 'あなたの番です (X)' : 'NPCの番です (O)'} </p> )} </div> <Button onClick={resetGame} className="w-full"> ゲームをリセット </Button> </CardContent> </Card> ) }
以下のように入力して、コードを別の形にできるかを試してみます。
コードをHTMLとCSSとJavaScript(VanillaJS)での実装に変更することはできますか。
しばらく待つと、HTMLとCSSとJavaScript(VanillaJS)の3ファイルに分けてコードの生成が行われました。
最終的な〇×ゲームのコードは以下になります。
〇×ゲームのコードのデモページ
コメントが承認されるまで時間がかかります。