不良セクタの隣 の問題で肩慣らし。
以下はとりあえずテスト通しただけの状態そのままのコード。単体テスト含めてフルスクラッチからで45分くらい。場当たり的にモジュール化したので、無駄が多い。
初め「複数の」を見落としてて、最後に方針転換したけど、適度にモジュール化されてたのでなんとかなった。
Cloud9上で解いたので、キーバインドでも苦しんだ。Ctrl-s 押し忘れてセーブされてなかったり Ctrl-k 押してよくわからなくなったり。あと、45分の時間には含んでないけど、 コアモジュールのインストールも必要 。
package Sector; use strict; use warnings; use Exporter qw(import); our @EXPORT_OK = qw(solve); my @all_sectors = ( [100 .. 107], [200 .. 215], [300 .. 323], [400 .. 431], ); sub degrees ($$) { my ($sectors, $sector) = @_; my $deg = 360 / @$sectors; my $sec_num = $sector - $sectors->[0]; if ($sec_num == 0) { ([360 - $deg / 2, 360], [0, $deg / 2]); } else { ([($sec_num - .5) * $deg, ($sec_num + .5) * $deg]); } } sub sectors_in_degrees ($$$) { my ($sectors, $deg1, $deg2) = @_; my %result; for my $sec (@$sectors) { my @ds = degrees($sectors, $sec); for (@ds) { my ($d1, $d2) = @$_; $result{$sec}++ unless ($d1 <= $deg1 && $d2 <= $deg1) || ($deg2 <= $d1 && $deg2 <= $d2); } } return keys %result; } sub warning_sectors ($$) { my ($all_sectors, $sector) = @_; my $ringnum = int($sector / 100) - 1; my @degrees = degrees($all_sectors->[$ringnum], $sector); my %result; my $localnum = $sector % 100; my $localmax = @{$all_sectors->[$ringnum]}; $result{$all_sectors->[$ringnum][($localnum + 1) % $localmax]}++; $result{$all_sectors->[$ringnum][($localnum + $localmax - 1) % $localmax]}++; if (0 < $ringnum) { my @secs = map { sectors_in_degrees($all_sectors->[$ringnum - 1], $_->[0], $_->[1]) } @degrees; $result{$_}++ for @secs; } if ($ringnum < $#$all_sectors) { my @secs = map { sectors_in_degrees($all_sectors->[$ringnum + 1], $_->[0], $_->[1]) } @degrees; $result{$_}++ for @secs; } keys %result; } sub _diff ($$) { my ($ar1, $ar2) = @_; my %ar2 = map { $_ => 1 } @$ar2; grep { ! $ar2{$_} } @$ar1; } sub _uniq ($) { my $ar = shift; my %ar = map { $_ => 1} @$ar; keys %ar; } sub solve ($) { my @broken = split /,/, $_[0]; my %warnings; for (map { warning_sectors(\@all_sectors, $_) } @broken) { $warnings{$_}++; } my @many_warnings = grep { $warnings{$_} >= 2} keys %warnings; my @pure_warnings = _uniq [_diff(\@many_warnings, \@broken)]; join ',', sort @pure_warnings or 'none'; }
use strict; use warnings; use Test::More import => [qw(done_testing is)]; use Sector qw(solve); while (<DATA>) { tr/\r\n//d; my ($num, $in, $out) = split /\s+/, $_; is solve($in), $out, "TEST#$num"; } done_testing; __END__ 0 400,401,302 300,301,402 1 105,100,306,414 none 2 100 none 3 211 none 4 317 none 5 414 none 6 100,106 107 7 205,203 102,204 8 303,305 304 9 407,409 306,408 10 104,103 207 11 204,203 102,305 12 313,314 209,418 13 419,418 314 14 100,102,101 201,203 15 103,206,309 205,207,308,310 16 414,310,309 206,311,413 17 104,102,206,307,102,202 101,103,203,204,205,207,308 18 104,206,308,409,407 103,205,207,306,307,309,408,410 19 313,406,213,301,409,422,412,102,428 none 20 101,300,210,308,423,321,403,408,415 none 21 304,316,307,207,427,402,107,431,412,418,424 none 22 205,408,210,215,425,302,311,400,428,412 none 23 200,311,306,412,403,318,427,105,420 none 24 105,305,407,408,309,208,427 104,209,306,406 25 311,304,322,404,429,305,316 203,303,321,405,406,430 26 210,401,316,425,101 211,315 27 414,403,404,416,428,421 303,415 28 207,300,103,211,428 104,206 29 322,314,310 none 30 427,200,215 100,323 31 311,402,424,307,318,430,323,305,201 200,204,301,302,306,322,423,425,431 32 425,430,408 none 33 202,320,209,426 319,427 34 430,209,302,310,304,431,320 202,303,323 35 208,206,406,424,213,312 207,311,313 36 420,302,313,413,317,402 301,403 37 319,306,309,418,204,411 305,307,308,412 38 400,308,105,430,203,428,209 104,210,429,431 39 200,305,214 215 40 214,408,410,407,317,422 306,316,409,423
毎回そうなんだけど、実装中、部品の単体テストをしてないので、最後にテスト全部通るかは神のみぞ知る。とはいえ、1時間で部品の単体テストまで書くのは、時間配分的に現実的ではないと思う。
追記: 3年前の自分の回答 。今書いたコードより整ってるようには見えるけど、 $D
ってなんだっけ・・・。