v0を使ってみる

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ファイルに分けてコードの生成が行われました。

〇×ゲームのコードのデモページ

最終的な〇×ゲームのコードは以下になります。
〇×ゲームのコードのデモページ

このエントリーをはてなブックマークに追加

関連記事

コメントを残す

メールアドレスが公開されることはありません。
* が付いている欄は必須項目です

CAPTCHA


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

2024年12月
1234567
891011121314
15161718192021
22232425262728
293031