2021/11/30

ヒューマン・リソース・マシーン 入社30年目−隠された暗号

目次

1)課題

左側のいくつかのアドレス番号があります。

それが指す文字を1文字目とし、それに続く文字を「0」に遭遇するまで、全て右側に運んで下さい。

2)考え方

入社29年目で学んだ間接指定を使っていきます. 左のコンベアにあるパネルには一文字目のアドレスを書いてあります. 例えば, 左のコンベアのパネルが「4」であれば, カーペットの4番「T」の文字から右のコンベアに運べば, 上司の要求に応えられます. 手順は次のようになります.

  1. 左のコンベアからパネルを取り出し, カーペットの24番に置く. 
  2. 間接指定により, カーペット24番が示すパネルを取る.
  3. 取ったパネルが「0」なら先頭に戻る.
  4. 「0」でなければ, 持っているパネルを右のコンベアに運ぶ.
  5. カーペット24番を1増やす. 
  6. 2行目に戻り, カーペットの次のパネルを取る.

3)実装

カーペットの24番に「アドレス」と名前を付けます. 上で考えた手順をそのままプログラムに落とし込みます. 

見ての通り, そのままです. これを実行すると課題をクリアーできます.

サイズ目標, スピード目標共にクリアーできました.

目次

2021/11/27

ヒューマン・リソース・マシーン 入社29年目−間接的な指定

 目次

1)課題

左側の各数値は、カーペット上の番号を示しています。各番号の場所におかれている文字を取得し、右側に運んで下さい。

「データの間接指定」が出来るようになりました。下記の例を実行して、直接していとの違いを感じてみましょう。

2)解説

この課題では, カーペットの12番に対して2種類のCOPYFROMを配置しています. ステップ実行してみます. 

2行目のCOPYFROMコマンドを実行すると, カーペットの12番に置いてあるパネルの値をカーペットの番号とみなして, カーペットの8番に置いてあるパネルを取ります. これが, 「データの間接指定」と呼ばれる理由です.

この結果を使って課題に取り組みます. 手順としては次のようになります.

  1. INBOXコマンドを使って左のコンベアからパネルを取り出し, カーペットの12番に置く. 
  2. COPYFROMコマンドを「間接指定」でカーペットの12番に対して実行する. 
  3. OUTBOXコマンドを使ってパネルを右のコンベアに運ぶ. 

この通りにプログラムを作ってみました. これを実行すると課題をクリアーできます. 

3)間接指定の注意事項

間接指定をする場合, 上司に怒られないように細心の注意が必要となります.

間接指定である/なしにかかわらず, パネルを置いていないカーペットを指定すると上司に怒られます.

間接指定の場合, 数値以外のパネルを置いてあるカーペットを指定しても上司に怒られます.

カーペットの12番に置いてあった8を使って16に増やしました. カーペットは0番から14番までしかありません. その範囲外を指定しても上司に怒られます. 実務でこういうことをやらかすと対応が難しいので注意が必要です. 「注意しましょう」で解決するなら苦労はしません. 実務での解決法については, 別の機会に. 

目次

2021/11/23

ヒューマン・リソース・マシーン 入社28年目−小から大へ

 目次

1)課題

左側の数値3つごとに対し、小さい順に並べ替え、右側に運んで下さい。

2)考え方

3つの数値をA, B, Cとします. 3つの数値の大小関係を調べ, 条件分岐をしていきます.

(1)A<Bの時

A<CならAが最小となる. B<Cなら小さい方からA, B, Cの順になり, C<BならA, C, Bの順になる.

C<AならCが最小となり, 小さい方からC, A, Bの順になる.

(2)B<Aの時

B<CならBが最小となる. A<Cなら小さい方からB, A, Cの順になり, C<AならB, C, Aの順になる.

C<BならCが最小となり, 小さい方からC, B, Aの順になる.

3)もう一工夫

これをそのままコードに落とし込んでいっても良いのですが, コードの見通しが悪くなり, うまく動かないときの対応が難しくなります. そこで, BとCを比較し, C<Bなら, BとCを入れ替えます. つまり, 必ずB<Cであることにして, Aとの比較を考えます. 

(1)A<Bの時

Aが最小となり, B<Cであるから, 小さい方からA, B, Cの順になる.

(2)B<Aの時

Bが最小となる. A<Cなら小さい方からB, A, Cの順になり, C<AならB, C, Aの順になる.

B<Cを保証することで, 大小を比較する回数を減らすことができました. 

4)実装

問題文には予め, 左のコンベアから3枚のパネルを取り出し, カーペットの0番から2番に配置するコードを書いてあります. ここからスタートしていきます. 

まず, カーペットの0番に「A」, 1番に「B」, 2番に「C」,3番に「SWAP」と名前を付けます. C<Bの場合, 「SWAP」と名前を付けたカーペットを使って, BとCのパネルを入れ替えます. ステップ実行して, B<Cの順になることを確認します.

続けてAとBを比較します. 比較結果から, 最小となる値が決まりますので, 最小のパネルを右のコンベアに運びます. なお, 問題文では「小さい順に並び替え」と書いてありますが, 上司は右のコンベアに運んだパネルしか見ていませんので, 放っておいて大丈夫です.

続けて, 分かりやすい方を片付けます. Aが最小と分かれば, 小さい順にA, B, Cと並びますので, その順に右のコンベアに運びます. 25行目のJUMPコマンドは先頭にジャンプさせています. 

次に, Bが最小の場合を考えていきます. まず, 残りのAとCを比較します. 小さい方のパネルを右のコンベアに運ぶところまでコードを書いて, 動作を確認します.

残るは最大のパネルを右のコンベアに運ぶだけです. 35行目と40行目のJUMPコマンドは先頭に戻っています. ここまでできれば, 課題をクリアーできます. 

分かりやすさを優先しましたので, サイズ目標, スピード目標共に達成できていません. 達成するためには, OUTBOXコマンドの使用回数を減らすところから取り掛かると思います. これについては, 原稿を改めます.

目次

2021/11/20

ヒューマン・リソース・マシーン 入社26年目−割り算のしかた

目次

1)課題

左側の数値2つ(A, B)ごとに割り算(A÷B)を行い、その商を右側へ運んで下さい。

ただし、2つ目の数字に0が来る事は無いものとする。

TIPS: 前の課題で書いたコードを「コピー&はりつける」で持ってくると手間が省けて便利かもしれません。

2)解説

入社24年目で, 割り算をした余りを求めました. この課題では, 余りではなく商, つまりAからBを何回引けるか, を求めます. まず, 問題文にもあるように, 入社24年目で作成したコードをコピーして貼り付けます. 

入社24年目からコードをコピーして貼り付けました. ここからプログラムを改造していきます.

  1. 初期設定する時, 商を表すカーペットに0を配置します. このカーペットに「Q」と名前を付けます.
  2. 「A-B」の結果がプラスであれば, 「Q」を1増やします. つまりBUMP+コマンドを使います. JUMPコマンドで引き算に戻る時, 「A」のパネルに持ち替えることに注意してください.
  3. 「A-B」の結果がマイナスであれば, 「Q」の値を右のコンベアに運びます.

コードを修正するとこのようになります. これを実行すると課題をクリアーできます.

サイズ目標まであと1行です. 簡単に修正できますが, このままにしておきます. スピード目標については, 入社24年目と同様に達成できてしまいました. 開発元がどのような想定でプログラムを作成したのか気になります.

目次 

2021/11/18

ヒューマン・リソース・マシーン 入社25年目−ゼロまで足して

目次

1)課題

左の各数値に対して、0までのカウントダウンを行い、自身を含めたすべての数値を加算した結果を出力せよ。

例えば左の数値が3である場合、右に運ぶ数値は6(=3+2+1)になります。

2)考え方

ここまでの課題をクリアーすれば, 次のような考えが浮かんでくると思います.

  1. 左のコンベアから取ったパネルを1つずつ減らし, その都度, 答えを書いてあるカーペットに足し込んでいけばよい.
  2. 左のコンベアから取ったパネルと答えのパネルをカーペットに保存する場所を用意しておく.
  3. 当然, 答えのパネルは0に初期化しておく.

これぐらい思いつけば, コマンドを並べて試行錯誤することで課題をクリアーできるでしょう. ここでは, もう少し落ち着いて考えていきます.

ここで, 総和を求める関数Sを考えます. 例を挙げます. 

S(3) = 3 + 2 + 1
S(5) = 5 + 4 + 3 + 2 + 1

「関数S」などと書いてあると苦い経験を思い出されるかもしれませんが, 1からSに続く数字までの和を計算するすることを表す, 程度に考えてください.

さて, S(3)を例にしてもう少し考えます. S(3)は3+2+1ですが, 2+1はS(2)に相当します. ですから, S(3)は次のようにも書けます.

S(3) = 3 + S(2)

同じようにして, S(2)=2+1ですが, S(2)=2+S(1)と書けます. また, S(1)=1です. これらをまとめると次のようになります.

S(3) = 3 + S(2)
S(3) = 3 + 2 + S(1)
S(3) = 3 + 2 + 1

式を変形する途中で, できる足し算は片付けてしまいます.

S(3) = 3 + S(2)
S(3) = 5 + S(1)
S(3) = 6

ヒューマン・リソース・マシーンのプログラムにするため, もう少し式に手を加えます. 

S(3) = 0 + S(3)
S(3) = 3 + S(2)
S(3) = 5 + S(1)
S(3) = 6 + S(0)

右辺の1つ目の項をカーペットの「こたえ」に, 2つ目の項をカーペットの「S」に割り当てれば, プログラムをつくれます. 

3)プログラムを作る

プログラムを作っていきます.

計算するための準備をします. 所謂, 初期化です. 「こたえ」に0を配置し, 「S」に左のコンベアから取り出したパネルを配置します.

左のコンベアから取り出し, 「S」に配置したパネルを「こたえ」に足し込みつつ, 「S」を1つずつ減らしています. 左のコンベアから取り出したパネルが3でしたので, 「S」が0になった時に「こたえ」が6になっており, 期待通りの結果が得られました. 「S」が0になった時, 「こたえ」を右のコンベアに運べば上司の要求に応えられます.

9行目にJUMP if zeroコマンドを追加して, 「S」が0になった時に「こたえ」を右のコンベアに運ぶようにしました. うまく計算できているようですが, 図では「S」が-1となっています. 0ではありませんので, 無限ループに入ってしまいます.

9行目をJUMP if zeroコマンドからJUMP if negativeコマンドに変更し, 無限ループを回避します. また, この変更により, 「こたえ」に0を加えることになりますが, 結果に変わりはありませんのでこのままとします. 

課題をクリアーできました. スピード目標を達成するためには, 左のコンベアから取り出したパネルが0の時, そのまま右のコンベアに運ぶ, といった工夫が必要です.

目次

2021/11/16

ヒューマン・リソース・マシーン 入社24年目−あまりはいくつ?

1)課題

左側の数値2つ(A, B)ごとに割り算(A÷B)を行い、その剰余(あまり)を右側へ運んで下さい。実際に割り算をする必要はありません。割り算の意味を改めて考えてみましょう。

この課題ではマイナス値は出ません。また、2つ目の数字に0が来る事はありません。

2)解説

入社20年目で掛け算をしました. A×Bを計算するために, 0から始めて, AをB回加えました. この課題ではA÷Bを行い, 余りを求めます. 考え方としては, 掛け算と逆にAからBを引き続ければ答えに近づけそうです. まず, 例として8÷3を考えてみます. 

「A」に8, 「B」に3を配置し, 「A」から「B」を引いた結果を「A」に配置していきます.

  A  B
  8 3
  5 3
  2 3
 ―1 3

4行目で「A」が負の数となりました. 8÷3の余りは2ですから, 4行目の一つ上にある3行目の「A」の値2が求める答えです. プログラムでは, 「Aがマイナスになる一つ手前」とは言えません. 代わりに, 「AがマイナスになったらBを加え, その結果が求める余り」とします. 

問題文にあるように, 負の数や「B」が0となることはありませんので, これ以上, 考える必要は無さそうです. この考えに従いプログラムを作ります.

1行目から4行目で, 左のコンベアから取ったパネルをカーペットに配置しています. 5行目と6行目で「A-B」を計算し, 結果がマイナスになったか判定しています. マイナスの場合, 10行目にジャンプし, 「B」の値を加えて右のコンベアに運びます. マイナスでない場合, 8行目で引き算した結果を「A」にコピーして, 6行目に戻ります. このプログラムを実行すると課題をクリアーできます.

サイズ目標, スピード目標共に達成できました. プログラムを最適化すると, これらの目標を下回ることができます.

目次

2021/11/13

ヒューマン・リソース・マシーン 入社23年目−一番小さいのは?

目次

1)課題

複数の「0区切り文字列」が置かれています。

各文字列の内から一番小さい数字を右側に運んで下さい。ただし、各文字列は少なくとも1つの数値を含むものとする。

2)大小の比較

この課題を解くためには, 2枚のパネルの大小を比較する方法が必要です. SUBコマンドとJUMP if negativeコマンドを組み合わせれば, パネルの大小を比較できます.

SUBコマンドを使うと, 持っているパネルからカーペットのパネルを引いた結果が得られます. 引いた結果がマイナス値であれば, 持っていたパネルがカーペットのパネルより小さいと言えます. 

3)一番小さいのは?

上司の要求は, 「一番小さい数字」です. 一番小さい数字を求めるために, 「チャンピオン」と「チャレンジャー」を用意します. 「チャレンジャー」を「チャンピオン」に挑ませ, 「チャレンジャー」が勝てば次の「チャンピオン」になり, 最後に「チャンピオン」であった者が真の「チャンピオン」です. この考え方を整理します.

  1. 「チャンピオン」と書いたカーペットには, 左のコンベアの先頭のパネルを置きます.「チャンピオン」と書いてありますが, あくまでも暫定王者です.
  2. 左のコンベアからパネルを取り出し, 「チャレンジャー」と書いたカーペットに置きます. 
  3. 「チャンピオン」と「チャレンジャー」のどちらが小さいかを比較します. 
  4. 「チャンピオン」の方が小さければ, そのまま左のコンベアから次の「チャレンジャー」を取り出し,比較します.
  5. 「チャレンジャー」の方が小さければ, 「チャレンジャー」が新しい「チャンピオン」になります.
  6. 0と書いたパネルを取り出せば, そこで終了です. 「チャンピオン」を右のコンベアに運びます.

少しずつ作っていきます. まずは, 大小を比較するところまでコードを書いてみました. 図のコードは, 「チャレンジャー」-「チャンピオン」を計算します. 

SUBコマンドに続けて, JUMP if negativeコマンドを入れました. SUBコマンドの結果がマイナス値であれば, 「チャンピオン」を交代させます. マイナス値でなければ, JUMPコマンドを使って次の「チャレンジャー」を呼び出します. 

図は, 左のコンベアから0と書いたパネルを取り出したところです. 0は「区切り文字」ですから「チャレンジャー」ではありません. 

4行目のJUMP if zeroコマンドにより, 0の場合は12行目にジャンプさせ, 「チャンピオン」を右のコンベアに運びます. 14行目のJUMPコマンドの先が画面に入っていませんが, 先頭に戻っています. 

サイズ目標とスピード目標まで, もう少しのようです. これらの目標を達成するためには, プログラムの読みやすさを犠牲にしなくてはなりません. 記事を改めて解説します.

目次

2021/11/12

ヒューマン・リソース・マシーン 入社22年目−フィボナッチ数列

1)課題

左側の数値に対し、それ自身を超える直前までのフィボナッチ数列を右側に運んで下さい。

例えば、入力が10である場合、出力は1 1 2 3 5 8となります。

フィボナッチ数列に関する詳しい話は、そこで見ている上司にきいてみましょう。

2)アルゴリズム

問題文と上司に教えてもらったことから, フィボナッチ数は次のように計算できます.

1+1=2
  1+2=3
    2+3=5
      3+5=8
        5+8=13


字下げを取り除いて表の形式にし, 各列にラベルを付けます.

A B C
1+1=2
1+2=3
2+3=5
3+5=8
5+8=13

この結果から, カーペットに置いたパネルの動かし方が分かります.

次に, 上司に解答例を示してもらいます.

解答例では, 始めに「1, 1, 」と出力しています. これも考慮に入れて計算手順を見直します. 

A B C
0+1=1
1+1=2
1+2=3
2+3=5
3+5=8
5+8=13

0と1を加えることから始めると, 「1」を出力する見通しが立ちました. 

更にカーペットの初期状態も含めて考えます. 「+」や「=」の記号を取り除き, カーペットの数値の変化に注目できるようにします.

A B C
0 0 1
0 1 1
1 1 2
1 2 3
2 3 5
3 5 8

1行目から2行目, 2行目から3行目へと移る時, 次の操作をします.

  1. 「C」を右のコンベアに運ぶ.
  2. 「B」から「A」にコピーする.
  3. 「C」から「B」にコピーする.
  4. 「A」と「B」を加えた結果を「C」にコピーする.

Cの値が左のコンベアから取り出したパネルの値を超えたところで終了です. 

3)実装

上で考えたアルゴリズムを使ってプログラムを作ります.

始めに, カーペットを初期化します. カーペットに名前を付け, パネルを配置します. 

プログラムの本体に取り掛かります. プログラムの流れは次のようになります.

  1. 「上限」と「C」を比較します.
  2. 「C」の方が大きければ先頭に戻ります.
  3. 「上限」の方が大きければ, 「C」を出力します. 続けて「B」を「A」に, 「C」を「B」にコピーし, コピー後の「A」と「B」を加えた結果を「C」にコピーします. 
  4. 先頭に戻ります.

この流れに沿って, プログラムを作ります.

10行目のJUMP if negativeコマンドは, 「上限」から「C」を引いた値が負であれば先頭に戻っています. 11行目以降で, 「C」を右のコンベアに運び, 次のフィボナッチ数を求めるための処理を記述しています. これを実行すると課題をクリアーできます.

サイズ目標を達成できていました. スピード目標を達成するためにはまだまだ工夫が必要です.

2021/11/06

ヒューマン・リソース・マシーン 入社21年目−ゼロが区切り

目次

1)課題

左側にいくつかの「0で終わる数値グループ」が置いてあります。

各グループ内の数値の合計値を算出し、右側に運んで下さい。

2)解説

左のコンベアからパネルを取り出し, 0と書いたパネルを取るまでパネルの値を足し込んでいけば, 上司の要求に応えられます. 手順を考えてみます.

  1. 入社20 年目の「掛け算のしかた」と同じように, パネルの値を足し込むためのカーペットが必要です. カーペットのラベルに「こたえ」と書いておきます.
  2. 「こたえ」は, 0から始める必要があります. カーペットの5番に0があるので, これをコピーします.
  3. 左のコンベアからパネルとカーペットの「こたえ」に置いてあるパネルを足します. 足した結果を「こたえ」にコピーします.

ここまで考えた内容でプログラムを作ってみました. これを実行すると, 左のコンベアからパネルを取り出し, 「こたえ」に足し続ける様子を観察できます. 

このプログラムでは, 左のコンベアのパネルがなくなるまで繰り返し, 右のコンベアにパネルを運びませんので, 上司の要求に応えられていません. 左のコンベアから取ったパネルが0の場合の対応を考えます. 左のコンベアから取ったパネルが0であれば, 問題文にある「数値グループ」が終わったということです. カーペットの「こたえ」には, 「数値グループ」のパネルを足した結果となっています. これを右のコンベアに運べば, 上司の要求に応えられます.

INBOXコマンドを使って左のコンベアからパネルを取った直後に, 0であるか判定します. 0であれば, カーペットの「こたえ」においてあるパネルを取り, 右のコンベアに運びます. 運び終われば, 最初に戻って次の「数値グループ」の合計を求めます. 

プログラムを実行するとクリアーできます. スピード目標については, 記事を改めて解説します.

目次

ヒューマン・リソース・マシーン 入社41年目−並べ替えよ

目次 1)課題 0を終端とした文字列がいくつか流れてきます。各文字列に対してソート(並べ替え)を行い、小さい順(昇順)に右側へ運んでください。 2)状況の確認 この問題では, 予めコードが入っています. このコードを実行して, 何をするコードなのか確かめます.  左のコンベアから...