1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

ChatGPTが本当に優しくてわかりやすい先輩過ぎる②

Posted at

下記記事の続きです!
ChatGPTが本当に優しくてわかりやすい先輩過ぎる①

image.png

ありがとうChatGPT!今日も優しいね!

私の課題&ChatGPTの回答

image.png

<div class="contents">
  <p>対象者人数</p>
  <input type="number" id="target" min="1" />
  <button id="draw">抽選</button>
  <button id="reset">リセット</button>
  <div id="left"></div>
  <div class="output" id="subject"></div>
</div>
// 初期名簿
const masterList = [
  "アカウント1","アカウント2","アカウント3",
  "アカウント4","アカウント5","アカウント6"
];

// クリック間で共有する残りプール
let pool = [...masterList];

const targetEl  = document.getElementById("target");
const subjectEl = document.getElementById("subject");
const leftEl    = document.getElementById("left");

function updateLeft() {
  leftEl.textContent = `残り: ${pool.length}人`;
}

// 抽選
document.getElementById("draw").addEventListener("click", () => {
  const targetNumber = Math.max(0, Number(targetEl.value || 0));

  if (pool.length === 0) {
    subjectEl.textContent = "もう残りがいません。リセットしてください。";
    return;
  }

  const drawCount = Math.min(targetNumber, pool.length);
  const winners = [];

  for (let i = 0; i < drawCount; i++) {
    const randIndex = Math.floor(Math.random() * pool.length);
    winners.push(pool[randIndex]);
    pool.splice(randIndex, 1); // 重複防止:プールから除外
  }

  // 表示(複数行)
  subjectEl.innerHTML = winners.join("<br>");

  if (targetNumber > drawCount) {
    subjectEl.innerHTML += `<br><small>※残り人数が不足していたので ${drawCount} 名のみ抽選しました。</small>`;
  }

  updateLeft();
});

// リセット
document.getElementById("reset").addEventListener("click", () => {
  pool = [...masterList];
  subjectEl.textContent = "";
  targetEl.value = "";
  updateLeft();
});

// 初期表示
updateLeft();

とりあえず読んでみて、命名規則をキャメル記法からスネーク記法にしたかったので、その意思を伝えてコードをまずスネーク記法に統一した上でわからないところを質問です。

image.png
image.png

そして爆速回答。これslackならどんなに早い先輩でも30分はかかる気がする…すごいよ…

image.png

なるほどね~いるかいらないか悩むけどとりあえず置いておくか。
100人とか抽選対象ならちょっとカウントダウンみたいで面白いし。

image.png

…ちょっとこれわからないからググります。
mdn web docsを参照。ちなみに前記事からずっとmdn web docsを参照していますが、JavaSctriptを教わった時に公式でここが一番良いと聞いたからです。そこは人の教えを守り続けます。

わかるようでわからないんだよな~…もやもやするので追撃しますね。

配列をコピーすることで何回も同じ配列の中で操作できること?

image.png
image.png

いや、わかんない。ダメだ、これはさすがに動かさないと無理だ。

image.png

色々まとめてくれたので、JSFiddleに移動してガチャガチャ書いていきます。
JSFiddleも人から教わりました。こういう知識があるのは人の手を借りているのと自分の頭なのでAIとの共存を感じています。

貰ったコードでJSFiddleで色々試してみました。
自分で配列作ったりなんやり…。なんとなーく動き方はわかったのですが、これを今後どう使いこなせばいいかは正直イメージが掴めていません。

ただ、私の今の目標はこの「抽選ツール」を作ることなので後でおさらいします。
リアルな会社の人間の先輩に頼ってみます。(ここにそう書いておかないと聞くことを絶対に忘れてしまうので書いておきます。)

image.png

忘れていた仕様を追加

とにかく、配列の中身がランダムに取得されることばかり考えていました。
なので、下記でずっと仮で配列作っていました。

//抽選対象の配列
let subject_array = [  
"アカウント1","アカウント2","アカウント3","アカウント4","アカウント5","アカウント6" 
];

完全に忘れていたのでその旨を教えてあげる。
そして、わからないところを素直に聞く。


ごめん、進める前に忘れていた仕様

抽選対象者をカンマ区切りで下記に入力したい

<p>対象者</p>
    <form name = "targetForm" action="">
        <input type="text" id ="targets"></input>
    </form>    

で、targetsの入力値をtargetslistでカンマ区切りの配列にして、subject_arrayに入れたい

      //入力された対象者を取得する
        const targets = document.getElementById("targets");
        const targetslist = //ここがわからん 

        //入力された対象者人数を取得
        const target = document.getElementById("target");
        const targetnumber = Number(target.value);

        //抽選対象の配列
        let subject_array = [  
        "アカウント1","アカウント2","アカウント3","アカウント4","アカウント5","アカウント6" 
        ];

image.png

えっ、急に一気に来るじゃん…?
ChatGPTが提案してくれたコードです。

<p>対象者</p>
<input type="text" id="targets" placeholder="例) アカウント1, アカウント2, アカウント3">

<p>対象者人数</p>
<input type="number" id="target" min="1">

<button id="draw_button" type="button">抽選</button>
<button id="reset_button" type="button">リセット</button>

<div id="left"></div>
<div class="output" id="subject"></div>
// DOM参照(スネーク記法)
const targets_el   = document.getElementById("targets");
const target_el    = document.getElementById("target");
const subject_el   = document.getElementById("subject");
const left_el      = document.getElementById("left");
const draw_button  = document.getElementById("draw_button");
const reset_button = document.getElementById("reset_button");

// 初期名簿(手入力を優先するので空でOK。必要ならデフォルト値を入れてもいい)
let master_list = [];
let pool = []; // 残りプール

function update_left() {
  left_el.textContent = `残り: ${pool.length}人`;
}

// 入力欄から master_list を作る(カンマ/読点/改行対応・トリム・空除去・重複除去)
function build_master_list_from_input() {
  const raw = targets_el.value || "";
  const tokens = raw
    .split(/[,\n]/)          // カンマ, 改行, 全角読点で分割
    .map(s => s.trim())        // 前後空白トリム
    .filter(Boolean);          // 空要素除去

  // 重複を除きたいなら Set でユニーク化
  // 重複も許容したいなら次の1行を tokens のままにしてね
  master_list = Array.from(new Set(tokens));
  pool = [...master_list];     // 抽選用にコピーしてプール作成
  update_left();
}

draw_button.addEventListener("click", () => {
  // 入力から名簿を最新化(毎回反映したい場合)
  build_master_list_from_input();

  const target_number = Math.max(0, Number(target_el.value || 0));

  if (pool.length === 0) {
    subject_el.textContent = "対象者がいません。";
    return;
  }

  const draw_count = Math.min(target_number, pool.length);
  const winners = [];

  for (let i = 0; i < draw_count; i++) {
    const rand_index = Math.floor(Math.random() * pool.length);
    const winner = pool[rand_index];
    winners.push(winner);
    pool.splice(rand_index, 1); // 重複防止:プールから除外
  }

  subject_el.innerHTML = winners.join("<br>");
  if (target_number > draw_count) {
    subject_el.innerHTML += `<br><small>※残りが不足していたので ${draw_count} 名のみ抽選しました。</small>`;
  }
  update_left();
});

reset_button.addEventListener("click", () => {
  build_master_list_from_input();  // 入力内容でプールを作り直す
  subject_el.textContent = "";
  target_el.value = "";
});

// 初期表示
build_master_list_from_input();

こちらもhtmlはさすがにすぐ理解できましたが、JavaScript側がわからない部分が多いので一生レスバ。
このコードなに?これってこういう意味で書いてる?違う、そうじゃない…!と一生レスバ。

もう書きすぎたのでこちらの記事に載せるのは割愛します。

そしてレスバしまくって自分なりの解釈もコメントに残して書いたコードがこちらです!!

//ボタンクリックで抽選イベント発火
document.getElementById("draw_button").addEventListener('click',
    function(){
 
        //入力された対象者たちと抽選人数を取得する
        const targets_el   = document.getElementById("targets");
        const target_el    = document.getElementById("target");
        //結果と残人数の出力欄取得
        const subject_el = document.getElementById("subject");
        const left_el = document.getElementById("left");
        //操作ボタン取得
        const draw_button  = document.getElementById("draw_button");
        const reset_button = document.getElementById("reset_button");

        //抽選対象の配列作成先の空の箱
        let master_list = [];
        //抽選対象者の残り人数の箱
        let pool = []; 

        //抽選対象者の残り人数を表示する
        function update_left(){
            left_el.textContent = `${pool.length}人`;
        }

        //抽選対象の配列をカンマ区切りで作成する(空白、重複除去あり)
        function build_master_list(){
            const raw = targets_el.value || ""; //null許容ナシ
            const tokens = raw
            //カンマ区切りで入力されているからそれを分割して、空白除去+空要素を除去して配列の中をお掃除
            .split(",").map(s => s.trim()).filter(Boolean);

            //ユニーク化して配列作成
            master_list = Array.from(new Set(tokens));
            //元の抽選対象者リストを保護したまま残人数用をコピー?
            pool = [...master_list];
            update_left();    
        }

        //抽選処理
        //まず対象者リストを削除
        build_master_list();

        //抽選人数の入力値が未入力だった場合は数値の0に変換して負の値(マイナス)は絶対に入れない
        const target_number = Math.max(0, Number(target_el.value || 0));

            if (pool.length === 0) {
                subject_el.textContent = "対象者がいません。";
                return;
            }

        //残り人数も考慮して最終的な当選者の数を作成
        const draw_count = Math.min(target_number, pool.length);
        //当選者を入れる用の空の箱を作る
        let winners = [];

        //ランダムに抽選対象者人数分(draw_count)をループで取得   
        for (let i = 0; i < draw_count; i++){
            //ランダムに残人数から抽選開始
            const rand_index = Math.floor(Math.random() * pool.length);
            //抽選結果を配列にどんどん詰めていく
            const winner = pool[rand_index]; 
            //作った空の箱に抽選結果を配列として追加
            winners.push(winner);
            //抽選対象が重複しないように1度選ばれた人は削除する
            pool.splice(rand_index, 1);
            }

        //取得した対象者表示+残人数も考慮
        subject_el.innerHTML = winners.join("<br>");
        if (target_number > draw_count) {
            subject_el.innerHTML += `<br><small>※残りが不足していたので ${draw_count} 名のみ抽選</small>`;
        }

        update_left();

        //再抽選時にプールを作り直す
        reset_button.addEventListener("click", () => {
            //pool初期化
            build_master_list();  
            //抽選結果と抽選人数欄リセット
            subject_el.textContent = "";
            target_el.value = "";
        });
    });

途中でエラーが出ましたが一度自分で考えました。

  • 変数名を変えまくったので一部変更できていなかった
  • アロー関数を=だけで書いていて=>にしていなかった
  • 必要な関数を呼び出せていなかった
    というあるあるな凡ミス祭りでした。
    上2つは自力で解決して、最後だけChatGPTに頼りました。

image.png

もう問いかけも脳死です。

出来ている画面がこちら。

image.png

基礎のロジックはできたのであまりにクソダサくてやる気が失せるので次はCSSをやっていきますね。
その後、もっと改善箇所を探していきます。

…と、その前にChatGPTが本当に優しくてわかりやすい先輩過ぎる①の最後に書いた、Geminiコードレビューを試してみます!!!

🔥 ChatGPT VS Gemini 🔥

次回はこちら!絶対読んでくれよな!!!


オブジェクティブグループではXの投稿も平日毎日行っています!
IT 関連の小ネタや便利技から、日常のアニメ・ゲーム布教なども幅広く投稿してるので、
ご興味のある方は是非フォロー・いいねをお願いします。

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?