【Ruby】🏡THE HOUSE OF THE DEAD CODE🧟🧟‍♀️🧟‍♂️

この記事は  **[闇の魔術に対する防衛術 Advent Calendar 2020](https://qiita.com/advent-calendar/2020/yaminomajutu)** の24日目の記事です。


明日、最終日はカレンダーの作成者でもある **@nfujita55a** さんの **よく知らないアプリケーションの性能と戦わないといけないときの防衛術（後編）** です！！


---

# THE HOUSE OF THE DEAD CODE

標示されるrubyのコードから、 **デッドコードとなっている `Am I dead?` 部分を、制限時間内に全てクリック** してください。

コードは、**ruby 2.7.2** で **`ruby` コマンドで起動** されるものとします。

<p class="codepen" data-height="480" data-theme-id="light" data-default-tab="result" data-user="j5c8k6m8" data-slug-hash="PoGJxmE" style="height: 480px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;" data-pen-title="HODC【Ruby】">
  <span>See the Pen <a href="https://codepen.io/j5c8k6m8/pen/PoGJxmE">
  HODC【Ruby】</a> by j5c8k6m8 (<a href="https://codepen.io/j5c8k6m8">@j5c8k6m8</a>)
  on <a href="https://codepen.io">CodePen</a>.</span>
</p>
<script async src="https://cpwebassets.codepen.io/assets/embed/ei.js"></script>

**<font color="red">私の環境ではCodePenの埋め込みが動きませんでした。CodePenの埋め込みが動かない場合は、下記のリンクから参照してください</font>**
**https://codepen.io/j5c8k6m8/full/PoGJxmE**

# 作成経緯など

**[闇の魔術に対する防衛術 Advent Calendar 2020](https://qiita.com/advent-calendar/2020/yaminomajutu)** の１日目の記事 **[DEAD CODE COOKBOOK ~デッドコードの作り方と復活の呪文~ の紹介](https://qiita.com/j5c8k6m8/items/0f0596845b63e3b32d7d)** 執筆時に、**THE HOUSE OF THE DEAD CODE** というタイトルを思い付いたので、勢いで24日目にエントリーしました。

当初は、様々なデッドコードを含んだコードを単純に掲載しようと考えていましたが、 **The Typing of the Dead** のようなゲーム要素を入れても楽しいかなー？と思いながら、何もせずに、あっという間に２日前となってしまいました:frowning2:

とにかく形にしたい！ただ、コードのハイライトだけは死守しようと考え、CDNでの prism.js 利用を前提として考えました。

時間もないし、CDNだし、ハイライト変換後のDOM操作必要だし、 ~~オワコンの~~ jQuery 使っちゃえ！と、ライブラリはシンプルに prism.js + jQuery だけで作りました。

結果、「4時間程度で作れたし、jsは86行だし、クイズとしても楽しいし、まぁ、いいな。文字列に `"` 使う言語なら HTML 書くだけで簡単に問題作れるから、 **[GitHub](https://github.com/j5c8k6m8/HODC/tree/v0.0.3)** に入れておくか。」という適当コードです。

<details><summary>ゲーム部分のコードを見る</summary><div>

```js:HODC.js
setTimeout(() => {
const pages = {};
let current_page, current_zombies;
let current_id = 0;
const start = i => {
  current_page = i;
  current_id += 1;
  if (pages[i]) {
    $('pre.active').removeClass('active');
    $("#stage-num").html(i);
    $("#stage-time").html(pages[i]['time']);
    current_zombies = pages[i]['zombies'].concat();
    current_num = current_zombies.length;
    $('pre.stage').addClass('active');
    setTimeout(() => {
      $('pre.active').removeClass('active');
      $(`[data-page="${i}"]`).addClass('active');
      const action_id = current_id;
      setTimeout(() => {
        if (action_id === current_id && current_zombies.length > 0) {
          current_id += 1;
          $('pre.active').removeClass('active');
          $('pre.dead').addClass('active');
        }
      }, pages[i]['time'] * 1000);
    }, 1500);
  } else {
    $('pre.active').removeClass('active');
    $('pre.complete').addClass('active');
  }
}
$('[data-page]').each(function() {
  pages[Number($(this).attr('data-page'))] = {
    zombies: $(this).attr('data-zombie').split(',').map( s => `"${s} Am I dead?"`),
    time: Number($(this).attr('data-time')),
  };
  $(this).find('span.token.string').each(function() {
    if (/⭕"$/.test($(this).html())) {
      $(this).html($(this).html().replace("⭕", "Am I dead?"))
      $(this).click(function () {
        const action_id = current_id;
        const s = $(this).html();
        if (/Am I dead\?"$/.test(s)) {
          const i = current_zombies.indexOf(s)
          if (i > -1) {
            current_zombies.splice(i, 1);
            const $this = $(this);
            $this.attr('data-org-code', $(this).html());
            $this.html('"🧟"');
            setTimeout(() => {
              if (action_id === current_id) { // 2週目の考慮はしない
                if ($this.html() === '"🧟"') {
                  $this.html('"☠"');
                  setTimeout(() => {
                    if (action_id === current_id) { // 2週目の考慮はしない
                      current_num += -1;
                      if (current_num === 0) {
                        start(current_page + 1);
                      }
                    }
                  }, 400);
                }
              }
            }, 400);
          } else {
            current_id += 1;
            $('pre.active').removeClass('active');
            $('pre.miss').addClass('active');
          }
        }
      });
    }
  });
});
$(".retry").click(function() {
  $('pre.active').removeClass('active');
  $('pre.top').addClass('active');
});
$("#start").click(function() {
  $('[data-org-code]').each(function() {
    $(this).html($(this).attr('data-org-code'))
  });
  start(1)
});
$('pre.top').addClass('active');
}, 1000); // prism.jsのマークアップを待受
```

```css:HODC.css
body {
  width :320px;
}
pre {
  display: none;
}
pre.active {
  display: block;
}
.top,.stage,.dead,.miss,.complete {
  text-align: center;
}
button {
  margin-top: 18px;
}
span {
  touch-action: manipulation;
}
```
</div>


動作保証はしませんが、以下のような HTML のみで簡単に問題作れます。

<details><summary>本問題の HTML を見る</summary><div>

```html
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>HODC【Ruby】</title>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/prism/1.22.0/themes/prism.min.css" integrity="sha512-tN7Ec6zAFaVSG3TpNAKtk4DOHNpSwKHxxrsiw4GHKESGPs5njn/0sMCUMl2svV4wo4BK/rCP7juYz+zx+l6oeQ==" crossorigin="anonymous" />
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/prism/1.22.0/themes/prism-twilight.min.css" integrity="sha512-akb4nfKzpmhujLUyollw5waBPeohuVf0Z5+cL+4Ngc4Db+V8szzx6ZTujguFjpmD076W8LImVIbOblmQ+vZMKA==" crossorigin="anonymous" />
<link rel="stylesheet" href="https://cdn.jsdelivr.net/gh/j5c8k6m8/HODC@v0.0.2/HODC.css"/>
</head>
<body>
<pre class="top" style="padding-top: 20px;">
  <span style="font-size: 24px;">THE</span><span style="font-size: 40px;margin-left: 4px">HOUSE</span><span style="font-size: 32px;margin:10px;">OF</span><span style="font-size: 24px;">THE</span><span style="font-size: 40px;margin-left: 4px;margin-right:18px;">DEAD</span>
  <span style="font-size: 36px;line-height: 40px;">CODE</span>
  <span style="font-size: 24px;line-height: 40px;">【Ruby】</span>
  <button id="start" type="button">START 🏡</button>
  <span style="font-size: 18px;line-height: 60px;"> 遊び方: DEAD CODEをクリックしよう </span>
</pre>
<pre class="stage" style="font-size: 24px; padding-top: 80px;">
  ROOM <span id="stage-num"></span>
  (制限時間 <span id="stage-time"></span> 秒)
</pre>
<pre class="complete" style="padding-top: 80px;">
  <span style="font-size:30px;">🎉 Congratulations! 🎉</span>
  <button class="retry" type="button">リトライ</button>
</pre>
<pre class="dead" style="padding-top: 80px;">
  <span style="font-size:30px;">🧟 Time Out! 🧟</span>
  <button class="retry" type="button">リトライ</button>
</pre>
<pre class="miss" style="padding-top: 80px;">
  <span style="font-size:30px;">👮 Miss Shot! 👮</span>
  <button class="retry" type="button">リトライ</button>
</pre>
<pre data-page="1", data-zombie="🙍🏾‍♂️" data-time="5">
  <code class="language-rb">
puts "🙎‍♂️ ⭕"
return
puts "🙍🏾‍♂️ ⭕"
  </code>
</pre>
<pre data-page="2", data-zombie="🙅🏽‍♂️" data-time="10">
  <code class="language-rb">
3.times do |i|
  case i
  when 1,2 then
    puts "💁🏼‍♀️ ⭕"
  when 3 then
    puts "🙅🏽‍♂️ ⭕"
  else
    puts "🤦🏽 ⭕"
  end
end
  </code>
</pre>
<pre data-page="3", data-zombie="🤷🏽‍♀️,🙍🏻‍♂️" data-time="10">
  <code class="language-rb">
def add a, b
  puts "🤷🏽‍♀️ ⭕"
  return a + b
  puts "🙍🏻‍♂️ ⭕"
end

puts 3 + 5
puts "🙅🏽‍♂️ ⭕"
  </code>
</pre>
<pre data-page="4", data-zombie="👨🏼‍🎓" data-time="10">
  <code class="language-rb">
3.times do |i|
  if i % 2 == 0
    unless i % 3 == 0
      puts "👩🏾‍🌾 ⭕"
    end
    if i % 3 == 1
      puts "👨🏼‍🎓 ⭕"
    end
  end
end
  </code>
</pre>
<pre data-page="5", data-zombie="👨🏽‍🏭,👨🏻‍🏫" data-time="10">
  <code class="language-rb">
if false
  puts "👨🏽‍🏭 ⭕"
end
if 0
  puts "👨🏿‍🚀 ⭕"
end
if ""
  puts "👨‍🍳 ⭕"
end
if nil
  puts "👨🏻‍🏫 ⭕"
end
  </code>
</pre>
<pre data-page="6", data-zombie="👩‍👩‍👧,👩🏾‍🤝‍👨🏻,👩‍👦,👩🏼‍🤝‍👨🏿" data-time="20">
  <code class="language-rb">
while true do
  puts "👨‍👨‍👦 ⭕"
  for num in 1..3 do
    puts "👩🏼‍🤝‍👨🏻 ⭕"
      until false do
        puts "👨🏿‍🤝‍👨🏼 ⭕"
      end
      puts "👩‍👩‍👧 ⭕"
    continue
    puts "👩🏾‍🤝‍👨🏻 ⭕"
  end
puts "👩‍👦 ⭕"
end
puts "👩🏼‍🤝‍👨🏿 ⭕"
  </code>
</pre>
<pre data-page="7", data-zombie="🧘🏼‍♂️,🏌🏽‍♀️,🏋" data-time="15">
  <code class="language-rb">
def a
  puts "🤸🏾 ⭕"
  b
  c
  puts "🧘🏼‍♂️ ⭕"
end
def b
  puts "🤾🏻‍♂️ ⭕"
  c
  puts "🤹🏼‍♂️ ⭕"
  a
  puts "🏌🏽‍♀️ ⭕"
end
def c
  puts "🏋🏾 ⭕"
end
a
puts "🏋 ⭕"
  </code>
</pre>
<pre data-page="8", data-zombie="🦹🏿‍♀️,🧝🏽" data-time="10">
  <code class="language-rb">
def a
  puts "🦸🏻‍♂️ ⭕"
  yield
  puts "🧙🏼‍♀️ ⭕"
end
def b
  puts "🦹🏽‍♂️ ⭕"
  yield
  puts "🦹🏿‍♀️ ⭕"
end

a do
  puts "🧙🏼‍♂️ ⭕"
end
b do
  puts "🦸🏿 ⭕"
  break
  puts "🧝🏽 ⭕"
end
  </code>
</pre>
<pre data-page="9", data-zombie="🐴,🐖,🐫" data-time="30">
  <code class="language-rb">
puts [*1..3].filter{ |x|
  puts "🐕 ⭕"
  x % 2 == 1
}.filter{ |x|
  puts "🐈 ⭕"
  x % 3 == 2
}.filter{ |x|
  puts "🐴 ⭕"
  x % 4 == 3
}.any? { |x|
  puts "🐖 ⭕"
  x % 4 == 3
}&.tap {
  puts "🐏 ⭕"
} ? "🐫 ⭕"
  : "🐘 ⭕"
  </code>
</pre>
<pre data-page="10", data-zombie="🦸🏽" data-time="6">
  <code class="language-rb">
def raise
  puts "👨‍💻 ⭕"
end

begin
  puts "🐅 ⭕"
  raise
  puts "🙇 ⭕"
rescue RuntimeError
  puts "🦸🏽 ⭕"
end
  </code>
</pre>
<script src="https://code.jquery.com/jquery-3.5.1.min.js" integrity="sha256-9/aliU8dGd2tb6OSsuzixeV4y/faTqgFtohetphbbj0=" crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/prism/1.22.0/components/prism-core.min.js" integrity="sha512-hqRrGU7ys5tkcqxx5FIZTBb7PkO2o3mU6U5+qB9b55kgMlBUT4J2wPwQfMCxeJW1fC8pBxuatxoH//z0FInhrA==" crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/prism/1.22.0/plugins/autoloader/prism-autoloader.min.js" integrity="sha512-Q3qGP1uJL/B0sEmu57PKXjCirgPKMbg73OLRbTJ6lfHCVU5zkHqmcTI5EV2fSoPV1MHdKsCBE7m/aS6q0pPjRQ==" crossorigin="anonymous"></script>
<script src="https://cdn.jsdelivr.net/gh/j5c8k6m8/HODC@v0.0.2/HODC.js"></script>
</body>
</html>

```
</div>

デッドコードを制限時間内に見つけるゲームって、プログラミング教育が求められている今、ポテンシャルがありそうだから、~~SEGAさん~~ 誰かがちゃんとしたのを作ってくれないかなー。~~他人任せ~~

# おわりに

実は、アドベントカレンダー期間は毎日 **[デッドコードクックブック](https://zenn.dev/j5c8k6m8/books/dead-code-cookbook)** を更新する予定でしたが、途中で挫折しました。(今後、継続的に更新していく予定です。。)
~~**[闇の魔術に対する防衛術 Advent Calendar 2020](https://qiita.com/advent-calendar/2020/yaminomajutu)**には結局6個のポエムを書いた~~

くよくよしても仕方がないので、 **ruby3.0というクリスマスプレゼント** がもらえる明日を楽しみに待つ！