読者です 読者をやめる 読者になる 読者になる

Javascriptシェル芸備忘録(2017.4)

先日のシェル芸勉強会で完全なるノリで始めました。
ですが、意外と楽しんでくれた人も多くて良かったです。
発表中には#Javascriptシェル芸なるハッシュタグも出来てて、
他の方が回答してくれたりしていて、思いがけず、とても勉強になりました。
ありがとうございます。
シェル芸かどうかは段々よく分からなくなっているけど、
まぁ分かりやすいし、言葉として結構気に入っています。

今回のきっかけ

最近、いろいろと仕事の関係でJavascriptを書くようになり、
ふと『シェル芸の問題をJavascriptで書いたら、どうなる?』と思い、
今回、挑戦してみました。
あとは、純粋にJavascriptの勉強になれば良いなと。

マイルール

あまり普通にやっても、つまらないかなと思い、ルールを作ってみました。
少しシェル芸っぽく、一行で書けるようにしたいなと。

  1. 全て繋げて書く。セミコロンレス。
  2. 要件を満たしているっぽく感じられたらOK!

実行環境

どちらでも出来るものもあれば、出来ないものもあります。
まぁ、そこはノリで。

シェル芸勉強会で発表したもの

大文字・小文字

第27回sedこわいシェル芸勉強会 Q1 https://blog.ueda.tech/?p=9283

  • 問題
次のechoの出力について、偶数番目の文字だけ大文字にしてください。
できたら、奇数番目の文字だけ大文字にしてください。
$ echo abcdefghijklmn
  • 回答
//偶数
"abcdefghijklmn".split("").map((char, index) =>  Boolean(index%2) ? char.toUpperCase() : char ).join('')
// 奇数
"abcdefghijklmn".split("").map((char, index) => !Boolean(index%2) ? char.toUpperCase() : char ).join('')

この問題は初歩的なので、おそらく解は多いのではと思います。
個人的には、自分の回答より、ツイートされていた下記の回答の方が好きですし、適切だと思います。

響け!ユーフォニアム

【ファン迷惑】「響け!ユーフォニアム」という文字列だけで遊ぶシェル芸人達 https://togetter.com/li/1041621

  • 問題
下記のような出力をする

響け!ユーフォニアム
け!ユーフォニアム響
!ユーフォニアム響け
ユーフォニアム響け!
ーフォニアム響け!ユ
フォニアム響け!ユー
ォニアム響け!ユーフ
ニアム響け!ユーフォ
アム響け!ユーフォニ
厶響け!ユーフォニア
  • 回答
"響け!ユーフォニアム".split("").map((char, index, line) => line.map((str, i, a) => a[Math.abs(i - index)]).join('')).join('\n')

シェル芸の中では、 伝統芸能とも称されるものですが、Javascriptなら簡単。

素数を算出

SHELQ: 怪しいシェル芸キュレーションサイト 第3位 https://blog.ueda.tech/?p=8862

  • 問題
素数を算出する
  • 回答
[...Array(100)].slice(2).map((u, i) => i + 3).reduce((pV,num) => pV.some((pn) => !(num % pn)) ?  pV : [...pV, num], [ 2 ])

上記回答は100までの素数を出すようにしています。これもJavascriptなら簡単ですね。

単語を数える

第24回◯◯o◯裏番組シェル芸勉強会 Q1 https://blog.ueda.tech/?p=8592

  • 問題
玉子 卵 玉子 玉子 玉子 玉子
玉子 玉子 卵 卵 卵 玉子
卵 玉子 卵 玉子 玉子 玉子
卵 玉子 卵 卵 卵 卵
玉子 卵 玉子
上のようなQ1ファイルについて、次のような出力を得てください。
玉子:5 卵:1 
玉子:3 卵:3 
玉子:4 卵:2 
玉子:1 卵:5 
玉子:2 卵:1 
  • 回答
require('fs').readFile('./Q1','utf8',(err, text) => console.log(text.split('\n').map((line) => line.split(' ')).map((line) => line.reduce((obj,str) => Object.assign(obj, obj[str]++), { '玉子' : 0, '卵' : 0 }))))

ファイル読み込みの処理を入れたので、Node.jsのみで動きます。

足して10になる

第22回ゴールデンウィークの存在疑惑シェル芸勉強会 Q5 https://blog.ueda.tech/?p=8028

  • 問題
足して10になる並びを全て見つけてみましょう。
1 3 4 4 2 3 5 6 7 9 1 4
  • 回答
"1 3 4 4 2 3 5 6 7 9 1 4".split(" ").map((v, i, array) => array.slice(i).reduce(({ sumArr, sum }, num) => sum === 10 ? { sumArr, sum } : { sumArr: [...sumArr, num], sum: sum + Number(num) }, { sumArr: [], sum: 0})).filter(({ sum }) => sum === 10).map(({ sumArr }) => sumArr)

本番で発表した時と、少しコードを変えました。

sin波

第25回もう4年もやってんのかシェル芸勉強会 Q8 https://blog.ueda.tech/?p=8737

  • 問題
サイン波を描いてください。
  • 回答
[...Array(20)].map((u, i) => Math.round((Math.sin(i) + 1) * 4)).forEach((count) => console.log(`${ " ".repeat(count) }*`))

map((u, i) => Math.round((Math.sin(i) + 1) * 4))の部分で大きさとかを調節しています。
本音を言うと、横向きにしたかったです。

ヒルベルト曲線

SHELQ: 怪しいシェル芸キュレーションサイト 第1位

  • 問題
ヒルベルト曲線を書く
  • 回答

これも伝統芸能の立ち位置ですね。
canvasタグ (id=canvas)が書かれているページで動作します。なのでChromeのみ。
最初の[...Array(4)]のところで大きさを調整しています。
あまり大きいと処理がパンクするので、せいぜい6が限度ではと思っています。
まだ、とりあえず書けるくらいに落とし込むまでしか行っていないので、もう少し洗練させる予定です。

  • 20170519追記

三角関数を使ったら、だいぶ短くなった。

オマケ

ズンドコキヨシ

[...Array(1)].reduce(() => zndk("") , zndk = (str) => /ズンズンズンズンドコ/.test(str) ? console.log(str + "キヨシ!") : zndk(str + ['ズン', 'ドコ'][Math.round(Math.random())])) 

reduceで再帰を試みるという汚いものです。
どうやったら再帰を上手く取り入れられるのかが最近の課題です。

FizzBuzz

[...Array(100)].map((v,i) => `${ ++i } : ${ !(i%3) ? "Fizz" : "" }${ !(i%5) ? "Buzz" : "" }` )

細かく答え合わせしてないけど、多分合っているのはと。