パッケージファイル読み込み完成

六帖webアプリ
kickzone/TrainNavi2 · GitHub
一通り区切りのいいところまでできたので、開発をしばらく停止する。路線データは時々追加を続けるけれど、他にやりたいことができた。
私は非正規の社員なので、ボーナスも退職金も出ない。国民年金も厚生年金も払っていないので、老後の蓄えは0円だ。30代に入ったばかりの自分は、あと35年程度で、働けなくなる日が来る。日本の平均寿命の上昇から考えて、さらに2〜30年ほど生きることになるだろう。
日本の高齢化の進行から考えて、70〜75まで働けるようになるかもしれない。その場合は、40:20, 45:15まで老後の資金が必要な比率は減る。しかし、60を超えればおそらく働ける機会や賃金は大幅減するだろう。したがって、35年以内に、何らかの方法で資産形成をする必要がある。1月1万円積み立てたとしても35年で400万円程度にしかならない。これは数年生きたところで尽きる。最低でも3000万、できれば5000万欲しい。
というわけで、投資を考えている。FXは死ぬので、株取引だろう。1月1万円の増資で35年で3000万円を目指すには、年利何%が必要か。簡単なプログラムを作ってみた。

<script>
//手持資金
var current = 10;
//年利
var rate = 0.09;
//月ごとの増資額
var delta = 1;
document.write("年利" + (rate*100) + "% " );
rate = (Math.pow(1+rate, 1/12)) - 1;
document.write("月利" + (rate*100) + "%<BR>" );
var nothingtodo = current;
var effort = current;
for(var year=1; year<=35; year++){
for(var month = 1; month <=12; month++){
nothingtodo += delta;
effort += delta;
effort *= (1 + rate);
document.write(year + "年目" + month + "月");
document.write(" 何もしない:" + nothingtodo + "万");
document.write(" 複利:" + effort + "万<BR>");
}
}
</script>

このプログラムをそのまま実行すると、35年後に2917万になる。つまり年利9%を平均してたたき出す必要がある。色々と調べてみたところ、まず無理だ。せいぜい年利5%くらいが妥当なところか。5%だと、1168万になる。何もしないと430万。これよりはずっとマシか。
今日の銘柄成績発表
このサイトが機械的に算出した結果だけを使った場合、2年9か月で41.7%の利益を得ることが期待できたらしい。年利に直すと11%ちょいくらい。これは希望の持てるソースだ。元手100万*2159銘柄を仮定してるので、無茶と言えば無茶だけど。
というわけで、機械的に売買銘柄を指定できる方法さえ開発できれば、年利9%も夢ではない。私には博打は向いてないだろうから、徹底的に機械的な方がいい。
材料は、株価データダウンロードサイト ここに8年分の株価データがある。未来を知ることができないという前提で、過去のデータだけに基づいて予測するアルゴリズムを開発し、元手、増資額、条件、手数料などを入力して、自動で売買させる。最も利益率の高かったアルゴリズムを採用し、試しに1年間ほどバーチャルで投資する。これでうまくいけば、現物に切り替えてもいいだろう。
必要な技術と知識は、DBの作成、統計学、分析アルゴリズムの作成、自動投資シミュレーションの作成、が最低限必須で、あとは本をたくさん読まなきゃいかんだろう。慣れてきたので、またPHP+JavaScriptで開発しよう。PCの発展のおかげで、MySQLを容量を気にせずバンバン使えるのがおいしい。
ただしロクなアルゴリズムができなければ、あきらめるしかないね。


パッケージファイル読み込み途中まで

六帖webアプリ
kickzone/TrainNavi2 · GitHub
路線図の読み込みまで対応した。あとは列車のデータを読み込めれば、一通り終了だ。これができたら、次は動作を軽くするための工夫を入れないといかん。路線図を作りこむと、直線が多くなるので当然ながら動作が重くなる。現在位置を調べる関数ものろくなる。
zipファイルの読み込みには、JSZip を使用した。モダンブラウザにのみ実装されているFileAPIと併用すると非常に楽だった。ただし、FileAPIはajaxを使用していると思われ、別スレッド処理になるので注意。以下使用例。

var onLoading = true;
function ReadZip(){
var packageFile = "package.zip";
//zipファイルをfilereaderで開く
var reader = new FileReader();
reader.onload = function(e) {
var zip = new JSZip(e.target.result);
//zipファイル内のfile1.txtをテキストファイルとして開く
var textStatic = zip.file("file1.txt").asText();
var aLines = textStatic.split("\n");
for(var i=0; i<aLines.length; i++)
{
//読み込んだテキストを使った処理 省略
}
//ロード終了
onLoading = false;
}
//ロード開始
onLoading = true;
reader.readAsArrayBuffer(packageFile);
}
ReadZip();
//ロード終了まで待つ
var wait = setInterval(function() {
if (!onLoading) {
//ロード終了、インターバルを削除
clearInterval(wait);
//以下、zipファイルロード後の処理
}
}, 100);

エディット機能

六帖webアプリ
kickzone/TrainNavi2 · GitHub
線路のエディット機能を追加。実質、googleマップに合わせて線路の形を整えるための機能となった。1日で300行ちょいのコードを書いた。
上手くいかなかったことはたくさんある。まず、canvasにmousemoveのイベントをかましていると、要素のmousemoveのイベントが動作しない。駅オブジェクトをドラッグして位置を変更したいのに、クリックイベントは発生するものの、mousemoveが動作しないため何も起こらない。おそらくcanvasに吸い取られてしまっているのだろう。この場合、canvasのイベントは消し去っておく必要がある。

//stationというオブジェクトがcanvas上にあるとする
function OnStationMouseDown(evt){
var canvas = $("canvas")[0];
//canvasのイベントを捨てる
canvas.removeEventListener('mousemove', OnCanvasMouseMove, false);
canvas.removeEventListener('mouseup', OnCanvasMouseUp, false);
//新たにイベントを登録する
canvas.addEventListener('mousemove', OnStationMouseMove, false);
canvas.addEventListener('mouseup', OnStationMouseUp, false);
}
function OnStationMouseMove(evt){
//mousemoveイベントの処理
}
function OnStationMouseUp(evt){
//mousemoveイベントの処理
//イベントハンドラを元に戻す
canvas.removeEventListener('mousemove', OnStationMouseMove, false);
canvas.removeEventListener('mouseup', OnStationMouseUp, false);
canvas.addEventListener('mousemove', OnCanvasMouseMove, false);
canvas.addEventListener('mouseup', OnCanvasMouseUp, false);
}

さらに、JavaScript→PHPにPOSTを使って値を受け渡しするとき、配列の個数が1000を超えると、1000を超えたものから削除されていく、という恐ろしいPHPの仕様にぶつかった。
参考
この仕様を知らなかったので、大きなデータを保存したら一部が消えてしまってびっくらこいた。1時間くらいの作業が吹っ飛んだので非常にまいった。配列の受け渡しはやめて、半角スペースなどのセパレータをつけてPHPでpreg_splitを使って分解するように変更した。


Googleマップ2

六帖webアプリ
kickzone/TrainNavi2 · GitHub
連携できるようになった。まず一番面食らったのは、自作の路線図の縮尺が全然合っていなかったということ。いくら倍率を揃えても地図と重ならないので、仕方なく、googleマップに合わせて路線を描画するようにした。
さらに面倒だったのは、ローカルの座標とgoogleマップ上の緯度・経度の変換方法がややこしいということ。googleマップには緯度・経度を座標に変換できるAPIが存在するが、得られる座標は、なんと全世界単位の座標だ。これをローカルの地図に合わせて変換する必要がある。次のようにする。

//緯度経度からローカル座標に変換
function fromLatLngToPoint(latLng, map) {
//表示中の地図の世界座標をゲット
var topRight = map.getProjection().fromLatLngToPoint(map.getBounds().getNorthEast());
var bottomLeft = map.getProjection().fromLatLngToPoint(map.getBounds().getSouthWest());
//倍率
var scale = Math.pow(2, map.getZoom());
//与えられたlatLngの世界座標をゲット
var worldPoint = map.getProjection().fromLatLngToPoint(latLng);
//地図の世界座標と画面上の世界座標の差を、倍率でかけて出来上がり
return new google.maps.Point((worldPoint.x - bottomLeft.x) * scale, (worldPoint.y - topRight.y) * scale);
}
//ローカル座標から緯度経度に変換
function fromPointToLatLng(point, map) {
//表示中の地図の世界座標をゲット
var topRight = map.getProjection().fromLatLngToPoint(map.getBounds().getNorthEast());
var bottomLeft = map.getProjection().fromLatLngToPoint(map.getBounds().getSouthWest());
//倍率
var scale = Math.pow(2, map.getZoom());
//地図の左上の座標にローカル座標を倍率を考慮して足し、世界座標を得る
var worldPoint = new google.maps.Point(bottomLeft.x + point.x / scale, topRight.y + point.y / scale);
//緯度経度に変換
var latlng = map.getProjection().fromPointToLatLng(worldPoint);
return latlng;
}

Googleマップと重ねてみると、今の路線図は概略にすぎず山の中を走ったり建物の中を突っ切ったり散々な状態であることが分かった。途中経路を表すhalfwayを作成し、綺麗な路線を作ることが急務となった。


GoogleMap

GoogleMapAPIのキーをゲットして実装中。なんと、今まで作っていた路線図がY方向にかなり潰れていたことが発覚した。
係数を調整し、路線を重ねることには成功したが、連動してマップを移動する処理が難しすぎて難航中。スクロール処理もほぼ作り直しか!?


年末年始

六帖webアプリ
ここ1週間で路線を15追加した。東京の地下鉄はすべて網羅したので、次はJRだ。しかしJRは来年3月に上野東京ラインが開業するため、DBを作ってもすぐに改訂しなければならないだろう。
ソフト面にそろそろ手を入れよう。昨日は日曜日なのに仕事の依頼があり殆ど作業できなかったので、次は仕事が薄くなる年末年始に大きな改良をしたい。主に次の3点をできるところまで作業する。
・パッケージファイルに対応、ローカルで動作するようにする
・Googleマップとの連携
・GPSに対応
これと、モバイル端末で動作する変更を加えれば、ひとまずそれなりに目標を達成したこととなる。


路線追加中

六帖webアプリ
kickzone/TrainNavi2 · GitHub
ここ2週間は大きな変更はせず、バグ取りと路線の追加のみ。東京の地下鉄は、浅草線を除きすべて追加した。
朝ラッシュのシミュレーションをしてみると、東京の電車がいかに多すぎるかが分かる。なお、現時点、中央線以外のJRの路線(山手線、京浜東北線など)は追加していないので、まだ増える。
全体図。地下鉄密集ゾーンのカオスっぷりはともかく、左側の中央快速線から大量の東京行が見えるのをはじめとして、東上線・田園都市線・東横線・京王線あたりからとてつもない密度の列車が迫っているのが分かる。右側は東西線・総武線が詰まっているが京葉線・京成線・総武快速線・常磐線・TXなどが未実装なので、まだまだ本気ではない。

行先表示をなくして若干見やすくしたバージョン。小田急・伊勢崎線は複々線なので分かりにくいが、相当詰まっている。地下鉄部分は文字をなくしてもあまり変わらない。

都心部拡大図。日本一と言われる丸ノ内線の密度が目立つ。どの駅にも列車がいる。拡大しても新宿・渋谷付近は意味不明。もっと表示を綺麗にする工夫が必要だ。


列車をゲットする論理変更、列車をクリックするとその列車の情報を表示、自動画面スクロール機能追加

六帖webアプリ
kickzone/TrainNavi2 · GitHub
一昨日の懸案、列車走行時刻が0時をまたぐ場合を考慮したSQL文を作成した。

starttime <= ToTime and FromTime <= endtime

これをstarttimeが日付をまたぐ場合(starttime>endtime)、またがない場合(starttime<=endtime)に分割し、

(starttime <= endtime AND starttime <= ToTime AND FromTime <= endtime)
OR (starttime > endtime AND ((starttime <= ToTime AND FromTime <= "24:00") OR ("0:00" <= ToTime AND FromTime <= endtime)))

まずこう変更した。しかし FromTime <= "24:00" と "0:00" <= ToTime には意味がない。自明だから。なので、最終的には

(starttime <= endtime AND starttime <= ToTime AND FromTime <= endtime)
OR (starttime > endtime AND (starttime <= ToTime OR FromTime <= endtime))

となった。意外にもすっきりしている。これで新幹線や長距離特急列車も問題なくなった。やった。来週はFileAPIの実装を始めよう。

現在時速を表示する機能を付けたものの、かなりインチキな速度になっている。というのも、加減速にかかる時間・列車停車時間を全列車共通にしているから。井の頭線や小田急の各停なんて、停車までに30秒もかからないはずだけど60秒かけるような設定になっていたり、駅で1分も停車しないはずだけど時刻表通りに実装していたり、これらのせいで最高速度が各停で150km/hになってしまったりする。もう少しそれっぽくできないかなぁ。


明日から真冬か

とうとう最高気温も10度まで下がるようです。足が冷たい。猫の小屋からは猫蒸気が小屋の底と床に染み渡るようになりました。通称猫汁
六帖webアプリ
総武緩行線・東西線・東葉高速線
京王井の頭線 <京王線系統全部終了
大雄山線
まで追加終了した。大雄山線は電車を見ると和むのに、ダイヤは完全なパターンで平日も土日も全く同じで面白味が全くない。特急かいじ、あずさ、ホームライナー千葉は総武快速線を実装するまで保留。次は田園都市線-半蔵門線-東武伊勢崎線系列だが、田園都市線は大井町線に乗り入れていることが判明したので、大井町線も一緒に実装しないといけない。複々線区間の割り振りが難しい。
伊勢崎線は新栃木だの会津田島だの尋常じゃないくらい長大な系列であることも判明したので、とりあえず押上経由で乗り入れする分だけ実装する。
とまらない。
1点、以前からの課題がある。列車を読み込む際のSELECT文が不完全なことだ。ある時刻の範囲に存在する列車の一覧を得たい。
いまは

$query = "SELECT distinct trainname FROM tnroute WHERE linename='$lines[$i]'
AND starttime>=\"".$_POST['FromTime']."\" and starttime<=\"".$_POST['ToTime']."\" 
  AND service=".$_POST['Service'];

と、starttime(列車の発車時間)しか見ていない。これだと、from〜toが例えば1分間だった場合に、10分間無停車の電車が引っかからない。新幹線なら1時間以上止まらない列車だってある。
なんとか、starttime〜endtime(列車の到着時刻)とfrom〜toが重なる列車の一覧を持ってきたい。
2つの期間が重なり合うかどうかを判定する。 – こせきの技術日記
これを参考にすれば、X <= B && A <= Y すなわち starttime <= ToTime and FromTime <= endtime でもよさそうだが、starttime, endtimeが日付をまたぐことがある。starttimeが23時55分、endtimeが0時5分などの場合だ。これをどのように処理すればいいのか。この課題が解決できれば、どれだけfromとtoの間を狭くしても電車を正しく読み込める。


デバッグ、駅名表示機能追加、中央快速線系統DB追加

六帖webアプリ
kickzone/TrainNavi2 · GitHub
やっと旧TrainNaviに追いついた。土日休日ダイヤも対応したから、すでに2倍の情報量か。
今後の予定

総武緩行線・東西線・東葉高速線
京王井の頭線 <京王線系統全部終了
大雄山線
田園都市線・半蔵門線・伊勢崎線・日比谷線・こどもの国線
東横線・みなとみらい線・副都心線・有楽町線・西武池袋線・東武東上線
南北線・埼玉高速鉄道線・都営三田線・東急目黒線
銀座線・丸ノ内線 –東京メトロ全部終了
都営大江戸線
都営浅草線・京急線(全線)・京成線(全線)・北総線・成田スカイアクセス<地下鉄全部終了
山手線
東海道本線・湘南新宿ライン
(関連)高崎線・宇都宮線
東海道新幹線(熱海まで)
京浜東北線
横須賀線・総武快速線
埼京線・川越線・りんかい線
京葉線・武蔵野線<山手線を通るJR全部終了
西武新宿線・西武多摩湖線・西武西武園線・西武国分寺線
西武多摩川線<西武線全部終了
東急大井町線・東急多摩川線・東急池上線
東急世田谷線
東急こどもの国線<東急線全部終了
南武線
横浜線
相鉄本線・いずみ野線
横浜市営地下鉄<神奈川県終了
東京モノレール
つくばエクスプレス
日暮里舎人ライナー
常磐線快速<東京都終了
新京成
成田線
東武野田線
総武本線・内房線・外房線

なぜ電車のシミュレーションごときにこんなに時間をかけてしまうのか。何が自分をこんなに掻き立てるのか、わからない。