虎の穴開発室ブログ

虎の穴ラボ株式会社所属のエンジニアが書く技術ブログです

MENU

Deno環境のTypeScriptでRubyプログラミング問題を解く

f:id:toranoana-lab:20211214150343p:plain

こんにちは、虎の穴ラボの磯江です。

この記事は虎の穴ラボ Advent Calendar 2021 14日目の記事になります。

13日目は、植竹さんが「GCPのサーバーレス環境「CloudRun」を実用してみた」という記事を書いています。

toranoana-lab.hatenablog.com

普段はRailsとVue.jsで開発に取り組んでいますが、TypeScript力(ぢから)を向上させるべく、プログラミング課題に取り組んだので、解説を記事にしました。

目次

Rubyプログラミング問題にチャレンジ! -改訂版・チェリー本発売記念-

Qiita様主催のアドベントカレンダーのひとつに「Rubyプログラミング問題にチャレンジ! -改訂版・チェリー本発売記念-」があります。 今回はこの課題に取り組んでみました。

qiita.com

詳しい課題内容は、上記アドベントカレンダーを確認してください。

簡単に説明すると、

  • TenjiMakerクラスと点字を表示するto_tenjiメソッドを実装する
  • 用意されているテストコードをパスする
  • 課題提出用リポジトリに実装したコードを提出する

今回はTypeScriptで課題に取り組むので、課題提出用リポジトリへのプルリクエストは作成しません。 そのため、以下の条件を満たせば良いこととします。

  • 課題提出用リポジトリに用意されているテストコードを移植する
  • 移植したテストをすべてパスする
  • 「とらのあなラボ」の点字出力をテストパターンに追加する

今回作成したコードは、以下のリポジトリに公開しています github.com

Denoを選んだ理由

Denoは、JavaScriptとTypeScriptの実行環境です。 虎の穴ラボにはいくつか推し技術がありますが、Denoはその一つです。 当ブログでは、Deno関連の記事もありますので、興味あればぜひ御覧ください。

deno.land

Denoは標準ライブラリだけでテストを実行することができるので、テストコードのクリアが必須な今回の課題にピッタリです。

さらにTypeScript実行環境を簡単に構築できます。

Denoの導入方法は、公式Webページを確認してください。

テストコードを移植する

移植するテストコードは、以下の6種類です。

  • アヒルの点字表記
  • キリンの点字表記
  • シマウマの点字表記
  • ニワトリの点字表記
  • ひよこの点字表記

Rubyでの実装は、以下から確認できます。

github.com

以下は、「アヒル」のコードです。

import { assertEquals } from "https://deno.land/std@0.116.0/testing/asserts.ts";
import TenjiMaker from '../lib/tenjiMaker.ts'

const tenjiMaker = new TenjiMaker();

Deno.test('test_a_hi_ru', () => {
  const tenji = tenjiMaker.toTenji('A HI RU');
  assertEquals(tenji,
    `o- o- oo
-- o- -o
-- oo --`.trimEnd());
});

deno testコマンドでテスト実行するためには、Deno.test()を利用します。 Rubyのプログラミング課題と同じ様に文字列比較をしています。

今回は追加で「とらのあなラボ」の点字表記を実行します。

Deno.test('test_bit_to_string_to_ra_no_a_na_ra_bo', () => {
  const tenji = tenjiMaker.toTenji('TO RA NO A NA RA BO')
  assertEquals(tenji,
    `-o o- -o o- o- o- -- -o
oo -o o- -- -- -o -o o-
o- -- o- -- o- -- -- oo`.trimEnd());
});

文字数が増えていますが、toTenjiファンクションが実装されていれば、大きな問題ではありません。

問題は BOです。元のテストコードでは、2文字分のマスを利用する濁点・半濁点は必要なかったのですが、 追加テストケースのために工夫が必要になりました。

Denoのテスト実行

テストコードの実行は以下のコマンドで実行可能です。

deno test

このコマンドを実行することで、末尾が _test.tsとなっているファイルのテストを実行してくれます。 詳細な仕様はDenoのマニュアルに記載されています。

https://deno.land/manual/testing

特定のテストケースのみを実行したい場合には、--filterオプションを利用します。

deno test --filter a_hi_ru

上記を実行するとtest_a_hi_ruのケースのみテスト実行できます。

実装

点字を実装するための考え方

Qiitaアドベントカレンダー内で紹介されている全国視覚障害者情報提供施設協会の点字の仕組みにあるように、点字は以下の基本構成となっています。

www.naiiv.net

①④
②⑤
③⑥
そのうち、①②④で母音を表し、③⑤⑥で子音を表しています。 各点は、点が「ある」「ない」の2種類状態を持っているので、点字は6桁の2進数と考えることができます。 上記の順番どおりに、母音を表現すると以下になります。

A = 0b100000 = 32
I = 0b110000 = 48
U = 0b100100 = 36
E = 0b110100 = 52
O = 0b010100 = 20

点字インターフェイス

上記の考えを元に点字を表現するインターフェイスを実行します。

export interface Tenji {
  character: string;
  prefixBit: number;
  bit: number;
}

characterは点字のローマ字文字定義です。
prefixBitは濁点・半濁点の定義です。
bitは点字の数値定義(6桁の2進数)です。

点字の大半は母音と子音を組み合わせることで、表現できるため母音と子音をそれぞれクラスとして定義します。

母音の定義

// 「あ」の定義
class VowelA implements Tenji {
  character = 'A';
  prefixBit = 0b000000;
  bit = 0b100000;
}

// 「い」の定義
class VowelI implements Tenji {
  character = 'I';
  prefixBit = 0b000000;
  bit = 0b110000;
}

// 「う」の定義
class VowelU implements Tenji {
  character = 'U';
  prefixBit = 0b000000;
  bit = 0b100100;
}

// 「え」の定義
class VowelE implements Tenji {
  character = 'E';
  prefixBit = 0b000000;
  bit = 0b110100;
}

// 「お」の定義
class VowelO implements Tenji {
  character = 'O';
  prefixBit = 0b000000;
  bit = 0b010100;
}

子音の定義

子音は、母音との組わせで表現可能な「か」「さ」「た」「な」「は」「ま」「ら」「が」「ざ」「だ」「ば」「ぱ」行分だけ定義します。

// か行の定義
class ConsonantK implements Tenji {
  character = 'K';
  prefixBit = 0b000000;
  bit = 0b000001;
}

// が行の定義
class ConsonantG implements Tenji {
  character = 'G';
  prefixBit = 0b000010;
  bit = 0b000001;
}

「が」行は濁点を示すマスがあるため、prefixBitが定義してあります。

母音と子音の組み合わせで表現できない文字の定義

「や」「ゆ」「よ」「わ」「を」「ん」は、子音と母音の組み合わせで表現できないため、個別に定義します。

// 「や」の定義
export class TenjiYA implements Tenji {
  character = 'YA';
  prefixBit = 0b000000;
  bit = 0b001100;
}

// 「ゆ」の定義
export class TenjiYU implements Tenji {
  character = 'YU';
  prefixBit = 0b000000;
  bit = 0b001101;
}

// 「よ」の定義
export class TenjiYO implements Tenji {
  character = 'YO';
  prefixBit = 0b000000;
  bit = 0b001110;
}

// 「わ」の定義
export class TenjiWA implements Tenji {
  character = 'WA';
  prefixBit = 0b000000;
  bit = 0b001000;
}

// 「を」の定義
export class TenjiWO implements Tenji {
  character = 'WO';
  prefixBit = 0b000000;
  bit = 0b001010;
}

// 「ん」の定義
export class TenjiN implements Tenji {
  character = 'N';
  prefixBit = 0b000000;
  bit = 0b001011;
}

その他の実装

あとは文字列を文字に分解して、子音と母音の組み合わせを作るだけです。 この解析・組み合わせの処理自体は、とくに特別なロジックはないため割愛します。

「KA」という文字列がある場合、 子音「K」のbit = 0b000001と母音「A」のbit = 0b100000を組み合わせた0b100001が「KA」を示す数値です。

これを点字の表示順に表示するだけです。

0b100001は10進数では 33ですが、点字を扱うために2進数文字列に変換する方法は以下です。

0b100001.toString(2).padStart(6, '0');

まとめ・感想

今回は、「Rubyプログラミング問題にチャレンジ! -改訂版・チェリー本発売記念-」に、TypeScriptとDenoの環境を利用して取り組んでみました。

考案したインターフェイスは、実装範囲ではうまく機能しているようです。 今回は促音「っ」、長音「ー」、拗音「ゃ、ゅ、ょ」系の実装をしていないですが、濁音と同じ様にprefixBitを利用して実装可能です。

また、Denoがテストコードの実装を容易にしてくれたため、TypeScriptで実装することに集中できました。 皆さんもプログラミング課題を自分の得意、または強化したい言語で取り組んでみてはいかがでしょうか?

P.S.

採用情報
■募集職種
yumenosora.co.jp

カジュアル面談も随時開催中です
■お申し込みはこちら!
news.toranoana.jp

■ToraLab.fmスタートしました!
メンバーによるPodcastを配信中!
是非スキマ時間に聞いて頂けると嬉しいです。
anchor.fm
■Twitterもフォローしてくださいね!
ツイッターでも随時情報発信をしています
twitter.com