2020年9月13日日曜日

こども漢字辞書を作った

こども漢字辞書 を作りました。 最近 Microsoft が漢字のアニメーションを公開 していたのですが、 ふと似たようなデータがあったような、と気付いたのがきっかけです。

個人的により良い漢字辞書があると良いなあとは多少思っていたので、これも夏休みの自由研究で作ったものです。 特徴は以下。
  • こどもの学習に無駄のないUI
  • SVGによる効率的なアニメーション
  • 意味調べや練習に適した用例の提示




かなり使いやすくできたと思うのですが、どうでしょうか。 利用データのライセンスを引き継いで、コードも CC BY-SA 4.0 で公開 しています。

いざ作ってみると、漢字の読みは常用漢字でさえブレが大きくて、どう対処すべきか迷いますね。 まあ国のデータのほうが正しいのでしょうと判断しましたが、頻出ケースでフィルタリングする手もあるのかも知れません。

2020年9月12日土曜日

お手軽にダークモード対応 (+処方箋)

ダークモード対応は意外と面倒なのですが、少し前に以下の記事がバズっていました。
これは素晴らしいと思ったのですが、白黒反転しただけではいくつかうまくいかないケースがあります。 その処方箋についてまとめます。

1. 色が薄くて読みにくいよ!

Bootstrap や典型的ないくつかのテンプレートでは、白黒反転しただけではわずかに読みにくいケースがあります。 そこで私が最初に思い付いたのは、以下のコードです。 配色の調整がしやすいのでほとんどのサイトでおすすめできます。
html[data-theme="dark"] {
  filter: invert(1) hue-rotate(180deg) brightness(1.5);
}
しかしこの方法ではうまくいかないケースがあることに気付きました。

2. filter 付けたくないものにも付いちゃうよ!

一番わかりやすいのは、getUserMedia などでカメラ映像を canvas に書き出す時です。 たとえば遊びで QRコードリーダーを作ってみた のですが、こういった処理をすると ホラー画像ができてしまいます。 html タグに filter を掛けると filter を付けたくないタグの調整ができなくなるため、さて困りました。

応急処置としては以下のようになるでしょうか。 復元不可能になる brightness(1.5) を諦めて、canvas だけ filter を掛け直します。
html[data-theme="dark"] { filter: invert(1) hue-rotate(180deg); }
html[data-theme="dark"] canvas { filter: invert(1) hue-rotate(180deg); }

…いかにも頭の悪いコードなのですが、簡単さを追求するとこれが一番な気がします。 色が薄くてどうしても読みにくいタグがあれば、そのタグだけ brightness(1.5) などを掛ければいいと思います。 もっと良い書き方、あるでしょうか。

3. Firefox の表示がおかしいよ!

Firefox には html, body 要素に対する background-color の filter が効かない仕様があるため、 上記のプロパティを適用しても、body 以下の要素しか反転しない問題があります。 これがどういった時に問題になるかというと、ページが短く body 要素がページ全体を覆っていない時、 下側の背景が反転しておらず不格好になります。 なので、Firefox は html 要素に色指定をつける必要があります。
html[data-theme="dark"] { filter: invert(1) hue-rotate(180deg); }
@-moz-document url-prefix() { html[data-theme="dark"] { background-color:black; } }

4. prefers-color-scheme を考慮したい

以下でいけます。最初の一回だけ色が反転するくらいなら気にしないで良いかも知れません。 私は 3 + loalStorage で十分と思ってます。
html[data-theme="dark"] { filter: invert(1) hue-rotate(180deg); }
@-moz-document url-prefix() { html[data-theme="dark"] { background-color:black; } }
@media (prefers-color-scheme: dark) {
  html { filter: invert(1) hue-rotate(180deg); }
  @-moz-document url-prefix() { html { background-color:black; } }
  html[data-theme="dark"] { filter: invert(0); }
  @-moz-document url-prefix() { html[data-theme="dark"] { background-color:white; } }
}

5. body の外側を完璧にする

3, 4 で一見完璧に見えるお手軽ダークモードですが、 スマホでページを一番上/一番下まで行き、さらに上下に動かそうとした時に、 ダークモードではない時の色設定が残る問題があります。 html で全体に filter を掛けた時、body には filter が掛かるけど、 その外には掛からないみたいなそんな感じでしょうか。 body そのものに背景色を指定しないと駄目なようなので、直すのは簡単ではありません。

暫定的な解としては以下があると思います。 html ノードに属性を付与するのではなく body に theme 属性を付与します。 body 直下のテキストノードの色が変わらないなどの制約はありますが、 font-color で対応すれば一応は何とかなる。
body[data-theme="dark"] { background-color:black; }
body[data-theme="dark"] > * { filter: invert(1) hue-rotate(180deg); }

全称セレクタを使ってるのは少し気になります。 body の下は普通なら header,main,footer,template,script くらいしかないから、別に問題ないのかな。 ただ body 直下にノードを生やす系のライブラリがあると面倒なことになりそう。 3 とどちらがいいか微妙なところ。こっちのほうが良いかな。

2020年9月7日月曜日

漢字しりとり、カタカナしりとりを作った

漢字しりとりカタカナしりとり を作りました。 ゲームとしては定番中の定番ですが、真面目な漢字しりとりのゲームは、あるようでなかった気がする。 漢字の読みは IPAdic からの熟語生成 を利用しています。



これも初学者用に GitHub でコードを公開 (漢字しりとりカタカナしりとり) してます。

漢字のしりとりは、二字なら余裕なのですが、三字は私も難しく感じるくらい。 原因としては IPAdic で生成される熟語の頻度に問題があります。 三字熟語はほとんどすべてが低頻度に張り付いてしまうために、難易度調整が難しくなっています。 今のところ良い解決策は浮かんでいないので、漢字の三字モードは、上級者向けということにしておきます。 やはり熟語を調べてもらうことが重要なゲームです。

IPAdic から頻出熟語を生成してみた

以前作った熟語ジェネレーター は、n-gram ベースでした。 他の作り方として IPAdic を使った方法もわかっていたので、作ってみました。

実際に作ってみた結論としては、
  1. IPAdic には読みデータが付いているメリットがある
  2. IPAdic のほうが低頻度領域のノイズは強い
  3. その一方で頻度分布自体が不正確なので n-gram のほうが利用しやすい
  4. カタカナ熟語は IPAdic だとやや不安定
  5. カタカナ熟語は IPAdic だとインターネット語に弱い
4 はわかりにくいので例を挙げます。 例えば「カタログ」で grep を掛けると、「カタログプロシージャ」「カタログデータ」などがヒットします。 これは熟語として使えるかというと、正直使いにくいと思います。 データとかプロシージャといった言葉はあらゆる単語に連接可能だからです。 つまりカタカナ熟語の生成は IPAdic を使っても微妙で、目視できちんと排除するしかありません。 このとき頻度情報が問題で、よく使うような熟語のコスト値も 3999 (低頻度) に分類されてしまっています。 n-gram 方式のように、頻度順に目視で対処というのが難しくなってます。 よって用例も多く、正確な頻度順にまとまっている n-gram 方式のほうが扱いやすそうという結論になります。

漢字に関しては、生成されたデータを目視で確認した限り、数が多ければ IPAdic でも問題ありません。 ただ数が少なくなってくると IPAdic はあまり使わない熟語が生成されやすい傾向は見て取れ、データ量の少なさによって生じる頻度問題を感じます。 n-gram 方式のほうがより良い熟語が取れるように思います。 とはいえ IPAdic には読みが付いているメリットがあるので、読みを活用したい場合には IPAdic が良さそうです。

まー n-gram に Mecab などで読みを付与する方法もあるとは思うんですが、エラー訂正面倒なので…。 それやるともはや形態素解析器の重み計算をやり直すようなものなので、今回はパス。 ちなみに IPAdic / n-gram どちらの場合もフィルターを付けないと、熟語として使いにくいことは変わりません。 これは n-gram からの熟語生成 と同様のフィルターを流用すると、いい感じでした。

IPAdic を使った熟語生成も コードを公開 しました。

Node.jsで複数のリソースからsleepしながらfetch

Node.js の非同期処理が苦手過ぎるので、Node.js で複数のリソースから sleep しながら fetch するサンプルを載せておきます。 API を使う時によく使う割にハマりやすい。


const fetch = require('node-fetch')

function sleep(time) {
  const d1 = new Date();
  while (true) {
    const d2 = new Date();
    if (d2 - d1 > time) {
      return;
    }
  }
}

// ここで API の仕様に沿った実装をする
function fetchFromABC(id) {
  return new Promise((resolve, reject) => {
    fetch('https://hoge.com/' + id)
    .then(response => response.json())
    .then(data => {
      // process.stdout.write(id);  // 進捗表示
      sleep(1000);  // sleep しながら同期的に取得
      resolve(data);  // 取得データを返却
    });
  }));
}

// sleep しながら取得する
async function fetchFromABCMultiple(ids) {
  var info = {};
  for (var i=0; j<ids.length; i++) {
    await fetchFromABC(ids[i]).then(res) => {
      info[i] = res;
    });
  }
}

var ids = [1, 2, 3, 4, 5];
fetchFromABCMulpile(ids).then(info => {
  console.log(info);
});

書き方に慣れないとこのへん本当にハマりやすいよなあ。

2020年9月3日木曜日

フリゲ紹介: 人生オワタの大冒険2

人生オワタの大冒険2 は、一発当たったら即死の初見殺しアクションゲームです。 人生オワタの大冒険 (無印) を知ってる方も多いと思いますし、 YouTuber の食い付きがすごいので紹介するまでもないかも知れませんが、とても良い作品でした。

平成が終わり、AA も規制が付いたり、Flash も終了が予告されている中の大人気で、 人生オワタの大冒険の知名度って凄いんだなあと感じました。



相変わらずの初見殺しで死にまくるのはいつも通りでしたが (左下)、 ワンマップごとにやり直せる仕組みがあるので、あまり理不尽さを感じずにプレイできるのが良いですよね。 今回一番の難所はおそらく、やる夫&やらない夫戦だと思います (右下)。 たぶん無印の tanasinn よりずっとたくさん死んだと思う。 単純なパターン動作だけど 2 体いるだけでこんなに難しくなるとは。 ラストはどこか切なく、そして満足感の高い ED でした。



ところで 2ch の AA ってゲームにするのがすごい簡単なんですよね。 人生オワタの大冒険クラスのものを作るのは大変としても、手頃な HTML ゲーム作成には割とおすすめだったりします。 また動く AA ってやっぱ良いよなあと思って、ファンアートと、簡単に動くブログパーツを作るための ネタ Framework (Svelke) を作ってみました。 ファンアートはボスで登場する、抜け毛のハゲしいおハゲです (なんとなく 2 匹にしてみた)。



動く AA を手軽に作れると、結構便利です。 Flash が死んでも AA は残って欲しいですね。

フリゲ紹介: DAY:0(:FIFTY)

今年もウディコン受賞作品を上位 20 件+α プレイしてみました。 83 件もエントリーがあり、レベルの高いコンテストだったように思います。

今年は、ベビーシッター2XXX や、266229 など国語や算数のゲームがあって新鮮でした。 総合 5 位の ピクロジカル (ピクロス) も算数と言えば算数だし、 君はヒの魔法使い も漢字を応用したシステムを使っています。 私もウディコンの裏で、夏休みの自由研究として平凡な国語のゲームを4つ作ったので、意外と作る人がいるんだなーと思いました。

好みもあると思いますが、私が上位 20 件で特に面白いと思ったのは、 DAY:0扉は君の鍵で開く怪異探偵委員会流星の射手 ~亜人大戦争~夢遊猫ネクロフィリア十二の願いが叶うなら の 6 つです。 扉は君の鍵で開く はたぶんありそうでなかった、完全質問型の探し物 ADV。 質問形 ADV って違和感なく作るの大変そうだけど、違和感なくプレイできてすごかった。 落ち葉の大地を走れ の作者様ですが、自力で答えを導いてくスタイルの作品作り、毎回凄いですね。

怪異探偵委員会流星の射手 ~亜人大戦争~夢遊猫ネクロフィリア十二の願いが叶うなら はシンプルに面白かったです。 無双猫シリーズはたくさん遊ばせてもらってますが、私は今までで一番ハマったかも? カードゲームはあまりやらないけど、とても遊びやすい内容でした。 十二の願いが叶うなら は見た目ゆるふわだけど、しっかりしてて面白い。

上記以外だと SeekerMemoria も面白かったけど、かなり上級者向けな気はします。 腕に自信がある人には歯ごたえがあって良さそうなシューティングです。 雰囲気という意味だと、THE CANDLE LIGHT も凄いです。 ゲーム自体はロウソクに火を灯していくというシンプルなゲームですが、これは手間暇掛かってる。


熱中度という意味だと、今回紹介する DAY:0(:FIFTY) (開発: PANO 氏) になるのかなと思います。 83 作品から選ばれただけあって、さすがの 1 位という感じがします。 DAY:0(:FIFTY) は、リアルタイム型のタワーディフェンスです。



特徴としては、10種類+のユニットと20種類のカード、スペル、地形を組み合わせてステージを攻略でき、自由度の高いところです。 反面、1プレイ中はユニットやカードの種類などの変更はできないため、タイトル画面で組み合わせを考えつつ、何度かプレイして楽しむ仕組みになっています (下)。 様々な組み合わせでプレイできますが、最初に設定されてるユニットと設定が、一番バランス良く強い気がします。



プレイしていてとても新鮮だったのは、通常のタワーディフェンスより多くのことを考えさせる仕組みです。 たとえば通常のタワーディフェンスでは敵が即死技を使ってくるのを見たことありませんが、DAY:0 では使ってくるため、回避の方法を考える必要があります。 他にも条件付きの無敵ユニットがいたり、地形破壊などの要素があり、とても新鮮です。

なぜ DAY:0 ではそのようなことができたかと言えば、ダウンした味方ユニットが数ターン後に復活できるシステムを用意したからだと思います。 この仕組みを用意したことでリカバリしやすくなり、先に述べたようなこれまでにない要素を追加できています。凄いなあと思いました。 また復活システムで少しくらいのミスがあってもリカバリできるため、30〜45分という長めのプレイ時間に通用するようにもなっている。

ボス戦が白熱するようになったのも熱中度を高める意味で大きなポイントだと思います。 初回時のラスボスは EASY でも本当にギリギリで、とても面白かったです。 初回以降も色々な組み合わせで楽しめて面白く、タワーディフェンスの未来を感じる作品でした。

2020年9月1日火曜日

三字熟語さがし、カタカナ熟語さがしを作った

三字熟語さがしカタカナ熟語さがし を作りました。 漢字のゲームとしては定番中の定番ですね。 漢字迷路カタカナ迷路熟語ジェネレーター のコアコードを利用した、夏休みの自由研究です。



重要なコードは先のアプリで書き終わっているので、すぐ作れました。 これも初学者用に GitHub でコードを公開 (三字熟語さがしカタカナ熟語さがし) してます。

語彙力不足の子はヒントなしだと迷路より探しもののほうが難しく感じる傾向があるように思います。 ただヒント機能があるので、ヒントを出しながらプレイすると、こちらのほうが圧倒的に楽になります。 プレイスタイルは自由でも、熟語を調べることが大事です。

フリゲ紹介: Dark Malice

Dark MaliceVIPRPG 2020 夏祭り で公開された、VIPRPG の世界に色々なものがたくさん混ざってる探索 RPG。 混ざりすぎて把握しきれないけど、Nepheshel、イストワール、メイジの転生録、あたりは強く混じってるように思う。 メインストーリーのクリアなら 5〜6時間でしたが、やり込むと相当楽しめそう。



突然のブレーキ音!で始まるため、ストーリーはほとんどないですが、 まずは先に召喚されて散り散りになっている仲間を探しながら、遥か北の地を目指します (左下)。 最初は 1人でスタートしますが、探索を進めていくと徐々に仲間が増えていきます (右下)。 ダンジョン探索が 90% くらいの作品でストーリーはほとんどないものの、やり込み要素などで世界の状況がおぼろげにわかる仕組みになっています。



ダンジョン探索は、シンボルエンカウント+デフォ戦 (下)です。 全体的に Nepheshel やイストワールの空気が漂っていて、プレイしたことのある人は、 どこかで見たようなトラウマボスやダンジョンを見かけることになるかと思います。 隠し宝箱はあまりない代わりにダンジョンはかなりギミックが効いている。 要所要所で雑魚も結構強く、また回復できないポイントが結構あるので、終盤はギリギリ感を味わえます。



上記類似作品に限らず、どこかで見たようなバランスブレイカーな仕組みがあったりなかったり。 物理と魔法の役割、そして職業の役割がきっちりわかれています。 耐性パズルは控えめの代わりに、役割分担をしっかり考えることが肝になっているのが、シンプルながら面白かったです。 特に重要なのが職業選択 (左下) で、強敵相手には有効なスキルを考える必要があって面白かったです。

メインストーリーのクリアは意外と早かったのですが、色々なところにやり込み要素が隠されています。 例えば、容姿端麗、頭脳明晰、高学歴な半竜なすーん (右下) や、落ちたら帰ってこれなそうな穴、などなど。



ネフェイストなオマージュ作品として、とても楽しめた作品でした。