質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.51%
JavaScript

JavaScriptは、プログラミング言語のひとつです。ネットスケープコミュニケーションズで開発されました。 開発当初はLiveScriptと呼ばれていましたが、業務提携していたサン・マイクロシステムズが開発したJavaが脚光を浴びていたことから、JavaScriptと改名されました。 動きのあるWebページを作ることを目的に開発されたもので、主要なWebブラウザのほとんどに搭載されています。

Q&A

解決済

3回答

4151閲覧

JavaScript 単語カード ランダム表示 表示済みカードは取り除く

may88seiji

総合スコア79

JavaScript

JavaScriptは、プログラミング言語のひとつです。ネットスケープコミュニケーションズで開発されました。 開発当初はLiveScriptと呼ばれていましたが、業務提携していたサン・マイクロシステムズが開発したJavaが脚光を浴びていたことから、JavaScriptと改名されました。 動きのあるWebページを作ることを目的に開発されたもので、主要なWebブラウザのほとんどに搭載されています。

0グッド

0クリップ

投稿2016/05/30 15:51

###前提・実現したいこと
前提:
JavaScriptを使って単語カードを作成しました。
内容はPhotoShopのショートカットでカードをクリックすると機能名⇄ショートカットキー となるように設定しています。

実現したいこと:
ランダムでカードを表示し、一度表示したカードは再度表示されないようにする。

###試したこと
配列に格納したカードは下記コードの乱数にてランダム表示しています。
配列を順番に表示することはfor文にて設定できますが、
「ランダム表示」と「表示済みカードは取り除く」を組み合わせるにはどのようにしたら良いでしょうか?

javascript

1function setCard() { 2 var num = Math.floor(Math.random() * words.length); 3 cardFront.innerHTML = words[num]['key']; 4 cardBack.innerHTML = words[num]['a']; 5 card.removeEventListener('transitionend', setCard); 6 } 7

###該当のソースコード

html

1<!DOCTYPE html> 2<html lang="ja"> 3<head> 4 <meta charset="utf-8"> 5 <title>PhotoShop</title> 6 <style> 7 body { 8 margin: 0; 9 background: #e0e0e0; 10 text-align: center; 11 font-family: Verdana, sans-serif; 12 color: #fff; 13 } 14 #btn { 15 width: 200px; 16 margin: 0 auto; 17 padding: 7px; 18 border-radius: 5px; 19 background: #00aaff; 20 box-shadow: 0 4px 0 #0088cc; 21 cursor: pointer; 22 } 23 #btn:hover { 24 opacity: 0.8; 25 } 26 #card { 27 margin: 60px auto 20px; 28 width: 400px; 29 height: 100px; 30 cursor: pointer; 31 font-size: 38px; 32 line-height: 100px; 33 perspective: 100px; 34 transform-style: preserve-3d; 35 transition: transform .8s; 36 } 37 #card-front, #card-back { 38 display: block; 39 width: 100%; 40 height: 100%; 41 border-radius: 5px; 42 position: absolute; 43 backface-visibility: hidden; 44 } 45 #card-front { 46 background: #fff; 47 color: #333; 48 } 49 #card-back { 50 background: #fff; 51 color: #333; 52 transform: rotateY(180deg); 53 } 54 .open { 55 transform: rotateY(180deg); 56 } 57 </style> 58</head> 59<body> 60 <div id="card"> 61 <div id="card-front"></div> 62 <div id="card-back"></div> 63 </div> 64 <div id="btn">NEXT</div> 65 <script> 66 (function() { 67 'use strict'; 68 69 var words = [ 70 {'key': '境界線調整', 'a': 'alt ctrl R' }, 71 {'key': '選択反転', 'a': 'shift ctrl I' }, 72 {'key': 'カンバスサイズ', 'a': 'ctrl alt C' }, 73 {'key': '塗りつぶし', 'a': 'shift F5' }, 74 75 ]; 76 77 var card = document.getElementById('card'); 78 var cardFront = document.getElementById('card-front'); 79 var cardBack = document.getElementById('card-back'); 80 var btn = document.getElementById('btn'); 81 card.addEventListener('click', function() { 82 flip(); 83 }); 84 btn.addEventListener('click', function() { 85 next(); 86 }); 87 88 function next() { 89 if (card.className === 'open') { 90 card.addEventListener('transitionend', setCard); 91 flip(); 92 } else { 93 setCard(); 94 } 95 } 96 97 function setCard() { 98 var num = Math.floor(Math.random() * words.length); 99 cardFront.innerHTML = words[num]['key']; 100 cardBack.innerHTML = words[num]['a']; 101 card.removeEventListener('transitionend', setCard); 102 } 103 104 setCard(); 105 106 window.addEventListener('keyup', function(e) { 107 if (e.keyCode === 70) { 108 flip(); 109 } else if (e.keyCode === 78) { 110 next(); 111 } 112 }); 113 114 function flip() { 115 card.className = card.className === '' ? 'open' : ''; 116 } 117 118 })(); 119 </script> 120</body> 121</html>

どうぞよろしくお願いいたします。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答3

0

考え方として、バラバラの順番で1つずつ出てくれば目的が達成できると思います。よって、まず候補を全てシャッフルして、あとは先頭から順番に出していけば良いです。
シャッフルの仕方についてはFisher–Yatesなどのアルゴリズムが有名です。探せば資料やサンプルコードはたくさん見つかると思うので、探してみてください。

投稿2016/05/30 16:37

thinca

総合スコア1864

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

may88seiji

2016/05/31 06:59

回答ありがとうございます。 Fisher–Yatesなどのアルゴリズム、大変勉強になりました。 今回いきなり単語カードに応用はすこし難しそうなので、まずはサンプルコードを使って簡単な表示からやってみようと思います。
guest

0

ベストアンサー

Math.random() は偏るけどとりあえずこういう感じかと。

JavaScript

1var words = [ 2 {'key': '境界線調整', 'a': 'alt ctrl R' }, 3 {'key': '選択反転', 'a': 'shift ctrl I' }, 4 {'key': 'カンバスサイズ', 'a': 'ctrl alt C' }, 5 {'key': '塗りつぶし', 'a': 'shift F5' }, 6]; 7var stock = []; // ← 追加(この位置であることにたいした意味は無く、wordsがここに有るのと同じ理由) 8 9/* ( 中略 ) */ 10 11function setCard() { 12 if ( stock.length === 0 ) { stock = words.slice( 0 ); } // stock が空の時 words からコピー 13 var num = Math.floor( Math.random() * stock.length ); // stock.length ← words.length から変わっているので注意 14 var tmp = stock.splice( num, 1 )[ 0 ]; // splice( num, 1 )で stock から1個削除し、それが要素1の配列で返るからそれを選択 15 cardFront.innerHTML = tmp.key; // tmp は「{'key': '境界線調整', 'a': 'alt ctrl R' }」とかが入っているからそれを入れる 16 cardBack.innerHTML = tmp.a; // 〃 17 card.removeEventListener( 'transitionend', setCard ); 18}

【Array.prototype.splice() - JavaScript | MDN】
https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Array/splice

投稿2016/05/30 16:41

kei344

総合スコア69357

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

may88seiji

2016/05/31 02:46

回答ありがとうございます。 無事、「ランダム表示×同じカードに偏らない」ように動かすことが出来ました。 ひとつ追加の質問で恐縮なのですが、上記のコードだと、全て表示する→次の表示のループとなります。表示は一度だけにするにはどのようにすればよいでしょうか? 全て終わったら「Finish!」等表示させたいと思いますが、それは自分でやってみようと思います。 良ければアドバイスお願い致します。
kei344

2016/05/31 02:58

どういう形で終了するのかわからなかったのでエラーが出ないようにループさせていました。 > 全て終わったら「Finish!」等表示させたいと思います setCard() の最後で stock が空か判定して、次 setCard() を呼ぶタイミングで setCard() を呼ばずに「Finish!」等表示させたら良いと思います。
may88seiji

2016/05/31 03:25

何度も有難うございます。 >setCard() の最後で stock が空か判定して、次 setCard() を呼ぶタイミングで setCard() を呼ばずに「Finish!」等表示 一度、if ( stock.length === 0 ) { stock = words.slice( 0 ); }の stock =に「Finish!」表示の変数と入れ替えたところ、最初からFinish!表示となりました。 何度も申し訳ないのですが、ループを終わらせるコードはどのようになりますでしょうか。
may88seiji

2016/05/31 06:56

if ( stock.length === 0 )を差し替えるのではなく、追加で記述することで無事に「Finish!」を表示することができました。ありがとうございました。
kei344

2016/05/31 09:15

解決されたようでよかったです!
may88seiji

2016/05/31 12:56

kei344さん アドバイスありがとうございました! いろいろとコードを組み替えて復習してみます:)
guest

0

もとのカード配列の中身を替えてしまうと、元に戻す際に困ると思うので、

・表示したカードを入れておける配列を別に作成
・表示されたらそちらに追加
・setCard()で次のカードをセットするときに、その配列の中身と比較。合致しなくなるまでループしてカードを作成

・・・というのはどうでしょうか?
リセットするのも容易にできるかと思います。

投稿2016/05/31 00:41

編集2016/05/31 00:42
kaputaros

総合スコア1844

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

may88seiji

2016/05/31 01:44

回答ありがとうございます。 考え方は分かったのですが、実際に ・表示されたらそちらに追加 ・setCard()で次のカードをセットするときに、その配列の中身と比較。合致しなくなるまでループしてカードを作成 をコードで書くとどうなるでしょうか? すいません、思いついた枠組みをカタチにする技術がまだありませんので。。。
kaputaros

2016/05/31 05:51

それを考えるのも勉強ですが・・・。 すいません、今ちょっとそこまでは時間がないので、、、 for文と配列とArrayオブジェクトについて学べば書けると思います。 手がかりを元に考える癖をつけたほうがいいですよ。
may88seiji

2016/05/31 06:33

回答ありがとうございます。 失礼いたしました。手がかりをもとに試行錯誤してみます。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.51%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問