JavaScript 単語カード ランダム表示 表示済みカードは取り除く
解決済
回答 3
投稿
- 評価
- クリップ 0
- VIEW 1,759
前提・実現したいこと
前提:
JavaScriptを使って単語カードを作成しました。
内容はPhotoShopのショートカットでカードをクリックすると機能名⇄ショートカットキー となるように設定しています。
実現したいこと:
ランダムでカードを表示し、一度表示したカードは再度表示されないようにする。
試したこと
配列に格納したカードは下記コードの乱数にてランダム表示しています。
配列を順番に表示することはfor文にて設定できますが、
「ランダム表示」と「表示済みカードは取り除く」を組み合わせるにはどのようにしたら良いでしょうか?
function setCard() {
var num = Math.floor(Math.random() * words.length);
cardFront.innerHTML = words[num]['key'];
cardBack.innerHTML = words[num]['a'];
card.removeEventListener('transitionend', setCard);
}
該当のソースコード
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="utf-8">
<title>PhotoShop</title>
<style>
body {
margin: 0;
background: #e0e0e0;
text-align: center;
font-family: Verdana, sans-serif;
color: #fff;
}
#btn {
width: 200px;
margin: 0 auto;
padding: 7px;
border-radius: 5px;
background: #00aaff;
box-shadow: 0 4px 0 #0088cc;
cursor: pointer;
}
#btn:hover {
opacity: 0.8;
}
#card {
margin: 60px auto 20px;
width: 400px;
height: 100px;
cursor: pointer;
font-size: 38px;
line-height: 100px;
perspective: 100px;
transform-style: preserve-3d;
transition: transform .8s;
}
#card-front, #card-back {
display: block;
width: 100%;
height: 100%;
border-radius: 5px;
position: absolute;
backface-visibility: hidden;
}
#card-front {
background: #fff;
color: #333;
}
#card-back {
background: #fff;
color: #333;
transform: rotateY(180deg);
}
.open {
transform: rotateY(180deg);
}
</style>
</head>
<body>
<div id="card">
<div id="card-front"></div>
<div id="card-back"></div>
</div>
<div id="btn">NEXT</div>
<script>
(function() {
'use strict';
var words = [
{'key': '境界線調整', 'a': 'alt ctrl R' },
{'key': '選択反転', 'a': 'shift ctrl I' },
{'key': 'カンバスサイズ', 'a': 'ctrl alt C' },
{'key': '塗りつぶし', 'a': 'shift F5' },
];
var card = document.getElementById('card');
var cardFront = document.getElementById('card-front');
var cardBack = document.getElementById('card-back');
var btn = document.getElementById('btn');
card.addEventListener('click', function() {
flip();
});
btn.addEventListener('click', function() {
next();
});
function next() {
if (card.className === 'open') {
card.addEventListener('transitionend', setCard);
flip();
} else {
setCard();
}
}
function setCard() {
var num = Math.floor(Math.random() * words.length);
cardFront.innerHTML = words[num]['key'];
cardBack.innerHTML = words[num]['a'];
card.removeEventListener('transitionend', setCard);
}
setCard();
window.addEventListener('keyup', function(e) {
if (e.keyCode === 70) {
flip();
} else if (e.keyCode === 78) {
next();
}
});
function flip() {
card.className = card.className === '' ? 'open' : '';
}
})();
</script>
</body>
</html>
どうぞよろしくお願いいたします。
-
気になる質問をクリップする
クリップした質問は、後からいつでもマイページで確認できます。
またクリップした質問に回答があった際、通知やメールを受け取ることができます。
クリップを取り消します
-
良い質問の評価を上げる
以下のような質問は評価を上げましょう
- 質問内容が明確
- 自分も答えを知りたい
- 質問者以外のユーザにも役立つ
評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。
質問の評価を上げたことを取り消します
-
評価を下げられる数の上限に達しました
評価を下げることができません
- 1日5回まで評価を下げられます
- 1日に1ユーザに対して2回まで評価を下げられます
質問の評価を下げる
teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。
- プログラミングに関係のない質問
- やってほしいことだけを記載した丸投げの質問
- 問題・課題が含まれていない質問
- 意図的に内容が抹消された質問
- 広告と受け取られるような投稿
評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。
質問の評価を下げたことを取り消します
この機能は開放されていません
評価を下げる条件を満たしてません
質問の評価を下げる機能の利用条件
この機能を利用するためには、以下の事項を行う必要があります。
- 質問回答など一定の行動
-
メールアドレスの認証
メールアドレスの認証
-
質問評価に関するヘルプページの閲覧
質問評価に関するヘルプページの閲覧
+2
考え方として、バラバラの順番で1つずつ出てくれば目的が達成できると思います。よって、まず候補を全てシャッフルして、あとは先頭から順番に出していけば良いです。
シャッフルの仕方についてはFisher–Yatesなどのアルゴリズムが有名です。探せば資料やサンプルコードはたくさん見つかると思うので、探してみてください。
投稿
-
回答の評価を上げる
以下のような回答は評価を上げましょう
- 正しい回答
- わかりやすい回答
- ためになる回答
評価が高い回答ほどページの上位に表示されます。
-
回答の評価を下げる
下記のような回答は推奨されていません。
- 間違っている回答
- 質問の回答になっていない投稿
- スパムや攻撃的な表現を用いた投稿
評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。
checkベストアンサー
+1
Math.random()
は偏るけどとりあえずこういう感じかと。
var words = [
{'key': '境界線調整', 'a': 'alt ctrl R' },
{'key': '選択反転', 'a': 'shift ctrl I' },
{'key': 'カンバスサイズ', 'a': 'ctrl alt C' },
{'key': '塗りつぶし', 'a': 'shift F5' },
];
var stock = []; // ← 追加(この位置であることにたいした意味は無く、wordsがここに有るのと同じ理由)
/* ( 中略 ) */
function setCard() {
if ( stock.length === 0 ) { stock = words.slice( 0 ); } // stock が空の時 words からコピー
var num = Math.floor( Math.random() * stock.length ); // stock.length ← words.length から変わっているので注意
var tmp = stock.splice( num, 1 )[ 0 ]; // splice( num, 1 )で stock から1個削除し、それが要素1の配列で返るからそれを選択
cardFront.innerHTML = tmp.key; // tmp は「{'key': '境界線調整', 'a': 'alt ctrl R' }」とかが入っているからそれを入れる
cardBack.innerHTML = tmp.a; // 〃
card.removeEventListener( 'transitionend', setCard );
}
【Array.prototype.splice() - JavaScript | MDN】
https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Array/splice
投稿
-
回答の評価を上げる
以下のような回答は評価を上げましょう
- 正しい回答
- わかりやすい回答
- ためになる回答
評価が高い回答ほどページの上位に表示されます。
-
回答の評価を下げる
下記のような回答は推奨されていません。
- 間違っている回答
- 質問の回答になっていない投稿
- スパムや攻撃的な表現を用いた投稿
評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。
0
もとのカード配列の中身を替えてしまうと、元に戻す際に困ると思うので、
・表示したカードを入れておける配列を別に作成
・表示されたらそちらに追加
・setCard()で次のカードをセットするときに、その配列の中身と比較。合致しなくなるまでループしてカードを作成
・・・というのはどうでしょうか?
リセットするのも容易にできるかと思います。
投稿
-
回答の評価を上げる
以下のような回答は評価を上げましょう
- 正しい回答
- わかりやすい回答
- ためになる回答
評価が高い回答ほどページの上位に表示されます。
-
回答の評価を下げる
下記のような回答は推奨されていません。
- 間違っている回答
- 質問の回答になっていない投稿
- スパムや攻撃的な表現を用いた投稿
評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。
15分調べてもわからないことは、teratailで質問しよう!
- ただいまの回答率 89.98%
- 質問をまとめることで、思考を整理して素早く解決
- テンプレート機能で、簡単に質問をまとめられる
2016/05/31 15:59
Fisher–Yatesなどのアルゴリズム、大変勉強になりました。
今回いきなり単語カードに応用はすこし難しそうなので、まずはサンプルコードを使って簡単な表示からやってみようと思います。