JavaScript ランダムではない"じゃんけん"について
- 評価
- クリップ 2
- VIEW 1,904
これまでコンピュータの出す手は、ランダム関数を利用してきました。
これをコンピュータが過去の戦績を参照して、出す手を考える、とすることは可能でしょうか。
たとえば、
・全3回対戦
・1,2回戦はランダムで
・3回戦は、過去2回で人間が出さなかった手に勝てる手を出す
(過去に出さなかったので3回戦で出す可能性が高い..はず)
などです。
JavaScriptに、
sessionStorageやlocalStorageという機能があり
データをローカル環境に保存することまでは調べました。
この機能を使って、上記のような戦績分析型(?)は作れるものでしょうか。
機能の理解で初歩的なところから間違っておりましたらすみません。
よろしくお願い申し上げます。
-
気になる質問をクリップする
クリップした質問は、後からいつでもマイページで確認できます。
またクリップした質問に回答があった際、通知やメールを受け取ることができます。
クリップを取り消します
-
良い質問の評価を上げる
以下のような質問は評価を上げましょう
- 質問内容が明確
- 自分も答えを知りたい
- 質問者以外のユーザにも役立つ
評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。
質問の評価を上げたことを取り消します
-
評価を下げられる数の上限に達しました
評価を下げることができません
- 1日5回まで評価を下げられます
- 1日に1ユーザに対して2回まで評価を下げられます
質問の評価を下げる
teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。
- プログラミングに関係のない質問
- やってほしいことだけを記載した丸投げの質問
- 問題・課題が含まれていない質問
- 意図的に内容が抹消された質問
- 広告と受け取られるような投稿
評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。
質問の評価を下げたことを取り消します
この機能は開放されていません
評価を下げる条件を満たしてません
質問の評価を下げる機能の利用条件
この機能を利用するためには、以下の事項を行う必要があります。
- 質問回答など一定の行動
-
メールアドレスの認証
メールアドレスの認証
-
質問評価に関するヘルプページの閲覧
質問評価に関するヘルプページの閲覧
checkベストアンサー
+2
グー、チョキ、パーを0,1,2で、_historyに格納しています。
次の勝負では一番少ない手に勝つ手をコンピュータが選びます。comChoice()の箇所です。
動作確認する際は、UTF-8で保存してお試しください。
グーチョキパーの履歴を残したのは、3回連続の場合にどうするとか、一定のパターンにマッチしたらどうするとか、そういった戦術を後から組み込むことも考慮してみました。
<!doctype html>
<html lang="ja">
<head>
<meta charset="utf-8">
<title>じゃんけん</title>
<script>
(function(w,d){
var _history = [];
var _scoreCom = 0;
var _scoreMan = 0;
var _scoreDraw = 0;
var _guCyoPar = ['グー','チョキ','パー'];
var _judge = ['引き分け','勝ち','負け'];
w.addEventListener('load',function(){init();},false);
function init() {
for (var i = 0; i < 3; i++) {
(function(i){
d.getElementById('hand' + i).addEventListener('click',function(){pon(i);},false);
})(i);
}
}
function comChoice() {
if (_history.length < 2) {
return Math.floor(Math.random() * 3);
}
var manHistory = countHistory();
var few = (manHistory[0] < manHistory[1]) ? 0 : 1;
few = (Math.min(manHistory[0],manHistory[1]) < manHistory[2]) ? few : 2;
var com = (few == 0) ? 2 : few - 1;
return com;
}
function countHistory() {
var manHistory = [];
manHistory[0] = 0;
manHistory[1] = 0;
manHistory[2] = 0;
for (var i = 0; i < _history.length; i++) {
manHistory[_history[i]]++;
}
return manHistory;
}
function pon(man) {
var com = comChoice();
_history.push(man);
var manHistory = countHistory();
var result = [];
result.push('コンピュータ:' + _guCyoPar[com]);
result.push('自分の手:' + _guCyoPar[man]);
result.push('勝敗:' + _judge[judge(com,man)]);
result.push('コンピュータの勝ち数:' + _scoreCom);
result.push('自分の勝ち数:' + _scoreMan);
result.push('引き分け数:' + _scoreDraw);
result.push('自分のグーの数:' + manHistory[0]);
result.push('自分のチョキの数:' + manHistory[1]);
result.push('自分のパーの数:' + manHistory[2]);
output(result);
}
function output(result) {
d.getElementById('output').innerHTML = '';
for (var i = 0; i < result.length; i++) {
var div = d.createElement('div');
div.innerHTML = result[i];
d.getElementById('output').appendChild(div);
}
}
function judge(com,man) {
if (com == man) {
_scoreDraw++;
return 0;
}
if (com == 0 && man == 2 || com == 1 && man == 0 || com == 2 && man == 1) {
_scoreMan++;
return 1;
} else {
_scoreCom++;
return 2;
}
}
})(window,document);
</script>
</head>
<body>
<h1>じゃんけん</h1>
<button type="button" id="hand0">グー</button>
<button type="button" id="hand1">チョキ</button>
<button type="button" id="hand2">パー</button>
<div id="output"></div>
</body>
</html>
`投稿
-
回答の評価を上げる
以下のような回答は評価を上げましょう
- 正しい回答
- わかりやすい回答
- ためになる回答
評価が高い回答ほどページの上位に表示されます。
-
回答の評価を下げる
下記のような回答は推奨されていません。
- 間違っている回答
- 質問の回答になっていない投稿
- スパムや攻撃的な表現を用いた投稿
評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。
+2
・3回戦は、過去2回で人間が出さなかった手に勝てる手を出すこれを素直にコード化すればよいだけです。
例えば、ユーザーの出した手が一度目はグー、二度目がパーだとして
var selected = [];
selected.push("グー");
selected.push("パー");
などと書けます。
3回目のコンピュータの手は
// それぞれの出した回数を求める
var gu_count = selected.filter(function(e){ return e === "グー" }).length;
var ck_count = selected.filter(function(e){ return e === "チョキ" }).length;
var pa_count = selected.filter(function(e){ return e === "パー" }).length;
// 選ばれた回数が一番少ないものを求める
// name に手を、count に選ばれた回数を持ったオブジェクトの配列を作る
var min = [
{ name: "グー", count: gu_count },
{ name: "チョキ", count: ck_count },
{ name: "パー", count: pa_count }
]
// count の少ない順にソート
.sort(function(a, b){
return a.count - b.count;
})[0]; // 0番目、つまり一番少なかった手のオブジェクトを選択する
// 一番少なかったもの(min.name) が
// 「グー」なら「パー」
// 「チョキ」なら「グー」
// 「パー」なら「チョキ」
// を選択する
var computersNext;
switch (min.name) {
case "グー":
computersNext = "パー"; break;
case "チョキ":
computersNext = "グー"; break;
case "パー":
computersNext = "チョキ"; break;
}
こんな感じですか。上記はあくまで例なので、方法なら他にもいくらでもあるはずです。
たぶん私なら「グーを0」「チョキを1」「パーを2」のように数値化して計算すると思います。
投稿
-
回答の評価を上げる
以下のような回答は評価を上げましょう
- 正しい回答
- わかりやすい回答
- ためになる回答
評価が高い回答ほどページの上位に表示されます。
-
回答の評価を下げる
下記のような回答は推奨されていません。
- 間違っている回答
- 質問の回答になっていない投稿
- スパムや攻撃的な表現を用いた投稿
評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。
+2
ご質問の中の
・3回戦は、過去2回で人間が出さなかった手に勝てる手を出すの実装とは、ちょっと違うことをレスします。
コンピュータの勝率をアップさせることを、このプログラムの
性能向上と考えると、人がじゃんけんをするときに、どういう
クセがあるか?というデータを「戦績分析」するロジックに
いろいろ組み込んでいくことになると思いますが、
こんなまとめサイトがありました。
じゃんけんで勝つ確率を飛躍的にあげるコツ
上記から行けるサイトのひとつ
ジャンケンで勝つ確率を上げる簡単な方法
には、以下のような調査結果が書かれています。
2009年6月20日の日本経済新聞土曜版「日経プラスワン」に、桜美林大学
の芳沢光雄教授による「ジャンケンに関する研究結果」が掲載されました。
芳沢教授が学生725人を集めて、のべ11567回ジャンケンさせたところ、
人間の手の出し方はグー、キョキ、パーそれぞれ1/3とはならなかったそうです。
当時の記事には、以下のように書かれています。
最も多いのはグーで4054枚(35.0%)、次はパーで3849回(33.3%)、
最も少ないのはチョキで、3664回(31.7%)と、かなりのバラツキが出た。
統計的にはグーが出やすく、チョキが出にくい。だから、パーを出せば
勝ちやすいというわけだ。
上記のようなデータもふまえつつ、とはいえ、実際に手を出してやる
じゃんけんと、WEBの画面で選ぶのとはまた違うので、たくさんの対戦
のデータを蓄積して、どういうパターンで出せば人間に勝てるのかの
戦略を、(流行り言葉でいってみれば)機械学習的に向上させていく
ようなロジックを考えるのも面白そうですね。
以上、ちょっとした思いつきでした。
投稿
-
回答の評価を上げる
以下のような回答は評価を上げましょう
- 正しい回答
- わかりやすい回答
- ためになる回答
評価が高い回答ほどページの上位に表示されます。
-
回答の評価を下げる
下記のような回答は推奨されていません。
- 間違っている回答
- 質問の回答になっていない投稿
- スパムや攻撃的な表現を用いた投稿
評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。
0
また、あまり単純な思考だとすぐにはめられかねません。
こういった時に有効なのは、どのように考えるか自体を、過去のデータからコンピュータに学習させる方法です。
パーセプトロンやニューラルネットワークと呼ばれ、対戦相手に応じて学習する能力も授けることができます。
投稿
-
回答の評価を上げる
以下のような回答は評価を上げましょう
- 正しい回答
- わかりやすい回答
- ためになる回答
評価が高い回答ほどページの上位に表示されます。
-
回答の評価を下げる
下記のような回答は推奨されていません。
- 間違っている回答
- 質問の回答になっていない投稿
- スパムや攻撃的な表現を用いた投稿
評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。
2015/05/08 20:14
ありがとうございました。
自分でもうまく動かすことができました。
昨日、今日とリファレンス本を片手に
読み解いていました。
正直申しあげて、
まだ理解しきれていないところもありますが、
引き続き取り組んでいきます。
いずれはグーチョキパーの履歴を使って、
さらに新しい戦術パターンを組み込めるところまで
できるようなりたいです。
漠然とこんなことが出来たら良いなと思って投げかけたところ
わずか数時間で、実際にカタチにできる方がいるのに驚きました。
プログラミングの威力をあらためて実感しています。
夜分にも関わらず
こんなに長いコードを書いて下さり
本当にありがとうございました。