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ファイルに分けてコードの生成が行われました。
最終的な〇×ゲームのコードは以下になります。
〇×ゲームのコードのデモページ




コメントが承認されるまで時間がかかります。