演習 6 上の例題をそのまま動かして確認しなさい。OK なら、次のことをやってみなさい。
- a. 数の配列を受け取り、その全ての値を 1 ずつ増やす。
- b. 数の配列を受け取り、正の要素だけ 1 ずつ増やす。
- c. 長さが偶数の配列を受け取り、前半と後半を入れ換える (例: 1, 2, 3, 4 → 3, 4, 1, 2)。
- d. 数の配列を受け取り、「小さい順」に並べる (例: 4, 11, 5, 1 → 1, 4, 5, 11)。
演習 8 配列を使った面白いと思うプログラムを作りなさい。
前回同様に、 Vec は各演算子を再定義することで、後から数字を指定できるようになります。
今回作成した Vec class のコードについては最後に記載しました。
Vec a ~ d では、_ 変数を引数のように扱うことで、演習 a ~ d までの式をつくりました。
Vec x ~ w は各方向の単位 Vector を <=> 演算子で指定して、Vec a に全て足しました。
.map は、値 v と index の i から、新しい Vec object がつくられます。
その他、 .size や .sort などよく使われそうな機能を作成しました。
以上から、 a ~ d のコード は以下のようになります。
_, x, y, z, w = (0..4).map do Vec.new end
a = _ + x + y + z + w
b = _.map(->v, i{v > 0 ? v + 1 : v})
c = _.map(->v, i{_[(i - _.size / 2).to_i % _.size]})
d = _.sort
x <=> [1, 0, 0, 0]
y <=> [0, 1, 0, 0]
z <=> [0, 0, 1, 0]
w <=> [0, 0, 0, 1]
puts " _ \t\t\t| a \t\t\t| b \t\t\t| c \t\t\t| d"
puts " :- \t\t\t| :- \t\t\t| :- \t\t\t| :- \t\t\t| :-"
(-3..3).map do |i|
_ <=> [0, 1, i, -i]
puts " #{_} \t| #{a} \t| #{b} \t| #{c} \t| #{d}"
end
実行結果は以下のようになりました。
| _ | a | b | c | d |
|---|---|---|---|---|
| [0, 1, -3, 3] | [1, 2, -2, 4] | [0, 2, -3, 4] | [-3, 3, 0, 1] | [-3, 0, 1, 3] |
| [0, 1, -2, 2] | [1, 2, -1, 3] | [0, 2, -2, 3] | [-2, 2, 0, 1] | [-2, 0, 1, 2] |
| [0, 1, -1, 1] | [1, 2, 0, 2] | [0, 2, -1, 2] | [-1, 1, 0, 1] | [-1, 0, 1, 1] |
| [0, 1, 0, 0] | [1, 2, 1, 1] | [0, 2, 0, 0] | [0, 0, 0, 1] | [0, 0, 0, 1] |
| [0, 1, 1, -1] | [1, 2, 2, 0] | [0, 2, 2, -1] | [1, -1, 0, 1] | [-1, 0, 1, 1] |
| [0, 1, 2, -2] | [1, 2, 3, -1] | [0, 2, 3, -2] | [2, -2, 0, 1] | [-2, 0, 1, 2] |
| [0, 1, 3, -3] | [1, 2, 4, -2] | [0, 2, 4, -3] | [3, -3, 0, 1] | [-3, 0, 1, 3] |
内積や外積、normalize など、よく使う演算を *, /, ! として再定義しました。
外積については 4次元以降は非常に複雑だったので、使いそうな3次元のみ対応しました。
また、Matrix については、時間内にdebugが出来ませんでしたが、今後作成する予定です。 コードとテストの実行結果については以下のようになりました。
a, b = (0..1).map do Vec.new end
puts " a \t\t| b \t\t| a·b \t\t| a×b \t\t\t| a/(a*a)"
puts " :- \t\t| :- \t\t| :- \t\t| :- \t\t\t| :-"
(0..2).map do |i|
(0..2).map do |j|
a <=> [i, j * 2, 3]
b <=> [4, i * 5, j * 6]
puts " #{a} \t| #{b} \t| #{a*b} \t\t| #{a/b}\t\t| #{!a}"
end
end
| a | b | a·b | a×b | a/√(a*a) |
|---|---|---|---|---|
| [0, 0, 3] | [4, 0, 0] | 0 | [0, 12, 0] | [0.0, 0.0, 1.0] |
| [0, 2, 3] | [4, 0, 6] | 18 | [12, 12, -8] | [0.0, 0.5547001962252291, 0.8320502943378437] |
| [0, 4, 3] | [4, 0, 12] | 36 | [48, 12, -16] | [0.0, 0.8, 0.6] |
| [1, 0, 3] | [4, 5, 0] | 4 | [-15, 12, 5] | [0.31622776601683794, 0.0, 0.9486832980505138] |
| [1, 2, 3] | [4, 5, 6] | 32 | [-3, 6, -3] | [0.2672612419124244, 0.5345224838248488, 0.8017837257372732] |
| [1, 4, 3] | [4, 5, 12] | 60 | [33, 0, -11] | [0.19611613513818404, 0.7844645405527362, 0.5883484054145521] |
| [2, 0, 3] | [4, 10, 0] | 8 | [-30, 12, 20] | [0.5547001962252291, 0.0, 0.8320502943378437] |
| [2, 2, 3] | [4, 10, 6] | 46 | [-18, 0, 12] | [0.48507125007266594, 0.48507125007266594, 0.7276068751089989] |
| [2, 4, 3] | [4, 10, 12] | 84 | [18, -12, 4] | [0.3713906763541037, 0.7427813527082074, 0.5570860145311556] |
def isNum (target) target.is_a? Numeric end
def isArr (target) target.instance_of?(Array) end
def isVec (target) target.instance_of?(Vec) end
class Vec
def initialize(init = [1, 0, 0], args = 0)
@v = init
@n = args
@_ = ->(v = @v, n = @n){Vec.new(v, n)}
end
def to_a() isArr(@v) ? @v : @v[@n] end
def to_s() to_a.to_s end
def size() to_a.size end
def sum() to_a.sum end
def sort() @_[->n{to_a.sort}] end
def map(_) @_[->n{to_a.map.with_index{|v, i| _[v, i]}}] end
def +(_) map(isNum(_) ? ->v, i{v + _} : ->v, i{v + _[i]}) end
def -(_) map(isNum(_) ? ->v, i{v - _} : ->v, i{v - _[i]}) end
def *(_) isNum(_) ? map(->v, i{v * _}) : map(->v, i{v * _[i]}).sum end
def /(_) isNum(_) ? map(->v, i{v / _}) : cross(_) end
def [](_) v = to_a; v[_] end
def <=>(_) @v = _ end
def >>(_) _ << @n end
def <<(n) @_[@v, n] end
def +@() map(->v, i{+v}) end
def -@() map(->v, i{-v}) end
def !@() self / Math::sqrt(self * self) end
def cross(_) @_[->n{ v = _.to_a; [
@v[1] * v[2] - @v[2] * v[1],
@v[2] * v[0] - @v[0] * v[2],
@v[0] * v[1] - @v[1] * v[0],]
}] end
end