LoginSignup
10
5

More than 1 year has passed since last update.

闘魂プログラミング(ストロングスタイル)をElixirで楽しむ!

Last updated at Posted at 2023-01-28

$\huge{元氣ですかーーーーッ!!!}$
$\huge{元氣があればなんでもできる!}$

$\huge{闘魂とは、己に打ち克つこと。}$
$\huge{そして、闘いを通じて己の魂を磨いていく}$
$\huge{ことだと思います}$

はじめに

アントニオ猪木さんは、1998-04-04引退試合でドン・フライを4分9秒グラウンドコブラツイストで破ったあとの引退セレモニーで次のように述べられています。

「わたしは色紙に、いつの日か闘魂という文字を書くようになりました。それを称して、ある人が『燃える闘魂』と名づけてくれました。闘魂とは、己に打ち克つこと。そして、闘いを通じて己の魂を磨いていくことだと思います」

闘魂とは、己に打ち克つこと。そして、闘いを通じて己の魂を磨いていくこと です。
将棋の大山康晴永世名人流に言うと、克己 です。
王陽明先生流に言うと、 山中の賊を破るは易く、心中の賊を破るは難し です。
稲盛和夫師流に言うと、 燃える闘魂 です。

この記事では、闘魂プログラミング をしてみます。
わたしは、Elixirで楽しみます。

闘魂とは、己に打ち克つこと。そして、闘いを通じて己の魂を磨いていくこと

闘魂プログラミング

関数を呼び出すときに、 "闘魂" を指定(注入)しないと動作しないようにします。
"闘魂" の指定を必須とします。

Elixirでの例を示します。

iex> Inoki.Enum.map(1..3, & &1 * 2)         
** (UndefinedFunctionError) function Inoki.Enum.map/2 is undefined or private. Did you mean:

      * map/3

    Inoki.Enum.map(1..3, #Function<42.3316493/1 in :erl_eval.expr/6>)
    iex:57: (file)

"闘魂" を指定(注入)しないので、エラーがでています。
"闘魂" を指定(注入)すると正しく動きます :tada::tada::tada:

Inoki.Enum.map(1..3, & &1 * 2, "闘魂")
[2, 4, 6]

関数の定義はどうなっているかというと、次のようになっています。

defmodule Inoki.Enum do
  def map(enumerable, fun, "闘魂"), do: Enum.map(enumerable, fun)
end

Enumモジュールをラップしているだけです。

第3引数に"闘魂"を必ず指定しないといけないわけです。
これを
$\huge{ストロングスタイル}$
といいます。

ウソデス

"闘魂"を指定(注入)しないと動かない関数をつくる

この記事のポイントです。一丁目一番地です。

全部手で書くのは辛いのでちょっと楽をします。
以下の2つを使います。

Module.__info__/1を使うと、関数の一覧が得られます。
たとえばEnumモジュールの場合は以下のような結果が得られます。

iex> Enum.__info__(:functions)
[
  all?: 1,
  all?: 2,
  any?: 1,
  any?: 2,
  at: 2,
  at: 3,
  ...
]

Code.eval_string/3は、文字列をElixirのコードとして解釈、実行してくれます。
たとえば、 "1 + 2" を実行してみます。

iex> Code.eval_string "1 + 2"
{3, []}

ここまで書けばカンのいい方はもうお分かりですよね。

必ず"闘魂"を指定する必要がある関数群で構成されたモジュールを文字列で作って、Code.eval_string/3を実行すればよいわけです。

無名関数にbintaという名前をつけてみます。
闘魂注入といえばやはりビンタです。

binta = fn mod ->
  short_mod = "#{mod}" |> String.split(".") |> Enum.at(-1)

  args = fn arity, add_args ->
    "#{1..arity//1 |> Enum.map(&"a#{&1}") |> Kernel.++(add_args) |> Enum.join(",")}"
  end

  funs =
    mod.__info__(:functions)
    |> Enum.map(fn {name, arity} ->
      """
      def #{name}(#{args.(arity, ["\"闘魂\""])}), do: #{short_mod}.#{name}(#{args.(arity, [])})
      """
    end)
    |> Enum.join("\n")

  """
  defmodule Inoki.#{short_mod} do
    #{funs}
  end
  """
  |> Code.eval_string()
end

使い方は、binta.(Enum)です。
Inoki.Enumモジュールが手に入ります。

iex> Inoki.Enum.map(0..2, & &1 + 1)
** (UndefinedFunctionError) function Inoki.Enum.map/2 is undefined or private. Did you mean:

      * map/3

    Inoki.Enum.map(0..2, #Function<42.3316493/1 in :erl_eval.expr/6>)
    iex:66: (file)

iex> Inoki.Enum.map(0..2, & &1 + 1, "闘魂")
[1, 2, 3]

説明が前後しますが以下のようなInoki.Enumモジュールの定義を文字列で作っています。

defmoudle Inoki.Enum do
  def all?(a1, "闘魂"), do: Enum.all?(a1)
  def all?(a1, a2, "闘魂"), do: Enum.all?(a1, a2)
  ...
  def map(a1, a2, "闘魂"), do: Enum.map(a1, a2)
  ...
end

できあがった文字列をCode.eval_string/3に渡して実行することで、Inoki.Enumモジュールが手に入るわけです。

闘魂プログラミングは何の役に立つのか?

役に立つことはありません。
趣味です。

否、役に立つことがあるかもしれません。

迂遠なようではありますが、有形無形になにかの役に立っているかもしれません。
少なくともわたしはこの記事を書くことを楽しみましたし、この記事がどなたか天才の頭脳を刺激して、すごいものがうみ出されるかもしれません。

楽しみです。ワクワクです。

闘魂は連鎖する!

1998-04-04、アントニオ猪木さんがドン・フライを4分9秒グラウンドコブラツイストで破った引退試合のあとで行われたセレモニーで、古舘伊知郎アナウンサーは次のように言いました。

闘う旅人、アントニオ猪木。
いま相手のいないリングに猪木はたった一人で佇んでいます。
おもえば38年におよぶプロレス人生。旅から旅への連続であり、そして猪木の精神も旅の連続であった。
安住の場所を嫌い、突き進んでは出口を求め、飛び出しては次なる場所に歩を進める。
どん底からの新日旗揚げ、世界王者とのストロングマッチ、大物日本人対決、格闘技世界一決定戦、IWGP、巌流島、人質解放、国会に卍固め、魔性のスリーパー。
決して人生に保険をかけることなく、その刹那、刹那を燃やし尽くせばよいという生き様。
猪木はこのあとの旅はどの方角に舵をとろうというのか。
一人ひとりのいま、ファンの胸には、どんな闘いの情景が映し出されているか。
猪木はすべての人間が内包している闘う魂をリング上で代演する宿命にあった。
我々は猪木が闘いの果てにみせる表情に己自身を投影させてきたのだ。
しかし、この瞬間をもって猪木はリングから姿を消す。
我々はどうやって今後、火を灯していけばいいのか。
物質に恵まれた世紀末、商業主義に踊る世紀末、情報が豊かでとても心が貧しい世の中、一人で闘うことを忘れかけた人々。
もう我々は闘魂に癒やされながら時代の砂漠をさまよってはいられない。
我々は今日をもって猪木から自立しなければいけない。
闘魂のかけらを携え、今度は我々が旅に出る番だ。
闘魂は連鎖する!

1943年2月20日、鶴見に生まれし一人の(おのこ)姓名猪木寛至闘魂の火種。
あなたを見続けることができたことを光栄におもいます。
燃える闘魂に感謝。
ありがとう! アントニオ猪木!


猪木さんの活躍がぎゅっと詰まっています。

闘魂を連鎖する!

わたしは「闘魂を連鎖させたい」とおもっています。
しかしながらわたしは、色紙を頼まれることはありません。

そこでインターネットの大地に、闘魂 を掘るように刻み込んでいるのです。
他には、年賀状に 闘魂 を揮毫しています。年賀状はチャンスが年に一回です。
「とうこん(闘魂)」と「とうこう(投稿)」は音にすると一字違いです。わたしは、記事を 闘魂 しています。話し言葉では、こっそり「とうこう」を「とうこん」と発しています。
他には自分が主催するコミュニティチャンネルに毎朝、 闘魂 を発信しています。
闘魂 を書く機会がないのなら、嘆く前に自分でその機会を作ればいいのです。これこそ 闘魂 です。己との闘いです。

スクリーンショット 2023-01-28 18.40.56.png

闘魂プログラミング をすると自然と、 闘魂 に接する機会が増えます。

闘魂とは、己に打ち克つこと。そして、闘いを通じて己の魂を磨いていくこと」を胸に刻みながら、闘魂プログラミングをしています。
こうした投稿(闘魂)が増えることが、闘魂が連鎖することにつながるとおもいます。
世界文化の進展に寄与するものとおもいます。

GoogleやOpenAIに、闘魂をたくさん学んでもらいましょう。

AtCoderを解く

問題はB - Shift onlyを解いてみます。
この問題は、「AtCoder Beginners Selection」、「AtCoder に登録したら次にやること ~ これだけ解けば十分闘える!過去問精選 10 問 ~」に取り上げられている問題です。

ちなみに、 闘える と書いてありますのは単なる偶然ではないとおもいます。競技プログラミングの本筋は、己との闘い、 闘魂 なのです。ランクが低い私が言うと全く説得力はありませんが、一言申し上げておきます。ランクは誇るものでもなく、ましてや卑下するものでもなく自分の位置を把握するための目安に過ぎないのです。大事なことは、 己の弱い心に打ち克つ ことにあるのです。

6
382253568 723152896 37802240 379425024 404894720 471526144

こういうインプットがある場合に、2行目の数字を2で割っていって奇数がでるまで何回割ることができるのかという問題です。

ふつうに解く

まずはふつうに解いてみます。

defmodule Main do
  def main do
    IO.read(:line)

    IO.read(:line)
    |> String.trim()
    |> String.split(" ")
    |> Enum.map(&String.to_integer/1)
    |> Enum.reduce_while(10_000_000_000, fn a, acc ->
      a
      |> do_solve(0)
      |> calc_new_acc(acc)
      |> calc_result()
    end)
    |> IO.puts()
  end

  defp do_solve(a, acc) when rem(a, 2) == 1, do: acc

  defp do_solve(a, acc), do: do_solve(div(a, 2), acc + 1)

  defp calc_new_acc(cnt, acc) when cnt < acc, do: cnt

  defp calc_new_acc(cnt, acc), do: acc

  defp calc_result(0), do: {:halt, 0}

  defp calc_result(acc), do: {:cont, acc}
end

AtCoderへの提出結果

スクリーンショット 2023-01-28 14.11.01.png

だいたい339msで実行して、全件パス:tada:しています!

闘魂プログラミングで解く

闘魂プログラミングで解いてみます。
意図した通り、ソースコード中に闘魂がたくさんでてきます。

defmodule Main do
  def main do
    binta = fn mod ->
      short_mod = "#{mod}" |> String.split(".") |> Enum.at(-1)

      args = fn arity, add_args ->
        "#{1..arity |> Enum.map(&"a#{&1}") |> Kernel.++(add_args) |> Enum.join(",")}"
      end

      funs =
        mod.__info__(:functions)
        |> Enum.map(fn {name, arity} ->
          """
          def #{name}(#{args.(arity, ["\"闘魂\""])}), do: #{short_mod}.#{name}(#{args.(arity, [])})
          """
        end)
        |> Enum.join("\n")

      """
      defmodule Inoki.#{short_mod} do
        #{funs}
      end
      """
      |> Code.eval_string()
    end

    binta.(IO)
    binta.(String)
    binta.(Enum)

    Inoki.IO.read(:line, "闘魂")

    Inoki.IO.read(:line, "闘魂")
    |> Inoki.String.trim("闘魂")
    |> Inoki.String.split(" ", "闘魂")
    |> Inoki.Enum.map(&Inoki.String.to_integer(&1, "闘魂"), "闘魂")
    |> Inoki.Enum.reduce_while(
      10_000_000_000,
      fn a, acc ->
        a
        |> do_solve(0, "闘魂")
        |> calc_new_acc(acc, "闘魂")
        |> calc_result("闘魂")
      end,
      "闘魂"
    )
    |> Inoki.IO.puts("闘魂")
  end

  defp do_solve(a, acc, "闘魂") when rem(a, 2) == 1, do: acc

  defp do_solve(a, acc, "闘魂"), do: do_solve(div(a, 2), acc + 1, "闘魂")

  defp calc_new_acc(cnt, acc, "闘魂") when cnt < acc, do: cnt

  defp calc_new_acc(cnt, acc, "闘魂"), do: acc

  defp calc_result(0, "闘魂"), do: {:halt, 0}

  defp calc_result(acc, "闘魂"), do: {:cont, acc}
end

AtCoderへの提出結果

スクリーンショット 2023-01-29 0.33.02.png

全件パス:tada:しています!
だいたい692msの実行時間がかかっています。
ふつうに解いたときとくらべておおよそ倍の実行時間がかかっています。
余計なことをしているからです。当然の結果です。

コードをよーくみますと、 Elixirで作った解答ソースコードは、 表現の中核として関数 が使われています。

感覚的なところです。ご自身でなにかを書いてみるとわかるとおもいます。


さいごに

闘魂プログラミングをわたしはElixirで楽しみました。

闘魂プログラミング の定義はありません。
各自の 闘魂 の数だけ 闘魂プログラミング があるのです。
そういうものです。

闘魂プログラミング の定義はありません。

わたしの場合はおおよそ以下の通りです。

  • ソースコードの中に闘魂ができるだけ多くでてくる
  • 闘魂 がないと本当に動かない箇所がある

競技プログラミングという時間に厳しい制約条件がある場面では、わたしの 闘魂プログラミング は邪魔でしかありませんし、非常に簡単な問題しか解いていませんが、AtCoderにも 闘魂 を刻みこむことができました。単なるコメントなどよりは多少意味があるものとして、 闘魂 をソースコードの中に登場させました。
世知辛い世の中ではありますが、たまにはこういうふうにのんびりコードと戯れるのもよいのではないでしょうか。

これからもインターネットの大地に、 闘魂 を掘るように刻み込み続けます!

ぜひみなさんも、お気に入りのプログラミング言語で 闘魂プログラミング をお楽しみください。

ぜひみなさんも、お気に入りのプログラミング言語で 闘魂プログラミング をお楽しみください。



おまけ

Thanks to: https://techblog.gmo-ap.jp/2021/06/15/text-visualization-wordcloud/

この記事を可視化してみました。

image.png


$\huge{元氣があればなんでもできる!}$

10
5
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
10
5