キャメルアップ開発記_004

サイコロを作る

要件は以下.

  • {1,2,3}が等確率で出る.
  • ラクダの色に応じた5色のサイコロがありこれらはランダムで選ばれる.
  • 出た色のラクダが出目だけ前進する.
  • 1度出た色はその他の色が全部出切るまで出現しない.

仮完成

f:id:ChiyosBigDragon:20190308153353g:plain
色々おかしいけどラクダの動きは正しい.当初地面は振ったダイスの色に変わっていて,これはこれで面白いと思っていたが,実装途中から黄色だけに反応するようになって使い物にならなくなった.整合性を取りながら機能を追加するのは難しい.地面は地面でグラを作るので大丈夫だとは思うが.
5色目が出た瞬間全色初期化されるのはちょっと気に食わない.実際は初期化前に精算があるのでそこまでの辛抱.

進捗(stack風)

キャメルアップ開発記_003

危機管理

適当にコードを書いていることに危機感を感じたのでESlintを入れてみることにする.Airbnbのスタイルが優れているということでそれに従う.ついでにatom-ternjsも入れた.
参考: ESLint 最初の一歩 — Qiita
参考: ESLintをAtomに導入し、Reactの構文にも対応したAirbnbのJSスタイルガイドを使う — maesblog

ピンチ

導入に成功したっぽいのでコードをlinterにかけてみる. f:id:ChiyosBigDragon:20190308154133p:plain
下見たらわかるけどエラー数365ですよ.全体で160行なのに.

なおす

インデント幅2でエラーが出たが幅4は譲れないのでここだけ設定をいじった.他のエラーは適切なスペースを入れることでおおよそ解消した.でもDisallow Early Use (no-use-before-define)が残ってしまった.相互再帰みたいなのはどうしたらいいんだろう.

進捗(stack風)

キャメルアップ開発記_002

ラクダを動かしたい

サンプルみたいにヌルっと動く必要はないので,グリッドを設定しその上を動くよう(なイメージ)にした.
f:id:ChiyosBigDragon:20190307224921g:plain
あの特徴的な動きを再現しなければ話は始まらない.情報を2次元配列に押し込んでいるので競プロの感じで実装した.これならJSだろうが無限ループも警察も怖くない.
以下では要件と実装gifを並べることにする.

あるラクダが移動する時,その上に重なったラクダは上下関係をそのままに追従する.
f:id:ChiyosBigDragon:20190307224916g:plain

前進時,移動先にラクダがいる場合,そのラクダの上に乗る.
f:id:ChiyosBigDragon:20190307224907g:plain

後退時,移動先にラクダがいる場合,そのラクダの下に潜る.複数のラクダが潜る場合,その上下関係はそのままである.
f:id:ChiyosBigDragon:20190307224911g:plain

通り過ぎる場合には以上の限りでない.
f:id:ChiyosBigDragon:20190307224903g:plain

進捗(stack風)

キャメルアップ開発記_001

初手

Unity/UE4は大仰すぎる感じがする.FLASHは淘汰されるらしいし,自然にHTML+JavaScript. 何も知らないのでとりあえずサンプルを作ることにした.
HTML Game Example — w3schools.com
写経をしたりしなかったりして進めていく.ボタンでの座標操作と画像読み込みまで読んだ.やってみよう.

素材が要る

ラクダのゲームなのでとりあえずラクダを描かないと.ピクセルアートが好きなのでEDGEを使う. f:id:ChiyosBigDragon:20190307223900p:plain
2の累乗サイズで作ったほうが圧縮効率が良いみたいな話を聞いたことがあるので32*32で作る.この大きさなら誤差とか言わない.色はカラーピッカーで適当に取った. f:id:ChiyosBigDragon:20190307223904p:plain
上下で綺麗に重なるのがこのゲームの特徴.その上でラクダっぽさを残すのがなかなか難しい.

できました

実際はこんなに小さくてかわいい. f:id:ChiyosBigDragon:20190307223912p:plainf:id:ChiyosBigDragon:20190307223843p:plain f:id:ChiyosBigDragon:20190307223847p:plain f:id:ChiyosBigDragon:20190307223851p:plainf:id:ChiyosBigDragon:20190307223854p:plain
カラーコードも置いておこう. #00569b #39b20d #f56300 #ffffff #ffd302

進捗(stack風)

Node.jsで作る番組情報通知Bot

先に

この記事はこれのパクリ.
Node.jsでテレビの映画放映情報をWebスクレイピングしてSlackに通知する — ほんじゃらねっと
もはや写経だが勉強記録用.

動機

家で新聞を取らなくなってからテレビの番組表はwebで確認しているのだが,いかんせん扱いにくい.どうせなら自分が興味のあるものだけ抜き出してしまおうというアレ.スクレイピングPythonでかじっているのでいけるはず.

検索

番組を探す — Gガイド.テレビ王国で見たい番組のキーワードや芸能人の名前を入力しURLを生成する.地上波+金属バット1で検索したところ以下のURLが得られた.
https://tv.so-net.ne.jp/schedulesBySearch.action?condition.genres[0].parentId=-1&condition.genres[0].childId=-1&stationPlatformId=1&condition.keyword=%E9%87%91%E5%B1%9E%E3%83%90%E3%83%83%E3%83%88&submit=%E6%A4%9C%E7%B4%A2&descriptive=true
このページのソースを元にスクレイピングする.

TV_scrape.js

const httpClient = require('cheerio-httpcli');

async function fetch(url) {
    const baseUrl = url;
    const scheduleList = [];
    const result = await httpClient.fetch(baseUrl);
    const $ = result.$;
    $('.utileList', '.contBlockNB').each(function () {
        const row = $(this);
        scheduleList.push({
            title: $('h2 a', row).text().trim(),
            date: $('.utileListProperty', row).text().trim().replace(/([\s\t\n]| )+/g, ' '),
            caps: $('.utileListDetail', row).text().trim(),
        });
    });
    return scheduleList;
}

function stringifyList(scheduleList) {
    return scheduleList.map(schedule => stringify(schedule)).join('\n\n');
}

function stringify(schedule) {
    let text = schedule.date + '\n';
    text += '*' + schedule.title + '*' + '\n';
    text += '>' + schedule.caps + '\n';
    return text;
}

module.exports = {
    fetch,
    stringifyList,
    stringify
}
  • ライブラリはcheerio-httpcliを使う.requireimportみたいなものか.
  • 関数名の前にasyncを置くと内部でawaitが使える.awaitは待機と例外処理を担う?
  • index側からfetchにURLを投げる.
  • タグはそのまま,id#class.を付けて表現する.
  • module.exportsは外から呼んだときに使えるようにするもの?

slack.js

const request = require('request');

module.exports = {
    postMessage: async (token, channel, text) => {
        const options = {
            headers: {
                'Authorization': 'Bearer ' + token
            },
            form: {
                channel: channel,
                text: text,
                as_user: true
            },
            json: true
        };
        return new Promise((resolve,reject) => {
            request.post('https://slack.com/api/chat.postMessage', options, (error, res, body) => {
                if(error) {
                    reject(error);
                }
                resolve({
                    response: res,
                    body: body
                });
            });
        });
    }
};
  • 一言一句違わず申し訳ない気持ちになる.
  • やっていることは単純だが一から書くとなると…

index.js

通知といったら瓦版なのでチャンネル名は#瓦版fetchの前にawaitを入れないとエラーを吐くので気を付ける.

const slack = require('./slack');
const TVScrape = require('./TV_scrape');
const fs = require('fs');

function main() {
    const jsonObject = JSON.parse(fs.readFileSync('./url.json', 'utf8'));
    jsonObject.list.forEach(async (obj) => {
        const scheduleList = await TVScrape.fetch(obj.url);
        const scheduleListText = TVScrape.stringifyList(scheduleList);
        const slackMessageText = '*<' + obj.id + ' の番組情報>*\n\n' + scheduleListText;
        const token = 'API_TOKEN';
        slack.postMessage(token, '#瓦版', slackMessageText);
    });
}

main();

url.jsonの中身はこんな感じ.idには自分で検索条件の説明を入れられる.listに2要素以上入れてもok.

{
    "list": [
        {
            "id": "地上波+金属バット",
            "url": "https://tv.so-net.ne.jp/schedulesBySearch.action?condition.genres%5B0%5D.parentId=-1&condition.genres%5B0%5D.childId=-1&stationPlatformId=1&condition.keyword=%E9%87%91%E5%B1%9E%E3%83%90%E3%83%83%E3%83%88&submit=%E6%A4%9C%E7%B4%A2&descriptive=true"
        }
    ]
}


以上のコードを実行するとSlackに通知が来る.
f:id:ChiyosBigDragon:20190313122804p:plain

他にやりたいこと

  • AWSで定期的に実行.
  • Slackのslash-commandを用いた検索条件の追加削除.

今回はここまで.

ブラウザで遊べるキャメルアップが作りたい

見たこともないほど最高にイカレたラクダレースへようこそ!
http://hobbyjapan.games/camel_up_2019/


先回りQ&A

  • キャメルアップ?
  • どういうやつ?
    • コースを爆走するラクダの順位を予想して資産を増やすゲーム.
  • 「競馬」っていうよく似たゲームがあるんですけどそれじゃダメですか?
    • は?お前上の動画見たか?乗っかり逆走1なんでもありだぞ?ファンタジー最高!!!!!
  • ルール?
    • 以下の動画が詳しい.お話は長いがちゃんとまとまっている.実装するときに詳細は書くから勘弁してくれ.
  • アプリあるじゃん?
    • いやお手軽に楽しみたいじゃん.あとああいうのってローカルルール2ないでしょ.俺たちもうその域まで行ってるから.既存のものに文句を言う我々は自分でコードを書くしかない.
  • 公開すんの?
    • Webサービスの経験がないのでどうしたらいいかわからない.プロトタイプはできるだけ公開するけど.完成品の公開は流石に権利関係やばそうなので考えます.まあ身内用なので.

やりたいこと

  • ゴッドフィールドみたいな多人数同時プレイ(COMは面倒だから作りたくない).
  • 2014版準拠/拡張パック準拠/2019版準拠/ローカルルールなど自由度の高いプレイ体験.
  • (いい感じのUIとチャーミングなグラフィック.)

今回はここまで.次回からただの進捗ログ.


  1. 逆走は2019版のみ.誰か買ってくれ.

  2. イキって英/独版買ったら説明書が読めなくて,独自に解釈したルールをローカルルールだと言い張っている.