📇

開発未経験の大学生がCarsor使ってみた!

2024/07/22に公開

自己紹介

こんにちは!
株式会社dotDの秋山です。
大学の講義の一環でdotDでインターンをしています。

今回は全くの開発初心者である私が、AIエディタ"Cursor"を使用してみたので、軽くご紹介してみようと思います。

AIエディタ Cursor

CursorはAI搭載のテキストエディターです。
開発元はAnysphereというアメリカの企業で、OpenAIからの出資を受けているそうです。気になりますね。

主な特徴は以下の通りです。
・VSCodeをフォーク:プログラミング専用ツール「VSCode(Visual Studio Code)」をベースに、新たに機能や改善を加えて開発された。拡張機能もそのまま引き継ぐ。
・ChatGPTを搭載:AIツール「ChatGPT」を搭載し、プログラミング関連のあらゆる業務を自動化できる。
・豊富な機能:コードの自動生成だけでなく、自動デバッグやチャットへの質問など、豊富な機能が備わっている。

導入方法

導入は非常の簡単です。
Cursorのホームページからインストールするだけです。

あとは画面の指示通り進んでいくだけで完了です。
VSCodeの拡張機能もそのまま引き継いでくれます。

主な機能

Cursorの機能をいくつかご紹介します。

1.AI edit

command + Kで、コードを編集および作成できる機能です。
都度都度、指定のコードの部分をコピペしてchatGPTに質問する手間が省かれるので非常に便利な機能です。

2.AI chat

command + Lまたは、Toggle AI Paneで画面右側にchat画面が展開されます。この画面ではchatGPTと同じようにchatで質疑応答が可能です。この機能が Cursor を使用するいちばんの理由だと思います。

3.Docs

ドキュメントの読み込みも可能です。
@シンボルの選択画面から Docs → Add new docで以下のようにドキュメントのURLを記載することでAIがドキュメントを読み込みます。そして、AIがドキュメント内容を理解したうえで回答することができます。

4.Codebase Answers

AIがプロジェクト全体のコードを読み込んで解凍してくれる機能です。
chat内で @ + Codebase、または、Command + Enterを押すことでプロジェクト全体のファイルを読み込んで回答をしてくれます。
chatGPTではプロジェクト全体をプロンプトすることは不可能に近いので、この機能のためだけでも使う価値時は大いにあると思います。

月額利用料

月々の利用金額は以下の通りです。

プラン ベーシック プロ ビジネス
金額 無料 $20 $40(1人あたり)
GPT-3.5の使用回数 200回 無制限 無制限
GPT-4(slow)の使用回数 50回 無制限 無制限
GPT-4(fast)の使用回数 使用不可 500回 500回

Cursorでは、FastGPT-4という機能があり、OpenAIのサーバー内で優先的に、処理を実行できる機能があります。Pro以上のプランでのみ使用できます。また、Proプラン以下だと、OpenAI社のサーバーにプロンプトや出力結果などのデータが保管されてしますが、Businessプランに入ると、OpenAI社のサーバーにデータが保管されなくなるため、さらにセキュアになります。
そのほかにも、Basicプランで登録した上で、自前のOpenAIのAPIキーやAzure OpenAI ServiceのAPIキーを登録して、利用することも可能です。

簡単なゲーム作ってみた

今までHTMLとCSSを使って全く動きの無いホームページしか
作ったことない私がチャットを駆使して簡単なスロットゲームを作ってみました。「スロット作って」と雑なプロンプトを出したり、細かく指定してみたりと色々試しました。

機能要件

1 ゲームプレイ
ユーザーは「スピン」ボタンを押してスロットを回すことができる
スロットは3つの数字(0〜5)で構成される
1回のスピンに10ポイントを消費する
3つの数字が全て同じ場合、500ポイントを獲得する
2 ポイント管理
初期ポイントは1000ポイント
現在のポイント数を画面上に表示する
ポイントが10未満の場合、スピンできない
3 挑戦回数
ゲーム開始からの挑戦回数を記録し、表示する
4 リセット機能
「リセット」ボタンを押すと、ポイントと挑戦回数が初期状態に戻る
5 履歴表示
「履歴表示」ボタンを押すと、直近15回の結果を表示する
履歴には各回の結果(「パーフェクト!」または「もう一度挑戦してください。」)のみを表示する

生成したプログラム

何度かAIとのチャットを繰り返し、最終的に以下のプログラムを作成することができました。

過程1

プロンプト:スロットを作って

過程2

プロンプト:スロットを作る。 数字を三つ揃えて当てたらセリフが出る。ボタンを押してスタート・ストップ。数字は一斉に回転し、左から順にボタンに合わせて止まる。ポイント制で初期値1000、コスト10。揃ったら500追加。挑戦回数を表示させる。

過程3

プロンプト:スロットの装飾を豪華にして。(意図的に雑に指示)

過程4

プロンプト:回数とポイントのリセット機能と結果の履歴機能を追加して。
見た目は追加されたが、昨日は追加されず。

過程5

プロンプト:リセットボタンを押すとポイントと挑戦回数が初期状態に戻るようにして。

過程6

プロンプト:履歴表示ボタンを押すと直近15回までに履歴を表示。

HTML

<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>スロットゲーム</title>
    <link rel="stylesheet" href="style.css">
</head>
<body>
    <div id="points">ポイント: 1000 | 挑戦回数: 0</div>
    <div id="result"></div>
    <div class="slot-machine">
        <div id="slot1" class="slot">0</div>
        <div id="slot2" class="slot">0</div>
        <div id="slot3" class="slot">0</div>
    </div>
    <button id="spinButton">スピン</button>
    <button id="resetButton">リセット</button>
    <button id="historyButton">履歴表示</button>
    <div id="history"></div>
    <script src="script.js"></script>
</body>
</html>

CSS

body {
    dpx 2px 4px rgba(0, 0, 0, 0.5);
    display: flex;
    flex-direction: column;
    justify-content: center;
    align-items: center;
    height: 100vh;
    margin: 0;
    font-family: 'Arial', sans-serif;
    background: linear-gradient(135deg, #ffcc33, #ff6699);
    color: #fff;
}

.slot-machine {
    display: flex;
    justify-content: center;
    margin-bottom: 20px;
    padding: 20px;
    border: 3px solid #fff;
    border-radius: 15px;
    background: linear-gradient(135deg, #ff9966, #ff5e62);
    box-shadow: 0 8px 16px rgba(0, 0, 0, 0.2);
}

.slot {
    font-size: 2em;
    margin: 0 10px;
    width: 60px;
    text-align: center;
    border: 2px solid #fff;
    border-radius: 10px;
    padding: 15px;
    background: linear-gradient(135deg, #ffffff, #e0e0e0);
    box-shadow: inset 0 4px 8px rgba(0, 0, 0, 0.2);
    color: #333;
}

#spinButton, #resetButton, #historyButton {
    margin-top: 20px;
    padding: 15px 30px;
    font-size: 1.2em;
    border: none;
    border-radius: 10px;
    background: linear-gradient(135deg, #00c6ff, #0072ff);
    color: #fff;
    cursor: pointer;
    box-shadow: 0 8px 16px rgba(0, 0, 0, 0.2);
    transition: background 0.3s ease;
}

#spinButton:hover, #resetButton:hover, #historyButton:hover {
    background: linear-gradient(135deg, #0072ff, #00c6ff);
}



#result {
    text-align: center;
    margin-bottom: 20px;
    font-size: 1.5em;
    color: #fff;
    text-shadow: 2px 2px 4px rgba(0, 0, 0, 0.5);
}

#points {
    text-align: center;
    margin-bottom: 20px;
    font-size: 1.5em;
    color: #fff;
    text-shadow: 2
}

JavaScript

let points = 1000;
let attempts = 0;
let spinning = [false, false, false];
let intervals = [];
let history = [];

function updatePoints() {
    document.getElementById('points').textContent = `ポイント: ${points} | 挑戦回数: ${attempts}`;
}

function startSpinning(slotId) {
    return setInterval(() => {
        document.getElementById(slotId).textContent = Math.floor(Math.random() * 6);
    }, 100);
}

function updateHistory(slot1, slot2, slot3, result) {
    history.push({ result });
    if (history.length > 15) {
        history.shift();
    }
}

function displayHistory() {
    const historyDiv = document.getElementById('history');
    historyDiv.innerHTML = '';
    history.forEach((entry, index) => {
        const entryDiv = document.createElement('div');
        entryDiv.textContent = `#${index + 1}: ${entry.result}`;
        historyDiv.appendChild(entryDiv);
    });
}

document.getElementById('spinButton').addEventListener('click', function() {
    if (points < 10) {
        document.getElementById('result').textContent = 'ポイントが足りません。';
        return;
    }

    if (!spinning[0] && !spinning[1] && !spinning[2]) {
        points -= 10;
        attempts += 1;
        updatePoints();
        spinning = [true, true, true];
        document.getElementById('result').textContent = '';
        intervals[0] = startSpinning('slot1');
        intervals[1] = startSpinning('slot2');
        intervals[2] = startSpinning('slot3');
    } else {
        for (let i = 0; i < 3; i++) {
            if (spinning[i]) {
                clearInterval(intervals[i]);
                spinning[i] = false;
                break;
            }
        }

        if (!spinning[0] && !spinning[1] && !spinning[2]) {
            const slot1 = parseInt(document.getElementById('slot1').textContent);
            const slot2 = parseInt(document.getElementById('slot2').textContent);
            const slot3 = parseInt(document.getElementById('slot3').textContent);

            let result;
            if (slot1 === slot2 && slot2 === slot3) {
                points += 500;
                result = 'パーフェクト!';
            } else {
                result = 'もう一度挑戦してください。';
            }
            document.getElementById('result').textContent = result;
            updateHistory(slot1, slot2, slot3, result);
            updatePoints();
        }
    }
});

document.getElementById('resetButton').addEventListener('click', function() {
    points = 1000;
    attempts = 0;
    updatePoints();
    document.getElementById('result').textContent = '';
    document.getElementById('slot1').textContent = '0';
    document.getElementById('slot2').textContent = '0';
    document.getElementById('slot3').textContent = '0';
});

document.getElementById('historyButton').addEventListener('click', displayHistory);

updatePoints();

感想

経験がほとんどない私が使っただけですので、どれだけ実務で使えるかわかりませんが、
良かった点を挙げると、
・CursorはVSCodeの使用感にAI機能が追加されたようなもの。VSCodeから移行が簡単でお試し感覚で使用できる。
・ファイルを横断して回答してくれるのはかなり便利。
一方で、少し不便なところも見つけました。
・AIとのチャット履歴を復元することができるが、一部見返すことができないところがあった。
・既存のコードを踏まえて生成してくれるが、かなりの頻度で内容がとんでいるところがあるため、
 生成したものと既存のコードを比較する必要がある。AI任せはNG。

また僕自身の反省点なのですが、チャットが便利なためしつこく質問をしてしまい、あっという間にレスポンスの上限になってしまいました。解決が難しそうだなと思ったらCursorに頼り切らず公式ドキュメントなどに切り替える柔軟性を持ちたいですね。

このCursorは作業を効率化してくれるとても便利なツールだと思います。

これを有効活用できれば、知識や高い実装力が必要な作業に集中できること間違いなしです!

dotDTechBlog

Discussion