inkを使ってReactでコマンドラインで遊べるテトリスを作成してみた!

# inkとは

reactでコマンドラインアプリケーションが作れるライブラリです

- [vadimdemedes/ink: 🌈 React for interactive command-line apps](https://github.com/vadimdemedes/ink)
- [inkでターミナルappを作る - Qiita](https://qiita.com/takeyuichi/items/4a862835c572a9710167)

コマンドラインアプリの勉強のためにとりあえずテトリスを作成してみました!

![Dl2JacS1hQ.gif](https://qiita-image-store.s3.amazonaws.com/0/142910/8d3298e7-b8cb-b361-d831-9229f49a6c7e.gif)

[コードはこちら](https://github.com/okumurakengo/00010_ink)

### 注意

私はjavascriptは趣味で勉強しているだけですので、コードはあてにしないでください。:bow:

コマンドラインアプリの勉強のためということのため、完成度にはこだわっておらずこのテトリスはバグだらけですすみません :confounded:

### バージョン

- node : v10.14.1

---

# 参考

shellで書かれたテトリスのサンプルはたくさんあるようなので、それらを参考にさせていただきました。

見た目の表示などこちらを特に参考にさせていただきました。

- [dkorolev/bash-tetris: Tetris game implemented in pure bash.](https://github.com/dkorolev/bash-tetris)

テトリスではないですが、コマンドラインで遊べるゲームの参考にさせていただきました

- [Arcade Games written in a Shell Script | *nix Shell](https://nixshell.wordpress.com/2011/07/13/arcade-games-written-in-a-shell-script/)

# ブロックの表現

自分の中では一番やり方がわからなかったのですが、**文字色と背景色を同じにして** ブロックを表現するというやり方のようです。

nodejsではchalkというライブラリで簡単にコマンドラインの文字に色を付けれるのでそちらを使用しました

- [chalk/chalk: 🖍 Terminal string styling done right](https://github.com/chalk/chalk)

(inkの`<Text>hoge</Text>`のコンポーネントでは背景色に対応していないようでした、chalkを直接使うと良さそうです)

```js:index.js
const chalk = require('chalk');
console.log(chalk.blue.bgYellow('[]'), '<- 文字色と背景色をそれぞれ指定できる');
console.log(chalk.green.bgGreen('[]'), '<- 文字と背景を同じ色にするとブロックに見える');
```

```bash:bash
npm i chalk
node index.js
```

![image.png](https://qiita-image-store.s3.amazonaws.com/0/142910/982e72d3-64a1-3e2c-3c91-f336a6af5ded.png)

# 標準入力

ブロックの移動、回転をさせるイベントを起こすために、キーボード入力の機能を調べました。

こちらをだいぶ参考にさせていただきました。

[vadimdemedes/ink-text-input: Text input component for Ink](https://github.com/vadimdemedes/ink-text-input)

---

参考にする際の注意点ですが、こちらのコードでは以下のような書き方がされています。

https://github.com/vadimdemedes/ink-text-input/blob/e978cd4265c4eff0a40e8739441cfe0b2af134a9/src/index.js#L89

こちらの `@babel/plugin-proposal-class-properties` を読み込まないとbabelで変換するときに現在ではエラーになるので注意です。

https://github.com/vadimdemedes/ink-text-input/blob/e978cd4265c4eff0a40e8739441cfe0b2af134a9/package.json#L43

---

新しい書き方ですので、babelのプラグインをインストールすると動かせます

https://www.npmjs.com/package/babel-plugin-transform-class-properties

google翻訳

> このプラグインは、es2015プロパティ初期化子構文で宣言されたプロパティと同様に、es2015静的クラスプロパティを変換します。

このようにpluginを使えば変換できます

![Screen Shot 2019-03-17 at 20.39.56.png](https://qiita-image-store.s3.amazonaws.com/0/142910/ea19479e-c705-fe5d-b02a-0dcf15a6b74e.png)


# 画面レイアウト

公式のReadmeにあることを一部流用です。flexboxの知識がある方はすんなりレイアウトできそうです。
実際使ってみて、レイアウトは簡単にできるから裏側のシステムに集中できるという感じでした、すごい!!

```jsx
import React from 'react';
import { render, Box } from 'ink';
const App = () => {
    return (
        <>
            {/* スペースで埋める */}
            <Box>
                Label:
                <Box flexGrow={1}>
                    Fills all remaining space
                </Box>
                aaa
            </Box>

            {/* 上下中央 */}
            <Box alignItems="center">
                <Box marginRight={1}>X</Box>
                <Box>{`A\nB\nC`}</Box>
            </Box>
            
            {/* 逆転 */}
            <Box flexDirection="column-reverse">
                <Box>X</Box>
                <Box>Y</Box>
            </Box>
        </>
    );
}

render(<App/>);
```

![image.png](https://qiita-image-store.s3.amazonaws.com/0/142910/5021c070-6f08-d858-03db-8aea73ba282c.png)

---

最後まで読んでいただいてありがとうございましたm(_ _)m