前回、基本的なところをお試ししてみましたが、
もう少しなんかやらせてみたいので、数あてゲームをやらせてみます。
ランダムな数字を、ヒント(High or Low)を基に当てる超楽しいゲームね。。。
実用性は皆無ですが、条件分岐、ループ、演算と、一通りのことを試すのにはいいかなと。
HTMLはこんな感じにしました。
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!doctype html> | |
<html ng-app="app"> | |
<head> | |
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.5/angular.min.js"></script> | |
</head> | |
<body ng-controller="ctrl"> | |
<div> | |
Random=<span id='val'>{{val}}</span><br> | |
Hint:<span id='hint'>{{hint}}</span><br> | |
<input id="expect" type="text" ng-model="expectNum"/><input type="button" ng-click="doExpect()" value="expect!" id="doExpect"/><br> | |
you guessed <span id='times'>{{challenge}}</span> times. | |
</div> | |
</body> | |
<script> | |
var app = angular.module("app", []); | |
app.controller("ctrl", function ($scope, $interval) { | |
var min = 1 ,max = 100 ; | |
$scope.val = Math.floor( Math.random() * (max + 1 - min) ) + min ; | |
$scope.challenge=0; | |
$scope.doExpect=function(){ | |
$scope.hint=""; | |
var num=parseInt($scope.expectNum, 10); | |
if(!isNaN(num)){ | |
$scope.challenge++; | |
if(num==$scope.val){ | |
$scope.hint="correct!"; | |
} else if(num<$scope.val){ | |
$scope.hint="low"; | |
} else { | |
$scope.hint="high"; | |
} | |
} | |
}; | |
}); | |
</script> | |
</html> |
まぁ、素直なコードかと。。。
問題のNightmare部ですが、ループや条件分岐を使うので、Promise/thenではきついと思われます。
ので、Generatorとvoを使用します。
|
|
こちらを激しく参考にさせてもらいました
んで、できたコードがこちら。
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
const Nightmare = require('nightmare'); // import から requreに変更 | |
const cheerio = require('cheerio'); | |
const vo = require('vo'); | |
function gotoHighLow(nm){ | |
return nm | |
.goto('http://localhost:8000/angularsample2.html') | |
.wait('#expect'); | |
} | |
function doExpect(nm, num){ | |
return nm | |
.type('#expect') | |
.type('#expect', num) | |
.click('#doExpect') | |
.evaluate(() => { | |
return document.getElementsByTagName('body')[0].innerHTML; | |
}); | |
} | |
//メインロジック | |
//yield を使のでfunction* | |
function* searchNumber(nm){ | |
let min=1,max=100; //予想範囲 | |
let hint=''; | |
let times=''; | |
while(hint!='correct!'){ ///正解するまでループ | |
let expectedNum=Math.floor((min + max)/2); //番号を予想(予想範囲の真ん中を使う)して | |
let doc=yield doExpect(nm,expectedNum); //お伺いを立てる | |
const $ = cheerio.load(doc); //結果をパース | |
hint = $("#hint").text(); | |
times= $("#times").text(); | |
console.log(min + '<' + expectedNum + '<' + max + ':' + hint); | |
if( hint=='low'){ //結果をもとに、番号予想範囲を狭める | |
min=expectedNum; | |
} else if(hint=='high'){ | |
max=expectedNum; | |
} | |
} | |
return parseInt(times); //成功までに要した試行回数を返す。 | |
} | |
//全体処理 | |
vo(function* () { | |
let nightmare = Nightmare({ show: true }); | |
yield gotoHighLow(nightmare); //ゲームページに移動 | |
let times=yield searchNumber(nightmare); // ゲームします | |
yield nightmare.end(); // 終わります | |
return times; | |
})(function (err, result) { | |
if (err) return console.log(err); | |
console.log(result + "Times"); | |
}); |
Generatorの使い方がミソですな。
今回function/yieldの概念を初めて使いましたが、<a href=“https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Statements/function” rel=“noopener” target=”_blank”>この辺読んでも意味が分かりません。
要はyield使うときは「function*」にしとけってことでしょうか?
今までコールバックとかPromiseとかで独特な記述になってた所が、素直に書けるようになったようです。
印象としてはC#のasync/awaitみたいな感じでしょうかね。
JSエンジンによってかなり実装が違うようです。ブラウザ向けのスクリプトじゃまだ使えなさそう。
実行するとこんな感じ

Nightmare使えそうです。
MoneyForwardが非対応なサービスのデータを、自動で取り込めるようにしたいなぁ。
さしあたってAEONのネットスーパー。対応してくんないかな。