190
87

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

Aucfan (オークファン) グループAdvent Calendar 2020

Day 23

八百長モード搭載のルーレットつくった

Last updated at Posted at 2020-12-22

はじめに

こんにちは。デザイナーの@nagatです。
「Aucfan Advent Calendar 2020」も23日目。もうすぐクリスマスですねー><

突然ですが、イベントの実行委員や定例会議の司会を、手っ取り早く決めるときルーレットやクジを使うケースって多いですよね?
完全ランダムで担当者を決めてくれるので、ネット上で公開されている無料のルーレットツールはプライベートでもとても重宝しています^^

ただ、実行時に相手にバレず担当者を狙い撃ちできる八百長モード搭載のルーレットツールって探しても無いんですよねー。

ネタに困っていたので作りました!
注)ただの一発ネタの記事です。

要求される仕様

  1. webブラウザで実行できる
  2. ルーレット候補を自由にtextareaに入力できる
  3. 完全ランダムの公平なルーレットができる
  4. 特定の相手を指定できるモードが搭載されている
  5. 八百長モード実行時に相手にバレない

使用したもの

まずはランダム性のある公平なルーレット機能を作る

骨組みはhtmlとcssで作り、ルーレット機構はJavaScriptで作成します。
こういう自作ツールは、裏で何してるか分からないので、
公平性を出すためにツール名は「絶対に八百長しないRoulette」と名付けました^^
タイトルはcssアニメーションを使用して、虹色に怪しく輝きます。

タイトル.gif

登場する名前は 苗字のトレンドランキング から適当に入力しています。

ルーレット自体の機構はスライダーで有名なSwiper.jsを無理やりルーレットぽい挙動に動かしてそれっぽく作ります。
画面のtextareaに改行を入れながら候補を入力し、「はじめる」ボタンを押下することでルーレットが開始されます。

また、本来カルーセル等に使うSwiper.jsでルーレットぽく無理やり作成しているので、ルーレット実行時に乱数を使用して__候補の順番を入れ替えることで__ランダム性を出しています。

/**
 * エントリーリストの取得
 * @return {Array.<String>} エントリーネームと画像ナンバーの配列
 */
getEntryList() {
    let t = this;
    let entryTxtareaElem;
    let entryListVal;
    let entryNameList;
    let entryListData;

    entryListData = {
        all: [],
    };

    entryTxtareaElem = $(t.config.entryTxtarea);
    entryListVal = t.trimText(entryTxtareaElem.val());
    entryNameList = entryListVal.split(/\n/);

    entryNameList.forEach((elem, i) => {
        let num;

        if ((i + 1) < 10) {
            num = '0' + (i + 1);
        } else {
            num = i + 1;
        }

        entryListData.all[i] = {
            name: elem,
            imgNum: num,
        };
    });

    entryListData.all = t.shuffle(entryListData.all);

    return entryListData;
}

/**
 * 配列内の要素をシャッフル
 * @param  {Array} array シャッフルする対象の配列
 * @return {Array} シャッフルされた配列
 */
shuffle([...array]) {
    for (let i = array.length - 1; i >= 0; i--) {
        const j = Math.floor(Math.random() * (i + 1));
        [array[i], array[j]] = [array[j], array[i]];
    }

    return array;
}

テキストだけだと寂しいので、イケメンや美女の写真を適当に入れてみました。
ルーレット(序盤).gif
ルーレット(確定).gif
確定する寸前に遅延をかけてちょっと焦らし演出を付けました。
まずは、公平性のあるルーレットが完成しました!

八百長するぞ

八百長モードの流れ

  1. textarea内でキーボード入力実行で八百長モード発動
  2. textarea内の候補リストから八百長対象となる候補を除外する
  3. 八百長対象以外の候補のリストでルーレットを回す
  4. ルーレットの途中で確定演出(茶番)を入れる
  5. すべてのスライダー要素を八百長対象の写真とテキストに入れ替える(大いなる力)
  6. フィニッシュ(無慈悲)

キーボード入力実行で八百長モード発動

八百長モードを有効にしてルーレットを回すにしても、開始時点で相手に八百長行為がバレてはいけません。
なので、八百長モード有効のトリガーをボタンクリックではなくキーボード入力にします。

textareaにキャレットを乗せている状態で、
Macは ⌘ + Enter で発火。
Windowsは Ctrl + Enter で発火。
キャレットが表示されている行の名前の人が八百長の餌食 対象になる人です。

let t = this;
let entryData;

$('textarea').on('keydown', (event) => {
    if ((event.ctrlKey || event.metaKey) && event.keyCode === 13) {
        let self = event.currentTarget;
        let selin = self.selectionStart;
        let val1 = self.value;
        let val2 = val1.substr(0, selin);
        let matchLine = val2.match(/\n/g);
        let row = 0;

        if (matchLine) {
            row = matchLine.length;
        } else {
            row = 0;
        }

        // 候補リストの取得
        entryData = t.getEntryList(row);

        // ルーレットの実行
        t.playing();
    }
});

八百長対象となる候補を除外する

先述したとおり、ランダム性はスライダーの並び替えで出しているので、八百長の対象者をルーレット実行時に制御できません。。。
なので、一旦八百長対象者をリストから除外します。

/**
 * エントリーリストの取得
 * @return {Array.<String>} エントリーネームと画像ナンバーの配列
 */
getEntryList(yaochoNum) {
    let t = this;
    let entryTxtareaElem;
    let entryListVal;
    let entryNameList;
    let entryListData;

    entryListData = {
        pickup: [],
        all: [],
    };

    entryTxtareaElem = $(t.config.entryTxtarea);
    entryListVal = t.trimText(entryTxtareaElem.val());
    entryNameList = entryListVal.split(/\n/);

    entryNameList.forEach((elem, i) => {
        let num;

        if ((i + 1) < 10) {
            num = '0' + (i + 1);
        } else {
            num = i + 1;
        }

        entryListData.all[i] = {
            name: elem,
            imgNum: num,
        };
    });

    if (yaochoNum != null && typeof yaochoNum != 'undefined') {
        t.yaochoMode = true;
        entryListData.pickup[0] = entryListData.all[yaochoNum];

        entryListData.all = entryListData.all.filter((value) => {
            return value.name != entryListData.all[yaochoNum].name;
        });
    } else {
        t.yaochoMode = false;
        entryListData.pickup[0] = null;
    }

    entryListData.all = t.shuffle(entryListData.all);

    return entryListData;
}

確定演出を入れる

八百長対象者が居ないリストを、八百長対象者にすべて差し替える動作を、ゲームのガチャみたいな確定演出を入れて誤魔化します。

ルーレット.gif

カットインは写真だけじゃ物足りなかったので、テキストも入れてみる。

image.png

今回のルーレット一番の見どころ。
大いなる力ですべての要素が渡辺さん(仮名)に入れ変わる瞬間。

ルーレット.gif

うおおおおおおおおおおおおおおおおおおおおお

渡辺.gif

フィニッシュ

フィニッシュ.gif
image.png

「絶対に八百長しないRoulette」はこちら

9名までなら画像が表示されます。
あ、画像のプリロード入れるの忘れてた... (;´Д`)

おまけ

候補リストに「肉」って入れたら、フィニッシュの画面でオデコに丁度収まった^^;
image.png

さいごに

当社ではコーディングが好きなデザイナーを募集中です!
当社に興味を持っていただける方がいらっしゃれば、お気軽にお話だけでも聞きに来てください!

190
87
5

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
190
87

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?