http://qiita.com/Nabetani/items/936e7885f4c607472060
http://nabetani.sakura.ne.jp/hena/ord13blocktup/
積み木の水槽に、水をどれだけ貯められるかを計算します。
かかった時間は30分くらい。
考え方は単純です。
「83141310145169154671122」を例に挙げてみると、まず0で分けて「8314131」「145169154671122」にします。
「8314131」を2文字目の「3」で見ると、左側にある壁の最大値は8、右側にある壁の最大値は4、よって左右両方の最大値は4です。
自分の高さは3なので、1升ぶんだけ水が貯まります。
4文字目の「4」で見ると、左の最大値は8、右の最大値は3、自分は4なので貯まりません。
というのを列ごとにくるくるしていくだけです。
「オフラインリアルタイムどう書く」の一覧
http://nabetani.sakura.ne.jp/hena/ord13blocktup/
積み木の水槽に、水をどれだけ貯められるかを計算します。
<?php
class BLOCKTUP{
/**
* 貯められる水容量を返す
* @param String 「83141310145169154671122」みたいな文字列
* @return int 「24」みたいな数値
*/
public function get($input){
$count = 0;
// 0で分割
$input = explode('0', $input);
// くるくる
foreach($input as $key=>$block){
// 幅が2以下であれば0
if(strlen($block) < 3){continue;}
// 2文字目から最後-1文字目までをくるくる
$arr = str_split($block);
for($i=1; $i<count($arr)-1; $i++){
// ( 左MAXと右MAXの低い方 - 自分 ) > 0であればそのぶん足す
$bucket = min(max(array_slice($arr, 0, $i, true)), max(array_slice($arr, $i+1, NULL, true))) - $arr[$i];
if($bucket > 0){
$count += $bucket;
}
}
}
return $count;
}
}
// テスト
$test = [
['83141310145169154671122', '24'],
['923111128', '45'],
['923101128', '1'],
['903111128', '9'],
['3', '0'],
['31', '0'],
['412', '1'],
['3124', '3'],
['11111', '0'],
['222111', '0'],
['335544', '0'],
['1223455321', '0'],
['000', '0'],
['000100020003121', '1'],
['1213141516171819181716151413121', '56'],
['712131415161718191817161514131216', '117'],
['712131405161718191817161514031216', '64'],
['03205301204342100', '1'],
['0912830485711120342', '18'],
['1113241120998943327631001', '20'],
['7688167781598943035023813337019904732', '41'],
['2032075902729233234129146823006063388', '79'],
['8323636570846582397534533', '44'],
['2142555257761672319599209190604843', '41'],
['06424633785085474133925235', '51'],
['503144400846933212134', '21'],
['1204706243676306476295999864', '21'],
['050527640248767717738306306596466224', '29'],
['5926294098216193922825', '65'],
['655589141599534035', '29'],
['7411279689677738', '34'],
['268131111165754619136819109839402', '102'],
];
$blocktup = new BLOCKTUP();
foreach($test as $key=>$data){
$answer = $blocktup->get($data[0]);
if($answer !== (int)$data[1]){
print('えらー');
}
}
なんか見た感じ難しそうだなあと思ってたのですが、実際に作ってみたら予想外に一瞬で終わった。かかった時間は30分くらい。
考え方は単純です。
「83141310145169154671122」を例に挙げてみると、まず0で分けて「8314131」「145169154671122」にします。
「8314131」を2文字目の「3」で見ると、左側にある壁の最大値は8、右側にある壁の最大値は4、よって左右両方の最大値は4です。
自分の高さは3なので、1升ぶんだけ水が貯まります。
4文字目の「4」で見ると、左の最大値は8、右の最大値は3、自分は4なので貯まりません。
というのを列ごとにくるくるしていくだけです。
「オフラインリアルタイムどう書く」の一覧
PR
http://nabetani.sakura.ne.jp/hena/ord3ynode/
第3回はqiitaの記事がないようです。
左右後ろに進み、どのような道筋を辿ったかを算出します。
'BA'が決まれば'CA''DA'は傾ければいいだけなので算出は可能なのですが、面倒になったのでもういいやー的な。
後ろに戻る場合も$nextに持たせておけばforループ内でわざわざ分岐する必要もないのですが、まあそちらも面倒なのでいいや的に。
かかった時間は30分程度。あっさり。
「オフラインリアルタイムどう書く」の一覧
第3回はqiitaの記事がないようです。
左右後ろに進み、どのような道筋を辿ったかを算出します。
<?php
class YNODE{
// 次の方向
private $next = [
'BA' => ['r'=>'C', 'l'=>'D'], 'CA' => ['r'=>'D', 'l'=>'B'], 'DA' => ['r'=>'B', 'l'=>'C'],
'AB' => ['r'=>'E', 'l'=>'C'], 'CB' => ['r'=>'A', 'l'=>'E'], 'EB' => ['r'=>'C', 'l'=>'A'],
'AC' => ['r'=>'B', 'l'=>'F'], 'BC' => ['r'=>'F', 'l'=>'A'], 'FC' => ['r'=>'A', 'l'=>'B'],
'AD' => ['r'=>'F', 'l'=>'E'], 'ED' => ['r'=>'A', 'l'=>'F'], 'FD' => ['r'=>'E', 'l'=>'A'],
'BE' => ['r'=>'D', 'l'=>'F'], 'DE' => ['r'=>'F', 'l'=>'B'], 'FE' => ['r'=>'B', 'l'=>'D'],
'CF' => ['r'=>'E', 'l'=>'D'], 'DF' => ['r'=>'C', 'l'=>'E'], 'EF' => ['r'=>'D', 'l'=>'C'],
];
/**
* 進んだルートを求める
* @param String 「rrrrbllrlrbrbrr」みたいな文字
* @return String 「ACBACABCFDEDADFC」みたいな数値
*/
public function get($input){
// 現在進んでる方向
$nowRoute = 'BA';
// 返り値
$ret = 'A';
for($i=0; $i<strlen($input); $i++){
// bだったら後ろに戻る
if($input[$i] === 'b'){
$ret .= $nowRoute[0];
$nowRoute = strrev($nowRoute);
continue;
}
// 次に進む
$next = $this->next[$nowRoute][$input[$i]];
$ret .= $next;
$nowRoute = $nowRoute[1] . $next;
}
return $ret;
}
}
// テスト
$test = [
['b', 'AB'],
/* 省略 */
];
$ynode = new YNODE();
foreach($test as $key=>$data){
$answer = $ynode->get($data[0]);
if($answer !== $data[1]){
print('えらー');
}
}
全方向を持たせておくという原始的方法で解決。'BA'が決まれば'CA''DA'は傾ければいいだけなので算出は可能なのですが、面倒になったのでもういいやー的な。
後ろに戻る場合も$nextに持たせておけばforループ内でわざわざ分岐する必要もないのですが、まあそちらも面倒なのでいいや的に。
かかった時間は30分程度。あっさり。
「オフラインリアルタイムどう書く」の一覧
http://qiita.com/Nabetani/items/9c514267214d3917edf2
縦5本横5本の通りを、同じ頂点を通らずに左上から右下まで進む方法が何パターンあるかを数えます。
ポイントは最短距離ではなく遠回りな道も有効というところでしょうか。
今回は全経路が8512種類しかないので問題なく動作しますが、おそらく一辺があと2くらい増えたら動かなくなるでしょう。
二重ループとかもどうにかしたいところです。
かかった時間は制限をぶっちぎって3時間くらい。
作った後で思いついたが、先に「次進める方向」から通行止めの行き先を削除し、それから「ルートを作成」したほうが早そうだ。
「オフラインリアルタイムどう書く」の一覧
縦5本横5本の通りを、同じ頂点を通らずに左上から右下まで進む方法が何パターンあるかを数えます。
ポイントは最短距離ではなく遠回りな道も有効というところでしょうか。
<?php
class ROUTE{
/*
座標は↓のようになる
abcde
fghij
klmno
pqrst
uvwxy
*/
// 次進める方向
private $next = [
'a'=>['b', 'f'], 'b'=>['c', 'g'], 'c'=>['d', 'h'], 'd'=>['e', 'i'], 'e'=>['j'],
'f'=>['g', 'k'], 'g'=>['b', 'f', 'h', 'l'], 'h'=>['c', 'g', 'i', 'm'], 'i'=>['d', 'h', 'j', 'n'], 'j'=>['i', 'o'],
'k'=>['l', 'p'], 'l'=>['g', 'k', 'm', 'q'], 'm'=>['h', 'l', 'n', 'r'], 'n'=>['i', 'm', 'o', 's'], 'o'=>['n', 't'],
'p'=>['q', 'u'], 'q'=>['l', 'p', 'r', 'v'], 'r'=>['m', 'q', 's', 'w'], 's'=>['n', 'r', 't', 'x'], 't'=>['s', 'y'],
'u'=>['v'], 'v'=>['q', 'w'], 'w'=>['r', 'x'], 'x'=>['s', 'y'],
];
// コンストラクタ
public function __construct(){
// 全ルートを作成
$this->route = iterator_to_array(
new RecursiveIteratorIterator(
new RecursiveArrayIterator(
$this->getRoute('', 'a')
)
)
, false);
}
/**
* 全ルートを作成する
* @param String これまで進んできたルート
* @param String 現在地
* @return mixed
* 途中なら、これまでのルートを持った配列。
* yに辿り着いたらそのルートまでの文字列。
* 行き止まったらfalse。
*/
private function getRoute($route, $point){
// yならゴール
if($point === 'y'){return $route . $point; }
// 次に進める限り繰り返し
$ret = [];
if($nextPoints = $this->getNextPoints($route, $point)){
foreach($nextPoints as $key=>$nextPoint){
$tmp = $this->getRoute($route.$point, $nextPoint);
if($tmp !== false){
$ret[] = $tmp;
}
}
return $ret;
}
// 進めなくなったら
return false;
}
/**
* 次進める場所を取得する
* @param String これまで進んできたルート
* @param String 現在地
* @return array 次進める場所の配列
*/
private function getNextPoints($route, $point){
// 既に通った道は不可
$ret = [];
foreach($this->next[$point] as $val){
if(strpos($route, $val) === false){
$ret[] = $val;
}
}
return $ret;
}
/**
* パターン数を取得
* @param String 「ab af」みたいな文字
* @return int 「8192」みたいな数値
*/
public function get($input){
$routes = $this->route;
// パース
if(!$input){ return count($routes); }
$stopArray = explode(' ', $input);
foreach($routes as $key=>$route){
// 通行止めを通ってるルートは削除
foreach($stopArray as $stop){
if(strpos($route, $stop)!==false || strpos($route, strrev($stop))!==false){
unset($routes[$key]);
}
}
}
return count($routes);
}
}
// テスト
$test = [
['', 8512 ],
['af', 4256 ],
['xy', 4256 ],
['pq qr rs st di in ns sx', 184 ],
['af pq qr rs st di in ns sx', 92 ],
['bg ch di ij no st', 185 ],
['bc af ch di no kp mr ns ot pu rs', 16 ],
['ab af', 0 ],
['ty xy', 0 ],
['bg ch ej gh lm lq mr ot rs sx', 11 ],
['ty ch hi mn kp mr rs sx', 18 ],
['xy ch hi mn kp mr rs sx', 32 ],
['ch hi mn kp mr rs sx', 50 ],
['ab cd uv wx', 621 ],
['gh mn st lq qr', 685 ],
['fg gl lm mr rs', 171 ],
];
$route = new ROUTE();
foreach($test as $key=>$data){
$answer = $route->get($data[0]);
if($answer !== $data[1]){
print('えらー');
}
}
とりあえず全経路を求めておいて、通行止めになった道を通っているものを削除するという、あまりに力業な求め方となりました。今回は全経路が8512種類しかないので問題なく動作しますが、おそらく一辺があと2くらい増えたら動かなくなるでしょう。
二重ループとかもどうにかしたいところです。
かかった時間は制限をぶっちぎって3時間くらい。
作った後で思いついたが、先に「次進める方向」から通行止めの行き先を削除し、それから「ルートを作成」したほうが早そうだ。
「オフラインリアルタイムどう書く」の一覧
http://nabetani.sakura.ne.jp/hena/ord4tetroid/
qiita版リンク集がない?
作者による回答例はこちら。
http://qiita.com/Nabetani/items/cdc38bfc5665a5361942
http://qiita.com/Nabetani/items/a2d6f70241b9e80ab17d
4つの座標から、どのテトリミノかを判断します。
正直どうすればよいのかよくわからん。
一番左上に詰めたときのパターンを全て持っておき、一致すればそれを返すという単純な作りです。
foreachが3回も出てくるのが微妙だ。
かかった時間は40分くらい。
「オフラインリアルタイムどう書く」の一覧
qiita版リンク集がない?
作者による回答例はこちら。
http://qiita.com/Nabetani/items/cdc38bfc5665a5361942
http://qiita.com/Nabetani/items/a2d6f70241b9e80ab17d
4つの座標から、どのテトリミノかを判断します。
正直どうすればよいのかよくわからん。
<?php
class TETRIMINO{
// 全パターン
private $minoList = [
'L0' => ['00', '01', '02', '12'],
'L1' => ['00', '01', '10', '20'],
'L2' => ['00', '10', '11', '12'],
'L3' => ['01', '11', '20', '21'],
'L4' => ['02', '10', '11', '12'],
'L5' => ['00', '01', '11', '21'],
'L6' => ['00', '01', '02', '10'],
'L7' => ['00', '10', '20', '21'],
'I0' => ['00', '01', '02', '03'],
'I1' => ['00', '10', '20', '30'],
'T0' => ['00', '10', '11', '20'],
'T1' => ['01', '10', '11', '12'],
'T2' => ['01', '10', '11', '21'],
'T3' => ['00', '01', '02', '11'],
'O0' => ['00', '01', '10', '11'],
'S0' => ['00', '01', '11', '12'],
'S1' => ['01', '02', '10', '11'],
'S2' => ['00', '10', '11', '21'],
'S3' => ['01', '10', '11', '20'],
];
/**
* テトリミノ
* @param String 「07,17,06,05」みたいな文字
* @return String 「L」みたいな文字
*/
public function get($input){
// パース
$list = explode(',', $input);
if(count(array_flip($list)) !== 4){ return '-'; }
// 左上に詰める
$minX = $minY = 9;
foreach($list as $key=>$val){
$minX = min($val[0], $minX);
$minY = min($val[1], $minY);
}
foreach($list as $key=>$val){
$list[$key] = ($val[0]-$minX) . ($val[1]-$minY);
}
// 同じものがあればそれを返す
sort($list);
foreach($this->minoList as $key=>$val){
if($val === $list){
return $key[0];
}
}
// なかった
return '-';
}
}
// テスト
$test = [
['55,55,55,55', '-'],
/* 省略 */
];
$tetrimino = new TETRIMINO();
foreach($test as $key=>$data){
$answer = $tetrimino->get($data[0]);
if($answer !== $data[1]){
print('えらー');
}
}
回転させるのが面倒なら、回転後のデータも全部持ってればいいじゃない、という暴挙。一番左上に詰めたときのパターンを全て持っておき、一致すればそれを返すという単純な作りです。
foreachが3回も出てくるのが微妙だ。
かかった時間は40分くらい。
「オフラインリアルタイムどう書く」の一覧
http://qiita.com/Nabetani/items/0ddde0164a745cd09c34
http://nabetani.sakura.ne.jp/hena/ord5railsontiles/
順番的には「第5回オフラインリアルタイムどう書くの問題」なのですが、難しすぎて解けないのでとりあえずパスして次に。
いや、解いたには解いたんですが500行とかになってしまったのでこれはあかん。
懐かしチクタクバンバン。
ただしこちらはパネルは動きません。
進むラインを求めます。
ただ普通に0~8とすると2→3の移動がOKとみなされてしまうため、侵入許可パネルという微妙なプロパティを作る羽目になりました。
あとPHPは
private $okPanel = array_flip([10, 11, 12, 23, 24, 25, 36, 37, 38]);
とか書けないから微妙にめんどい。
かかった時間は1時間くらい。
完成した後で考えなおしてみたら'ABC-DEF-GHI'の位置とかでやったほうがずっと簡単そうだった。
まあいいか。
「オフラインリアルタイムどう書く」の一覧
http://nabetani.sakura.ne.jp/hena/ord5railsontiles/
順番的には「第5回オフラインリアルタイムどう書くの問題」なのですが、難しすぎて解けないのでとりあえずパスして次に。
いや、解いたには解いたんですが500行とかになってしまったのでこれはあかん。
懐かしチクタクバンバン。
ただしこちらはパネルは動きません。
進むラインを求めます。
<?php
class TICKTUCK{
// 入力方向から次の入力方向を求める ←0↑1→2↓3
private $panel = [
0=>[0=>0, 1=>1, 2=>2, 3=>3],
1=>[0=>1, 1=>0, 2=>3, 3=>2],
2=>[0=>3, 1=>2, 2=>1, 3=>0],
];
// 入力方向による現在値の変化 ←-1↑-13→+1↓+13
private $direction = [0=>1, 1=>13, 2=>-1, 3=>-13 ];
// 侵入許可パネル
private $okPanel = [10=>1, 11=>1, 12=>1, 23=>1, 24=>1, 25=>1, 36=>1, 37=>1, 38=>1];
/**
* チクタクバンバン
* @param String 「101221102」みたいな文字列
* @return String 「BEDGHIFEH」みたいな文字列
*/
public function get($input){
// 現在地
$nowPanel = 11;
// 現在の方向
$nowDirection = 1;
// 進んだ順
$ret = '';
do{
// 現在地
$ret .= chr(65 + $nowPanel%10);
// 次の方向を求める
$nowDirection = $this->panel[$input[$nowPanel%10]][$nowDirection];
// 次の現在地を求める
$nowPanel += $this->direction[$nowDirection];
// 進める限り繰り返し
}while(isset($this->okPanel[$nowPanel]));
return $ret;
}
}
// テスト
$test = [
['101221102','BEDGHIFEH'],
/* 省略 */
];
$ticktuck = new TICKTUCK();
foreach($test as $key=>$data){
$answer = $ticktuck->get($data[0]);
if($answer !== $data[1]){
print('えらー');
}
}
パネルのA~Iをそれぞれ0~8に割り当て、パネルの形状によって移動する次のパネルを求める、という基本的には単純な作りです。ただ普通に0~8とすると2→3の移動がOKとみなされてしまうため、侵入許可パネルという微妙なプロパティを作る羽目になりました。
あとPHPは
private $okPanel = array_flip([10, 11, 12, 23, 24, 25, 36, 37, 38]);
とか書けないから微妙にめんどい。
かかった時間は1時間くらい。
完成した後で考えなおしてみたら'ABC-DEF-GHI'の位置とかでやったほうがずっと簡単そうだった。
まあいいか。
「オフラインリアルタイムどう書く」の一覧
http://qiita.com/Nabetani/items/89fb0e2e712d4b396535
http://nabetani.sakura.ne.jp/hena/ord13updowndouble/
「+1」「-1」「*2」だけで目的の数値を求めるという問題。
単純にやったら最短にならない場合があります。
単調減少:59→58→29→28→14→7→6→3→2→1→0(10回)
最短:59→60→30→15→16→8→4→2→1→0(9回)
どうすればいいんだろう?
試行錯誤で1時間くらい。
なお、このアルゴリズムが普遍のものなのか、今回たまたま動いてるだけなのかは知りません。
どこかの数学パズルか何かでこの解き方を見たような記憶があるのですが、探しても見つかりませんでした。
というかどんなキーワードでググれバインダー
「オフラインリアルタイムどう書く」の一覧
http://nabetani.sakura.ne.jp/hena/ord13updowndouble/
「+1」「-1」「*2」だけで目的の数値を求めるという問題。
単純にやったら最短にならない場合があります。
単調減少:59→58→29→28→14→7→6→3→2→1→0(10回)
最短:59→60→30→15→16→8→4→2→1→0(9回)
どうすればいいんだろう?
<?php
class MULTIPLY{
/**
* 0になる最短の回数
* @param int 「59」みたいな数値
* @return int 「9」みたいな数値
*/
public function get($input){
// 偶数であれば2で割る、+1して4で割れれば+1する、それ以外は-1
for($i=0;$input>4;$i++){
$input = ($input%2) ? ( (($input+1)%4) ? $input-1 : $input+1 ) : $input/2 ;
}
// 3か4になったら2、1、0となるだけなので+3
return $i+3;
}
}
// テスト
$test = [
[59, 9],
/* 省略 */
];
$multiply = new MULTIPLY();
foreach($test as $key=>$data){
$answer = $multiply->get($data[0]);
if($answer !== $data[1]){
print('えらー');
}
}
なんかできた。試行錯誤で1時間くらい。
なお、このアルゴリズムが普遍のものなのか、今回たまたま動いてるだけなのかは知りません。
どこかの数学パズルか何かでこの解き方を見たような記憶があるのですが、探しても見つかりませんでした。
というかどんなキーワードでググれバインダー
「オフラインリアルタイムどう書く」の一覧
http://bloggdgd.blog28.fc2.com/blog-entry-264.html
http://fushi.x0.com/blog/archives/828
プロパティ「"A"」には$obj->Aでアクセスできますが、プロパティ「0」にはどうやってもアクセスできねーよ、というお話。
まあキャストしてるから(array)と一緒だろ、と言われればそのとおりですが。
実はここからがわりと愉快で深刻な話になります。
http://fushi.x0.com/blog/archives/828
<?php
$arr = array('0'=>'zero', 'A'=>'B');
$obj = (object)$arr;
var_dump($obj);
object(stdClass)#1 (2) {
[0]=>
string(4) "zero"
["A"]=>
string(1) "B"
}
objectにキャストした結果、"zero"のキーが何故か数値になっています。プロパティ「"A"」には$obj->Aでアクセスできますが、プロパティ「0」にはどうやってもアクセスできねーよ、というお話。
$arrayObject = new ArrayObject($obj, ArrayObject::ARRAY_AS_PROPS); print($arrayObject[0]); // zeroできました。
まあキャストしてるから(array)と一緒だろ、と言われればそのとおりですが。
実はここからがわりと愉快で深刻な話になります。
<?php
$arr = array('0'=>'zero');
$obj = (object)$arr; // [0]になる
$obj->{0} = 'hoge'; // 実際は["0"]に入る
// ArrayObjectは全て"zero"
$arrayObject = new ArrayObject($obj, ArrayObject::ARRAY_AS_PROPS);
var_dump($arrayObject[0], $arrayObject['0'], $arrayObject->{0}, $arrayObject->{'0'});
// 配列はどちらも"zero"
$arr = (array)$iter;
var_dump($arr[0], $arr['0']);
// stdClassは何故か"hoge"
$obj = (object)$arr;
var_dump($obj->{0}, $obj->{'0'});
うむ、意味が分からない。
DatePeriodは日付の期間を表し、『1月1日から3月31日まで、1日2時間34分56秒ごと』のような自力で書くとめんどくさい繰り返しを簡単に取り扱うことができるようになります。
val1:2013-01-01 00:00:00
val2:2013-01-01 00:01:00
val1:2013-01-01 00:00:01
val2:2013-01-01 00:01:01 // bug
val1:2013-01-01 00:00:02
val2:2013-01-01 00:01:01 // bug
$val2には0時1分0秒を指定したはずなのですが、何故か1秒おまけされてしまっているところがあります。
DatePeriodから取得したDateTimeに対してsetTimeするとおかしな値になるぞ、というバグです。
例では秒だからまだ気付かれにくいですが、'P1D'にすると1日ずれるのでわりかし事故です。
なんか開発中に日付が一日ずれてしまう問題に突き当たり、どう見てもソースは合ってるんだが何故だろうと延々悩んでいたら実はPHPのバグだったとかいう。
いやっほうバグを見つけてやったぜいと思ってたら、当然とうの昔に修正されている既知のバグでした。
ノートによると5.3.5では直っていたようです。
PHP5.4.7では正しく計算されるようになっていたのを確認しました。
PHPではしれっとこういうことがあったりするのが怖いですね。
<?php
// 開始/終了日時
$start = new DateTime('2013-01-01 00:00:00', new DateTimeZone('Asia/Tokyo'));
$finish = new DateTime('2013-01-01 00:00:03', new DateTimeZone('Asia/Tokyo'));
// 1秒毎に分割
$dateInterval = new DateInterval('PT1S'); // 1秒
$datePeriod = new DatePeriod($start, $dateInterval, $finish);
// 1秒ごとに実行
foreach($datePeriod as $key=>$val){
$val1 = clone $val;
$val2 = clone $val;
$val2->setTime(0, 1, 0); // $val2は0時1分0秒を指定する
print( 'val1:' . $val1->format('Y-m-d H:i:s'));
print( 'val2:' . $val2->format('Y-m-d H:i:s'));
}
val1:2013-01-01 00:00:00
val2:2013-01-01 00:01:00
val1:2013-01-01 00:00:01
val2:2013-01-01 00:01:01 // bug
val1:2013-01-01 00:00:02
val2:2013-01-01 00:01:01 // bug
$val2には0時1分0秒を指定したはずなのですが、何故か1秒おまけされてしまっているところがあります。
DatePeriodから取得したDateTimeに対してsetTimeするとおかしな値になるぞ、というバグです。
例では秒だからまだ気付かれにくいですが、'P1D'にすると1日ずれるのでわりかし事故です。
なんか開発中に日付が一日ずれてしまう問題に突き当たり、どう見てもソースは合ってるんだが何故だろうと延々悩んでいたら実はPHPのバグだったとかいう。
いやっほうバグを見つけてやったぜいと思ってたら、当然とうの昔に修正されている既知のバグでした。
ノートによると5.3.5では直っていたようです。
PHP5.4.7では正しく計算されるようになっていたのを確認しました。
PHPではしれっとこういうことがあったりするのが怖いですね。
http://qiita.com/Nabetani/items/4c60f10b73812e86441c
http://nabetani.sakura.ne.jp/hena/ord6lintersection/
L字型の領域をふたつ作り、重なった部分の数を算出するという問題。
一見めんどくさそうですが、実はL字じゃなくて長方形*2とみなせば余計なこと考えなくていいので楽。
30分くらいで終わりました。
埋める部分の求め方がとっても力業なかんじがしますが、先日諦めたビット演算を今回はうまく使えたので満足です。
なお30分にはコメントとかは含んでいません。
ガガッと書いて30分で動いた、完成!としてから整形してJavadocとか書いてます。
それにしてもいくら読んでもこれが理解できぬ。
「オフラインリアルタイムどう書く」の一覧
http://nabetani.sakura.ne.jp/hena/ord6lintersection/
L字型の領域をふたつ作り、重なった部分の数を算出するという問題。
一見めんどくさそうですが、実はL字じゃなくて長方形*2とみなせば余計なこと考えなくていいので楽。
<?php
class INTERSECTION{
/**
* 面積を返す
* @param String 「23-94-28,89-06-51」みたいな文字列
* @return String 「11」みたいな文字列
*/
public function get($input){
// 10*10のマップ
$map = str_repeat('0', 100);
// 入力値を分割
$input = explode(',', $input);
$data1 = explode('-', $input[0]);
$data2 = explode('-', $input[1]);
// マップ埋め
$map = $this->bury($map, $data1[0], $data1[1], 1);
$map = $this->bury($map, $data1[0], $data1[2], 1);
$map = $this->bury($map, $data2[0], $data2[1], 2);
$map = $this->bury($map, $data2[0], $data2[2], 2);
// 重複したところをカウント
return (string)substr_count($map, '3');
}
/**
* 長方形内部をビット和で埋める
* @param String マップ
* @param String 頂点の座標
* @param String 対角線上の頂点の座標
* @param int 埋める値
* @return String マップをビット和で埋めたもの
*/
public function bury($map, $angle1, $angle2, $val){
for($x = min( $angle1[0], $angle2[0] );$x <= max( $angle1[0], $angle2[0] ); $x++){
for($y = min( $angle1[1], $angle2[1] );$y <= max( $angle1[1], $angle2[1] ); $y++){
$map[(int)$x.$y] = $map[(int)$x.$y] | $val;
}
}
return $map;
}
}
// テスト
$test = [
['23-94-28,89-06-51', '11'],
/* 省略 */
];
$intersection = new INTERSECTION();
foreach($test as $key=>$data){
$answer = $intersection->get($data[0]);
if($answer !== $data[1]){
print('えらー');
}
}
30分くらいで終わりました。
埋める部分の求め方がとっても力業なかんじがしますが、先日諦めたビット演算を今回はうまく使えたので満足です。
なお30分にはコメントとかは含んでいません。
ガガッと書いて30分で動いた、完成!としてから整形してJavadocとか書いてます。
それにしてもいくら読んでもこれが理解できぬ。
「オフラインリアルタイムどう書く」の一覧
http://qiita.com/Nabetani/items/5e1c944541f09f0f9711
http://nabetani.sakura.ne.jp/hena/ord6kinship/
家系図から二人の関係を算出します。
時間は30分足らず。
さてロジックをよく見てみると、姉妹であるかのチェックで、自分自身ではないという確認を行っていません。
よって実際は正確な判定ではないのですが、しかし今回は先に自分自身であるかを確認しているので事実上問題ありません。
おば判定で親チェックを行っていない、いとこ判定で姉妹や自分自身チェックを行っていないことについても同様です。
順不同でもきちんと判定を行いたいのであればそこらのチェックも必要になります。
「オフラインリアルタイムどう書く」の一覧
http://nabetani.sakura.ne.jp/hena/ord6kinship/
家系図から二人の関係を算出します。
<?php
class RELATIONSHIP{
/**
* 続柄を返す
* @param String 「5->2」みたいな文字列
* @return String 「mo」みたいな文字列
*/
public function get($input){
// 続柄
$relation = ['me', 'mo', 'da', 'si', 'au', 'ni', 'co'];
// ->で分割
list($from, $to) = explode('->', $input, 2);
$from = (int)$from;
$to = (int)$to;
// 続柄判断
foreach($relation as $val){
if($this->{'is'.ucfirst($val)}($from, $to)){ return $val; }
}
return '-';
}
// 自分自身であるか
private function isMe($from, $to){
return $from === $to;
}
// 親であるか
private function isMo($from, $to){
return $this->getMo($from) === $to;
}
// 娘であるか
private function isDa($from, $to){
return $this->getMo($to) === $from;
}
// 姉妹であるか
private function isSi($from, $to){
return $this->getMo($from) === $this->getMo($to);
}
// おばであるか
private function isAu($from, $to){
return $this->getMo($this->getMo($from)) === $this->getMo($to);
}
// 姪であるか
private function isNi($from, $to){
return $this->getMo($this->getMo($to)) === $this->getMo($from);
}
// いとこであるか
private function isCo($from, $to){
return $this->getMo($this->getMo($to)) === $this->getMo($this->getMo($from));
}
// 母を取得
private function getMo($from){
return intval(($from+1)/3);
}
}
// テスト
$test = [
['5->2', 'mo'],
/* 省略 */
];
$relationship = new RELATIONSHIP();
foreach($test as $key=>$data){
$answer = $relationship->get($data[0]);
if($answer !== $data[1]){
print('えらー');
}
}
とりあえず各メソッドを作っていたら答えになっていた。時間は30分足らず。
さてロジックをよく見てみると、姉妹であるかのチェックで、自分自身ではないという確認を行っていません。
よって実際は正確な判定ではないのですが、しかし今回は先に自分自身であるかを確認しているので事実上問題ありません。
おば判定で親チェックを行っていない、いとこ判定で姉妹や自分自身チェックを行っていないことについても同様です。
順不同でもきちんと判定を行いたいのであればそこらのチェックも必要になります。
「オフラインリアルタイムどう書く」の一覧