なが月・9日目

午前

今日はABC137があるため、過去問の代わりに今まで時間を削られていたVR制作を行った。Baked Indirectモードで間接光をベイクしたことで、日陰部分にも影ができ凹凸が明確になった。また久しぶりに実機でテストしたところ、Oculus Touchのゲーム中での「前」方向とグリップの方向が同一ではないので、ゲーム内で手に握っている設定の誘導棒がコントローラの前方向を軸にして配置されていると違和感があることに今更気づいた。さらに3D素材の切り替えを通じてディテールの細かさはビリーバビリティに直結することも痛感した(目の前を通る車が箱も同然のものと、適切にデフォルメされたローポリモデルではあまりに異なる)。

午後

C言語もいよいよ最終章である。構造体を宣言してからtypedef struct 構造体名 別名;とすることで一語で変数宣言することができる。

自作関数をライブラリとして分割して利用するには、someHeader.hとsomeSource.cに構造体や関数の宣言を記述するが、ヘッダファイルにおいてはプロトタイプ宣言にとどめ、関数名と引数だけを設定することが望ましいとされ、実際に関数の実装を行うのはsomeSource.cになる。<>で指定したヘッダは標準ヘッダであり、独自ヘッダは""で指定する(実際は探索順の違いだけのようだが)。#includeは当該ヘッダに書いてある内容をその場所に展開するので、#includeする代わりに人間が手でプロトタイプ宣言を書いておくことも可能ではあるということだった。

しかし#includeしているのはヘッダファイルだけであり、そこに関数の具体的な定義はなされていない。なぜそれで実装にアクセスできるのか?ということで調べたところ、main.cと一緒にsomeSource.cもコンパイルすることでリンクされる(https://www.atmarkit.co.jp/ait/articles/1404/11/news045_2.html)からだという。つまり、main.cの中でsomeHeader.hを#includeすると、「someHeader.hに書かれている関数であれば、一緒にコンパイルされたソースファイルのどこかしらには実装されているはずだから利用可能なはずである」という情報を得て、いざそこに書かれた関数が使用されていれば実装を探しに行き(ここはコンパイラの仕事だろうか?)、継ぎ足して完全な命令を構成すると理解した。

そのため、関数を呼んでいるソース中に関数の実装がなく、ヘッダにプロトタイプ宣言もされていない場合は、C99規約において暗黙の関数宣言でwarning扱いとなる。しかし一応他のソース内を探索するので、他ソース内に実装が発見されれば実行は可能であった。

逆にヘッダ上ではどこかに実装されていることになっている関数を呼び出しているがどこにも実装されていない場合は当然ながらundefined referenceでコンパイルに失敗する。

さらにこの扱いは関数だけでなく変数にも及び、ブロック外で初期化されている変数はどのソースからもアクセスできる(外部定義)。int a;のように初期化されていない場合は仮定義と呼ばれ、他の場所でaが外部定義されていればそれを参照する。そうでなければ初期化されたものとみなされる。

こうしたふるまいをするのではうかつに変数名を付けると衝突してしまうため、ソース内部からしか参照できない内部結合の識別子staticが存在する。また明示的に外部で定義された変数を参照させたいときはexternをつける。

ブロック内で宣言すればよい話ではあるが、気をつけておきたい。

Photoshopではコラージュの練習をした。明るさの異なる写真に合成する場合は背景の複製に平均フィルターをかけ、ソフトライトや乗算によって見え方を調整する。f:id:napier_0b:20190810195237j:plain

https://helpx.adobe.com/photoshop/how-to/match-color-tones-composite.htmlでは色相を合わせるチュートリアルを行ったが、今回は明るさであった。そろそろ公式チュートリアルがなくなってきたのでBlenderかPremiere/AEかSubstance Painterの勉強に移る頃合いかもしれない。

ABC137ではC問題で無駄に過去の全文字列に対して文字カウントが一致するかチェックするループを回してしまった。10文字のソート*N回はほぼO(N)とみてよいのでソートしてよく、ソートした文字列を辞書に追加しカウントアップ、最後にfor val in dic.values()でans += val * (val - 1) // 2して答えであった。D問題は区間スケジューリング、0-1ナップサックが頭に浮かんだが、区間スケジューリングとは異なり全て1日で終わり、0-1ナップサックではある番目の仕事以外を重さ1、当該仕事の重さを A_{i}とみなそうとしても、仕事の順番が肝心なので上から順番にやるかやらないか決めることでは解が得られない。漸化式としてどうとらえればよいのかわからなかった。そして終わってから5分後に「最後の日から遡って、『翌日払いの中で最も高給なもの』を選び、『翌日or2日後払いの中で最も高給なもの』を選び、...を繰り返す」だけの話だったことに気づいた。とはいえ、優先度付きキューの実装を知らないのでナイーブに1日前、2日前、...の時点で受けてよい仕事の報酬リストを順次extendしてmax()で求めてremoveするとTLEした。そうしたら優先度付きキューはPythonでは標準モジュールに入っている(1st ACは躊躇なくそれを使っている、またC++にも標準であるらしい)のだ!明日実装に挑戦する。