アルゴリズム一題
2005年06月01日 00:11
前のアダルト制作会社を辞めてから最初に彼女が手がけたサイトでは、とある 3D CAD ソフトの講習をやっていて、毎週の土曜日に開く講習の予約をとっています。
でも、前日の金曜日に予約されても準備が間に合わないので、金曜日の受付は翌週の土曜日として受け付けることにしているそうな。で、講習を受けたい人が希望の日をフォームで指定するところに、「上記の条件を満たす土曜日の日付だけ、数週間分を <select> 内の <option> として表示する」という課題がありました。てなわけで、この部分だけを PHP で表示しようということになり、お引き受けしました。
まず基本的な考え方として、上記の条件を満たす「次に受講可能な土曜日」を割り出して、その日から先の数週間ぶんだけ土曜日を表示すればよい、ということは分かると思います。しかし、「次に受講可能な土曜日」を、どうすれば単純な処理で導き出せるかということを考え始めると、最近はデザインばかりやっていたので、アルゴリズムのおさらいになりました。実際に書いたコードは、以下のとおり(秘匿のため一部のコードは省略)。
$flag = 0;
$plus = 0;
while( $flag == 0 ) {
date( “D” ) != ‘Fri’ ? $plus += 86400 : $plus += 691200; // 今日が金曜なら一週間後の土曜にずらす
$timetarget = time() + $plus;
if ( date( “D”, $timetarget ) != ‘Sat’ || ( date( “D”, $timetarget ) == ‘Sat’ && date( “Ymd” ) == date( “Ymd”, $timetarget ) ) ) {
continue;
} else {
$value = date( “Y年m月d日”, $timetarget );
$flag = 1;
}
}
$weektarget = 0;
for ( $i = 0; $i < 16; $i++ ) { // 15週くらい先まで表示する
$weektarget = $timetarget + $i * 604800;
echo ‘&;toption value=”‘ . date( “Ymd”, $weektarget ) . ‘”>’ . date( “m月 d日”, $weektarget ) . ” . “\n”;
}
要点としては、「土曜日になるまで繰り返し 86,400 秒(一日)ずつ足していけ」ということと、「金曜日以外は一日ずつ、金曜日は一日足して明日の土曜日が「目当ての土曜日」だということになっては困るから、一週間と一日足せ」ということでした。
もともと、この作業を引き受けた当初は、「前日の金曜日には受付しない」という条件がなかったので、土曜日であるかどうかを while から抜ける基準にしており、上記のコードも同じく土曜日かどうかを基準にはしているのですが、その前にある「金曜日以外は土曜だろうがなんだろうが一日足せばよい」という点、つまり土曜日を特別扱いにしなくてもよいということに気づくまで、いささか時間がかかりました。土曜日だって一日ズラしてしまえば日曜だから判定は次の(目当ての土曜日)までは、他の曜日と同じく 86,400 秒足していけばよいのであります。
また他のやり方もできるでしょう。エレガントではないにしても、「月曜ならしかじか」「火曜ならしかじか」・・・といったやりかたで、switch を使うことだって出来る。しかしそういうコードの書き方はいかにもつまらないし、結局はコードがやたらと長くなってしまいます。取り柄と言えば、そうとうな時間が経過した後で読み直しても、何をやっているコードなのかすぐに分かるということくらいでしょうか。あまりにも手の込んだアルゴリズムで書くと、後で「これはなんでこんな処理と判定基準をつかっているのか?」と首を傾げてしまうことがありますからなぁ・・・。
いまのところ上のような書き方で事なきを得ているのですが、これをいろんなやり方で書き直してみるのも面白そうです。恐らく本職のプログラマーさんであれば、まず「できるだけシンプルに書く」とか「できるだけ少ないコードで実現する」といった職人魂をゆすぶる目標をたてるかもしれない。あるいは「なるべく特殊な環境に依存しない書き方をする」とかいった品質の良さを求めるかもしれません。どうだろう? まずは、もっと少ないコードで目標の土曜日を判定したいです。どうやればよいだろうか。この続きは、よいアイディアが湧いたらということで・・・。
