忍者ブログ
[PR]
×

[PR]上記の広告は3ヶ月以上新規記事投稿のないブログに表示されています。新しい記事を書く事で広告が消えます。



2025/01/17 05:49 |
PHP5.5.3 PHPでナウいカレンダー
PHPでカレンダーとか死ぬほどよくありますが、mktime()とか使って手動で作ってるタイプばっかりで、DateTimeを使ったカレンダーが見当たらなかったので作ってみる。
<?php
// かれんだー
class Calendar{
	
	private $datetime;
	public function getDatetime(){ return clone $this->datetime; }
	
	/**
	* コンストラクタ
	* @param int 年
	* @param int 月
	* @param int 日
	*/
	public function __construct($year = NULL, $month = NULL, $day = NULL){
		// デフォルト
		$default = new DateTime();
		if($year  ===NULL){ $year  = $default->format('Y'); }
		if($month ===NULL){ $month = $default->format('m'); }
		if($day   ===NULL){ $day   = $default->format('d'); }

		// 本日
		$str =sprintf('%04d-%02d-%02d', (int)$year, (int)$month, (int)$day);
		$this->datetime = DateTime::createFromFormat('Y-m-d', $str, new DateTimeZone('Asia/Tokyo'));
		if(!$this->datetime){ throw new InvalidArgumentException(); }
	}
	
	/**
	* 日曜開始、土曜終了のカレンダーを取得
	* @return DatePeriod
	*/
	public function getCalendar(){

		// 開始日 月初を含む週の日曜日
		$start = clone $this->datetime;
		$start->modify('first day of')->modify('+1 day')->modify('last Sunday');

		// 終了日 月末を含む週の土曜の次の日 DatePeriodは最終日が含まれないため+1する
		$finish = clone $this->datetime;
		$finish->modify('last day of')->modify('-1 day')->modify('next Saturday')->modify('+1 day');
		
		return new DatePeriod($start, new DateInterval('P1D'), $finish);
	}
}

	// インスタンス
	$calendar = new Calendar($_REQUEST['y'], $_REQUEST['m'], $_REQUEST['d']);
	
	// 画面表示
	print('<table><tr><th>日</th><th>月</th><th>火</th><th>水</th><th>木</th><th>金</th><th>土</th></tr><tr>');
	foreach($calendar->getCalendar() as $key=>$val){
		if($val->format('w') === '0'){
			// 日曜日
			print('<tr><td>');
		}else{
			// その他
			print('</td><td>');
		}
		
		if($val->format('m') === $calendar->getDatetime()->format('m')){
			// 当月
			print($val->format('d'));
		}else{
			// 当月ではない
			print(' ');
		}
		
		if($val->format('w') === '6'){
			// 土曜日
			print('</td></tr>');
		}
	}
	print('</table>');
2038年問題フリーで、9999年まで使えるカレンダーです。

当月や週末の判定が微妙だな。
完全にやるならDatePeriodをくるくるしたときに出てくるDateTimeを上書きしてisPresentMonth()的なメソッドを追加するか、描画系もクラス内で行えるようにしておくとよいでしょう。

ここまで作っておいてなんですが、どうしても外部ライブラリが許されざる状況にあるとかでない限りはPEAR::Calendarとかに任せとけばいいんじゃないかな。
PR


2013/12/20 23:48 | Comments(0) | PHP
PHP5.5.3 PHPでgoto
PHP5.3で悪名高いgotoが実装されました。

あえて実装されたということはそれだけ有用でもあるということでしょう。
前作ったフィボナッチ数列をgotoで再現してみましょう。
<?php
	
	function fib5($n){
		$fib= [0, 1];
		$count = 1;
		
		loop:
		$count++;
		$fib[$count] = $fib[$count-1] + $fib[$count-2];
		if(!isset($fib[$n])){ goto loop; }
		
		return $fib[$n];
	}
あれ、予想外にわかりやすい。
しかもfib3()並に高速です。
本当は「goto使うのはやめとけ」って書くつもりだったのだがどうしてこうなった。

gotoの本当の恐ろしさ(そして有用さ)は、「あらゆる文脈を無視して強制的にジャンプを行うことができる」という点です。
PHPの場合は同一ファイル内のみ、関数内←→関数外への移動はできないなど一部制限はありますが、それでもその威力は暴力的です。
<?php
	// http://www.php.net/manual/ja/control-structures.goto.php#109027
	$link = true;

	if($link)goto iw_link_begin;
	iw__link_begin:
	if($link)goto iw_link_text;
	iw__link_text:
	if($link)goto iw_link_end;
	iw__link_end:

	goto iw_end_gt;

	iw_link_begin:
		echo'<a href="#">';
		goto iw__link_begin;
	
	iw_link_text:
		echo'SampleText';
		goto iw__link_text;
	
	iw_link_end:
		echo'</a>';
		goto iw__link_end;
	
	iw_end_gt:
	
	// 普通に書くとこう
	if($link)iw_link_begin();
	if($link)iw_link_text();
	if($link)iw_link_end();
	
	function iw_link_begin(){
		echo'<a href="#">';
	}
	function iw_link_text(){
		echo'SampleText';
	}
	function iw_link_end(){
		echo'</a>';
	}
上記はマニュアルのコメントに書かれている例ですが、こんなもん納品されてきた日には実装者をぶん殴るしかない。

なおgotoのラベルには値しか使用できないようです。
変数はおろか定数すら指定できません。
<?php
	$a = 'label1';
	goto $a;
	label1:
みたいなコードはパースエラーになります。
まあ、万一これが動いてしまったら更なる地獄になるのは間違いありませんが。

実のところPHPではgotoの使いどころがほぼありません。
他の関数が豊富なので、あえて使おうと思わない限り出番がないんですよね。
他言語では唯一の使いどころとして挙げられる多重ループ脱出についても、PHPでは普通に脱出レベルを設定できます。
いったいどんなときに使えばいいのか、私にはよくわかりません。


2013/12/13 22:45 | Comments(0) | PHP
PHP5.5.3 「第15回オフラインリアルタイムどう書くの問題」をPHPで解く
http://qiita.com/Nabetani/items/cba03c96d1ea55f6e861
http://nabetani.sakura.ne.jp/hena/ord15elebubo/

異星の電光掲示板。
解き方自体は前やったエントロピー符号と同じです。
しかし今回は、単純に「00」を詰めると「110111101110」みたいな一意にならない値が出てしまうので注意が必要です。
と思ったけど別に注意するようなことは全くなかった。

<?php
	class ELEBUBO{
		
		/**
		* 異星の電光掲示板
		* @param String 「2ed8aeed/34b0ea5b」みたいな文字列
		* @return String 「LTRSUNTSJ」みたいな文字列
		*/
		public function get($input){
			// 入力を2進数に
			$input =explode('/', $input);
			$upper = sprintf('%032s', base_convert($input[0], 16, 2));
			$under = sprintf('%032s', base_convert($input[1], 16, 2));
			// 一列にする
			$string = '';
			for($key=0;$key<strlen($upper); $key++){
				$string .= $upper[$key] . $under[$key];
			}
			// 置換
			$search = ['00', '101110', '110111', '111011', '011110', '101101', '1101', '1110', '0111'];
			$replace = ['', 'T', 'U', 'N', 'S', 'Z', 'L', 'R', 'J'];
			$ret = '';
			do{
				foreach($search as $key=>$val){
					if(strpos($string, $val) === 0){
						$string = substr($string, strlen($val));
						$ret .= $replace[$key];
						continue 2;
					}
				}
			}while(strlen($string));
			
			return $ret;
		}
		
	}
	
	// 以下はテスト
	$test = [
		['2ed8aeed/34b0ea5b', 'LTRSUNTSJ'],
		['00000200/00000300', 'L'],
		['00018000/00010000', 'R'],
		['00002000/00006000', 'J'],
		['00000700/00000200', 'T'],
		['01400000/01c00000', 'U'],
		['00003800/00002800', 'N'],
		['000c0000/00180000', 'S'],
		['00003000/00001800', 'Z'],
		['132eae6c/1a64eac6', 'LRJTUNSZ'],
		['637572d0/36572698', 'ZSNUTJRL'],
		['baddb607/d66b6c05', 'LTJZTSSSN'],
		['db74cd75/6dac6b57', 'ZZZTJZRJNU'],
		['3606c2e8/1b0d8358', 'ZZSSLTJ'],
		['ad98c306/e6cc6183', 'UZZZZZZ'],
		['4a4aaee3/db6eeaa6', 'JJLLUUNNS'],
		['ecd9bbb6/598cd124', 'TSSZZTTRR'],
		['e0000002/40000003', 'TL'],
		['a0000007/e0000005', 'UN'],
		['c0000003/80000006', 'RS'],
		['40000006/c0000003', 'JZ'],
		['01da94db/00b3b6b2', 'TSUJLRSR'],
		['76eeaaea/24aaeeae', 'TRNNUUNU'],
		['1dacaeee/1566e444', 'NRJZUTTT'],
		['26c9ac60/6c6d66c0', 'JSZLRJZS'],
		['6c977620/36da5360', 'ZZLLTNZJ'],
		['069aeae6/0db34eac', 'SJSLTUNS'],
		['06d53724/049da56c', 'RRULRNJJ'],
		['069b58b0/04d66da0', 'RLRSLZJR'],
		['1b6eced4/11b46a9c', 'RZZTZNRU'],
		['522e8b80/db6ad900', 'JLLJNLJT'],
		['6546cdd0/376c6898', 'ZULSZRTL'],
		['4e6d5b70/6ad9d620', 'LNSSURST'],
		['37367772/65635256', 'SNSZNTNJ'],
		['25535d58/377669cc', 'LUUSLTUZ'],
		['0ae6a55d/0eacedcb', 'UNSUJUTJ'],
		['76762edc/23536a88', 'TZNZJNRT'],
		/**/
	];

	$elebubo = new ELEBUBO();
	foreach($test as $key=>$data){
		$answer = $elebubo->get($data[0]);
		if($answer !== $data[1]){
			print('えらー');
		}
	}
うーん置換のあたりが微妙。
preg_replace()とかでまとめてできないかと思ったけど無理だった。
かかった時間は45分くらい。

ところでBUBOって何ですかね。


2013/11/15 23:59 | Comments(0) | PHP
PHP5.5.0 「第14回オフラインリアルタイムどう書くの問題」をPHPで解く
http://qiita.com/Nabetani/items/0597bd3af481e5834ae1
http://nabetani.sakura.ne.jp/hena/ord14linedung/
眠れるモンスターを狩ります。
武器AでモンスターBを狩れる、モンスターBは武器Cを落とす、武器CはモンスターDを狩れる、という連鎖です。
<?php
	
	class MONSTER{
		// 武器で狩れるモンスターと落とす武器
		private $list = [
			'a' => 'Bc',
			'c' => 'De',
			'e' => 'Fg',
			'g' => 'Hi',
			'i' => 'Jk',
			'k' => 'La',
		];
	
		/**
		* 狩ったモンスターの数を返す
		* @param String 「gLDLBgBgHDaD」みたいな文字列
		* @return int 「6」みたいな数値
		*/
		public function get($input){
			// 初期値
			$weapons = new ArrayIterator();
			$monsters = [];
			$ret = 0;
		
			// 入力値を整形
			foreach(count_chars($input, 1) as $key=>$val){
				// 小文字は武器、大文字はモンスター
				if($key < 97){
					$monsters[chr($key)] = $val;
				}else{
					$weapons[chr($key)] = $val;
				}
			}
			
			// 武器でくるくる
			foreach($weapons as $weapon=>$val){
				// その武器で狩れるモンスターがいれば
				if(isset($monsters[$this->list[$weapon][0]])){
					// 狩る
					$ret += $monsters[$this->list[$weapon][0]];
					// 落とした武器を入手
					$weapons[$this->list[$weapon][1]] = 1;
				}
			}
			
			return $ret;
		}
	}
	
	// 以下はテスト
	$test = [
		['gLDLBgBgHDaD', '6'],
		['DBcDLaLgDBH', '6'],
		['JJca', '0'],
		['FJDLBH', '0'],
		['HJBLFDg', '6'],
		['HBaDLFJ', '6'],
		['DJaHLB', '2'],
		['gDLHJF', '3'],
		['cJFgLHD', '5'],
		['FFBJaJJ', '1'],
		['FJeJFBJ', '2'],
		['iJFFJJB', '3'],
		['JBJiLFJF', '5'],
		['JDiFLFBJJ', '8'],
		['BDFDFFDFFLLFFJFDBFDFFFFDDFaDBFFB', '28'],
		['DDFBFcBDFFFFFFLBFDFFBFLFDFDJDFDF', '24'],
		['FDLBFDDBFFFeFFFFFDFBLDDFDDFBFFJF', '16'],
		['FDBFFLFDFFDBBDFFBJDLFgDFFFDFFDFF', '0'],
		['FDiFLDFFFFBDDJDDBFBFDFFFBFFDFLFF', '31'],
		['FDFDJBLBLBFFDDFFFDFFFFFDDFBkFDFF', '30'],
		['HBkFFFFHBLH', '3'],
		['FBHHFFFHLaB', '2'],
		['LFHFBBcHFHF', '0'],
		['LFBHFFeFHBH', '7'],
		['LgFHHHBFBFF', '3'],
		['FFiFHBHLBFH', '0'],
		['BFHHFFHBeFLk', '10'],
		['FHFaBBHFHLFg', '5'],
		['FFgacaFg', '0'],
		['JHDaDcBJiiHccBHDBDH', '9'],
		['FHJJLckFckFJHDFF', '12'],
		['DeDHJHDFHJBLHDLLDHJLBDD', '22'],
		['gJLLLJgJgJLJL', '0'],
		['DaaaDDD', '0'],
		['HFeJFHiBiiBJeJBBFFB', '9'],
		['FJFFJDBHBHaLJBHJHDLHkLLLFFFgJgHJLHkJkB', '32'],
		['giFLBiBJLLJgHBFJigJJJBLHFLDLL', '23'],
		['cgkLJcLJJJJgJc', '2'],
		['LDFHJHcFBDBLJBLFLcFJcDFBL', '22'],
		['JJHHHkHJkHLJk', '1'],
		['kHHBBaBgHagHgaHBBB', '11'],
		['HDBFFDHHHDFLDcHHLFDcJD', '20'],
		['HFFFHeFFee', '7'],
		['gLLDHgDLgFL', '1'],
		['JJJBBaBBHBBHaLBHJ', '7'],
		['FBFBgJBDBDgF', '0'],
		['LLLLakakLakLL', '7'],
		['HeJHeJe', '0'],
		['LDFLBLLeBLDBBFFBLFBB', '4'],
	];

	$monster = new MONSTER();
	foreach($test as $key=>$data){
		$answer = $monster->get($data[0]);
		if($answer !== (int)$data[1]){
			print('えらー');
		}
	}

単純に、手持ちの武器でモンスターを狩って、その戦利品で次のモンスターを狩って、を繰り返しただけです。
ArrayIteratorは、反復処理中に値の変更が可能という便利な配列です。
ここが普通の配列だとaddしたループ中は参照してくれません。

かかった時間は1時間くらい。
最初上で書いたとおり普通の配列でやろうとして動かなかった。
あとモンスターと武器の文字が順に並んでるので、ビット演算とかで解けないかと思ったがさっぱりわからなかった。


「オフラインリアルタイムどう書く」の一覧



2013/11/08 23:59 | Comments(0) | PHP
paluの忘却録『phpで特定の日付からある日数分前の日付一覧を取得する』の感想
http://d.hatena.ne.jp/palu0707/20131030/1383143532

とりあえずgetDay()を実行してみる。

Notice: Undefined variable: lenght in C:\xampp\test.php on line 33
Notice: Undefined offset: 6 in C:\xampp\test.php on line 50
Notice: Undefined offset: 5 in C:\xampp\test.php on line 50
Notice: Undefined offset: 4 in C:\xampp\test.php on line 50
Notice: Undefined offset: 3 in C:\xampp\test.php on line 50
Notice: Undefined offset: 2 in C:\xampp\test.php on line 50
Notice: Undefined offset: 1 in C:\xampp\test.php on line 50

array(3) {
  ["year"]=>
  string(4) "2013"
  ["month"]=>
  array(2) {
    [0]=>
    int(10)
    [1]=>
    string(2) "11"
  }
  ["day"]=>
  array(7) {
    [0]=>
    int(6)
    [6]=>
    int(31)
    [5]=>
    int(31)
    [4]=>
    int(31)
    [3]=>
    int(31)
    [2]=>
    int(31)
    [1]=>
    int(31)
  }
}
line 50はforの行です。
これを実行したのは2013/11/06。
月またぎの処理に異常があるようです。
修正しましょう。
というか、こういう処理はビルトインに任せるべきで、わざわざ自力でやる意味は全くありません。
<?php
	function getDay($year = NULL, $month = NULL, $day = NULL, $length = NULL) {
		if(!$year)  {$year   = date('Y');}
		if(!$month) {$month  = date('m');}
		if(!$day)   {$day    = date('d');}
		if(!$length){$length = 6;}
		
		// 終了日
		$end = new DateTime($year.'-'.$month.'-'.$day, new DateTimeZone('Asia/Tokyo'));
		// 開始日
		$start = clone $end;
		$start->modify($length . ' days ago');
		// DatePeriodにして返す
		return new DatePeriod($start, new DateInterval('P1D'), $end);
	}
	
	// 使い方
	$datePeriod = getDay();
	foreach($datePeriod as $key=>$val){
		print(($key+1) . '日目:' . $val->format('Y年m月d日'));
	}
跡形が無くなってしまった。
閏年なんてこちら側では一切考慮する必要はなく、DateTimeがよしなに処理してくれます。
返り値はDatePeriodなので、返ってきた側での使い方も非常に簡単です。


2013/11/06 23:08 | Comments(0) | PHP
PHP5.5.0 「第1回オフラインリアルタイムどう書くの参考問題」をPHPで解く
http://qiita.com/Nabetani/items/cbc3af152ee3f50a822f

ポーカーの役を求めます。
集計する対象はワンペア、ツーペア、スリーカード、フォーカード、フルハウス。
つまりスートは一切無視してよいということです。
<?php

	class POKER{
		// 役
		private $roles = [
			'4K'=>[4, 1],
			'FH'=>[3, 2],
			'3K'=>[3, 1, 1],
			'2P'=>[2, 2, 1],
			'1P'=>[2, 1, 1, 1],
		];
		
		/**
		* ポーカー
		* @param  String 「D3C3C10D10S3」みたいな文字列
		* @return String 「FH」みたいな文字列
		*/
		public function get($input){
			// 値をカウント
			$cards = array_count_values(explode('-', trim( str_replace(['S', 'H', 'D', 'C'], '-', $input), '-')));
			rsort($cards);
			// 同じ役があるか確認
			foreach($this->roles as $key=>$val){
				if($cards === $val){
					return $key;
				}
			}
			// なかった
			return '--';
		}
	}
	
	// テスト
	$test = [
		['D3C3C10D10S3', 'FH'],
		['S8D10HJS10CJ', '2P'],
		['DASAD10CAHA', '4K'],
		['S10HJDJCJSJ', '4K'],
		['S10HAD10DAC10', 'FH'],
		['HJDJC3SJS3', 'FH'],
		['S3S4H3D3DA', '3K'],
		['S2HADKCKSK', '3K'],
		['SASJDACJS10', '2P'],
		['S2S10H10HKD2', '2P'],
		['CKH10D10H3HJ', '1P'],
		['C3D3S10SKS2', '1P'],
		['S3SJDAC10SQ', '--'],
		['C3C9SAS10D2', '--'],
	];

	$poker = new POKER();
	foreach($test as $key=>$data){
		$answer = $poker->get($data[0]);
		if($answer !== $data[1]){
			print('えらー');
		}
	}
数字ごとの枚数に一切ぶれがないため、===で簡単にマッチング可能です。
これまでで一番簡単だった気がします。
かかった時間は20分程度。


「オフラインリアルタイムどう書く」の一覧



2013/09/30 23:41 | Comments(0) | PHP
PHP5.5.0 「第1回オフラインリアルタイムどう書くの問題」をPHPで解く
http://nabetani.sakura.ne.jp/hena/1/

三目並べの勝敗を決定します。
<?php
	class TICKTACKTOE{
		
		// 勝利パターン
		private $pattern = [
			'/o..o..o|^(...){0,2}ooo|o...o...o|..o.o.o../',
			'/x..x..x|^(...){0,2}xxx|x...x...x|..x.x.x../'
		];
		// プレイヤー
		private $player = ['o', 'x'];
		
		/**
		* 三目並べ
		* @param  String 「79538246」みたいな文字列
		* @return String 「x won.」みたいな文字列
		*/
		public function get($input){
			// 9文字で打ち切り
			$input = substr($input, 0, 9);
			// 初期化
			$tick = '---------';
			
			for($i=0; $i<strlen($input); $i++){
				// 既に入っていたら負け
				if($tick[$input[$i]-1] !== '-'){
					return 'Foul : '.$this->player[($i+1)%2].' won.';
				}
				
				// 該当値をセット
				$tick[$input[$i]-1] = $this->player[$i%2];
				
				// 勝っていれば終了
				if(preg_match($this->pattern[$i%2], $tick)){
					return $this->player[$i%2].' won.';
				}
			}
			
			// 引き分け
			return 'Draw game.';
		}
	}
	
	// テスト
	$test = [
		['79538246', 'x won.'],
		['35497162193', 'x won.'],
		['61978543', 'x won.'],
		['254961323121', 'x won.'],
		['6134278187', 'x won.'],
		['4319581', 'Foul : x won.'],
		['9625663381', 'Foul : x won.'],
		['7975662', 'Foul : x won.'],
		['2368799597', 'Foul : x won.'],
		['18652368566', 'Foul : x won.'],
		['965715', 'o won.'],
		['38745796', 'o won.'],
		['371929', 'o won.'],
		['758698769', 'o won.'],
		['42683953', 'o won.'],
		['618843927', 'Foul : o won.'],
		['36535224', 'Foul : o won.'],
		['882973', 'Foul : o won.'],
		['653675681', 'Foul : o won.'],
		['9729934662', 'Foul : o won.'],
		['972651483927', 'Draw game.'],
		['5439126787', 'Draw game.'],
		['142583697', 'Draw game.'],
		['42198637563', 'Draw game.'],
		['657391482', 'Draw game.'],
	];

	$ticktacktoe = new TICKTACKTOE();
	foreach($test as $key=>$data){
		$answer = $ticktacktoe->get($data[0]);
		if($answer !== $data[1]){
			print('えらー');
		}
	}
なんの変哲もなく、普通に正規表現で勝利パターンを引っかけてるだけです。
勝利パターンは8種類しかないので別に正規表現使わなくても十分だったりしますがまあいいや。

ちなみに「o..o..o」が縦、「^(...){0,2}ooo」が横、「o...o...o」「..o.o.o..」が斜めです。
まあ見ればわかるか。


「オフラインリアルタイムどう書く」の一覧



2013/09/27 23:59 | Comments(0) | PHP
PHP5.5.0 「第2回オフラインリアルタイムどう書くの参考問題」をPHPで解く
http://qiita.com/Nabetani/items/9d80de41903775296ca6

画像を回転させる問題です。
絶対に誰も真似しない方法で回答。
<?php

	class ROTATE{
		
		/**
		* 画像を回転させる
		* @param  String 「3:5b8」みたいな文字列
		* @return String 「3:de0」みたいな文字列
		*/
		public function get($input){
			// 入力を2進数に
			list($size, $hex) = explode(':', $input);
			$bit = '';
			$tmp = str_split($hex, 4);
			foreach($tmp as $key=>$val){
				$bit .= sprintf('%0'.(strlen($val)*4).'s', base_convert($val, 16, 2));
			}
			
			// 指定サイズの黒画像を作成
			$image = imagecreatetruecolor($size, $size);
			$dot = imagecolorallocate($image, 0, 0, 1);
			
			// 1のビットに点を打つ
			for($y=0; $y<$size; $y++){
				for($x=0; $x<$size; $x++){
					if($bit[$x+$y*$size]){
						imagesetpixel($image, $x, $y, $dot);
					}
				}
			}
			
			// 画像を回転
			$image = imagerotate($image, 270, 0);
			
			// 色を取得
			$rot = '';
			for($y=0; $y<$size; $y++){
				for($x=0; $x<$size; $x++){
					$rot .= imagecolorat($image, $x, $y);
				}
			}
			imagedestroy($image);
			
			// 16進数にして戻す
			$rot = str_pad($rot, (strlen($bit)), '0', STR_PAD_RIGHT);
			$ret = '';
			$tmp = str_split($rot, 16);
			foreach($tmp as $key=>$val){
				$ret .= sprintf('%0'.(strlen($val)/4).'s', base_convert($val, 2, 16));
			}
			return $size . ':' . $ret;
		}
	}
	
	// テスト
	$test = [
		['3:5b8', '3:de0'],
		['1:8', '1:8'],
		['2:8', '2:4'],
		['2:4', '2:1'],
		['2:1', '2:2'],
		['3:5d0', '3:5d0'],
		['4:1234', '4:0865'],
		['5:22a2a20', '5:22a2a20'],
		['5:1234567', '5:25b0540'],
		['6:123456789', '6:09cc196a6'],
		['7:123456789abcd', '7:f1a206734b258'],
		['7:fffffffffffff', '7:ffffffffffff8'],
		['7:fdfbf7efdfbf0', '7:ffffffffffc00'],
		['8:123456789abcdef1', '8:f0ccaaff78665580'],
		['9:112233445566778899aab', '9:b23da9011d22daf005d40'],
	];

	$rotate = new ROTATE();
	foreach($test as $key=>$data){
		$answer = $rotate->get($data[0]);
		if($answer !== $data[1]){
			print('えらー');
		}
	}
実際に画像を作って回転させました。
もちろん、このような回りくどいことをする必要性は皆無です。
単にやってみたかっただけという。

なおbase_convert()のあたりがややこしいのは、16桁以上の16進数をbase_convert()に突っ込むと正しくない値が返ってきてしまうせいです。
そのせいで最後の2サンプルだけ正しく動かなかったという。


「オフラインリアルタイムどう書く」の一覧



2013/09/23 22:47 | Comments(0) | PHP
PHP5.5.0 「第2回オフラインリアルタイムどう書くの問題」をPHPで解く
http://nabetani.sakura.ne.jp/hena/ord2/

配置済のテトリスです。
横に揃った行を削除して、消した結果を出力します。
<?php
	class TETRIS{
		
		/**
		* テトリス
		* @param  String 「ff-2f-23-f3-77-7f-3b」みたいな文字列
		* @return String 「1f-03-00-1c-0d-0f-06」みたいな文字列
		*/
		public function get($input){
			// 入力
			$input = explode('-', $input);
			$arr = array_fill(0, 8, '');
			$arr2 = array_fill(0, count($input), '');
			$ret = '';
			
			// 横向きに切る
			foreach($input as $key=>$val){
				$tmp = sprintf('%08s', base_convert($val, 16, 2));
				for($i=0; $i<8; $i++){
					$arr[$i] .= $tmp[$i];
				}
			}
			// 揃ってるところは消えて落ちる
			foreach($arr as $key=>$val){
				if(strpos($val, '0')=== false){
					unset($arr[$key]);
					array_unshift($arr, str_repeat('0', strlen($val)));
				}
			}
			// 縦に戻す
			foreach($arr as $key=>$val){
				for($i=0; $i<strlen($val); $i++){
					$arr2[$i] .= $val[$i];
				}
			}
			// 文字列にして戻す
			foreach($arr2 as $key=>$val){
				$ret .= '-' . sprintf('%02s', base_convert($val, 2, 16));
			}
			return substr($ret, 1);
		}
	}
	
	// テスト
	$test = [
		['ff-2f-23-f3-77-7f-3b', '1f-03-00-1c-0d-0f-06'],
		['01', '00'],
		['00', '00'],
		['7a-4e', '0c-02'],
		['56-b6', '08-14'],
		['12-12-12', '00-00-00'],
		['de-ff-7b', '0a-0f-05'],
		['95-be-d0', '05-1e-20'],
		['7c-b0-bb', '1c-20-2b'],
		['7a-b6-31-6a', '3a-56-11-2a'],
		['32-0e-23-82', '18-06-11-40'],
		['ff-7f-bf-df-ef', '0f-07-0b-0d-0e'],
		['75-df-dc-6e-42', '35-5f-5c-2e-02'],
		['62-51-ef-c7-f8', '22-11-6f-47-78'],
		['0c-47-8e-dd-5d-17', '04-23-46-6d-2d-0b'],
		['aa-58-5b-6d-9f-1f', '52-28-2b-35-4f-0f'],
		['ff-55-d5-75-5d-57', '0f-00-08-04-02-01'],
		['fe-fd-fb-f7-ef-df-bf', '7e-7d-7b-77-6f-5f-3f'],
		['fd-fb-f7-ef-df-bf-7f', '7e-7d-7b-77-6f-5f-3f'],
		['d9-15-b5-d7-1b-9f-de', '69-05-55-67-0b-4f-6e'],
		['38-15-fd-50-10-96-ba', '18-05-7d-20-00-46-5a'],
		['fe-fd-fb-f7-ef-df-bf-7f', 'fe-fd-fb-f7-ef-df-bf-7f'],
	];

	$tetris = new TETRIS();
	foreach($test as $key=>$data){
		$answer = $tetris->get($data[0]);
		if($answer !== $data[1]){
			print('えらー');
		}
	}
言いたいことはわかる。
何回ループ回してんだよ。

見たかんじビット演算使えば即座に解けるような内容だと思うんですよね。
しかし私はビット演算が苦手(というかまともに勉強したことがない)ので、入力を横に切って全部1だったら消すという超絶力業での回答です。
いやはや酷いもんだ。

かかった時間は1時間くらい。


「オフラインリアルタイムどう書く」の一覧


2013/09/20 23:57 | Comments(0) | PHP
PHP5.5.0 「第3回オフラインリアルタイムどう書くの参考問題」をPHPで解く
http://qiita.com/Nabetani/items/ebd8a56b41711ba459f9

野球のスコアカウントを行います。
得点やランナー等の無い超簡易版です。
<?php

	class BASEBALL{
		
		/**
		* 野球のスコアカウント
		* @param  String 「ssbbbb」みたいな文字列
		* @return String 「010,020,021,022,023,000」みたいな文字列
		*/
		public function get($input){
			$baseball = [[0, 0, 0]];
			
			// すすめる
			for($i=0; $i<strlen($input); $i++){
				$baseball[] = $this->{'get'.strtoupper($input[$i])}(end($baseball));
			}
			
			// 文字列にして返す
			array_shift($baseball);
			$ret = '';
			foreach($baseball as $val){
				$ret .= ','.implode('',$val);
			}
			return substr($ret, 1);
		}
		
		// ストライク
		private function getS($input){
			// ストライク
			if(++$input[1] >= 3){
				$input[1] = 0;
				++$input[0];
				// アウト
				if($input[0] >=3){
					$input = [0, 0, 0];
				}
			}
			return $input;
		}
		
		// ボール
		private function getB($input){
			if(++$input[2] >= 4){
				$input[1] = $input[2] = 0;
			}
			return $input;
		}
		
		// ファウル
		private function getF($input){
			if($input[1] < 2){
				$input[1]++;
			}
			return $input;
		}
		
		// ヒット
		private function getH($input){
			$input[1] = $input[2] = 0;
			return $input;
		}
		
		// ピッチャーフライ
		private function getP($input){
			$input[1] = $input[2] = 0;
			// アウト
			if(++$input[0] >= 3){
				$input[0] = 0;
			}
			return $input;
		}
	}
	
	// テスト
	$test = [
		['s', '010'],
		['sss', '010,020,100'],
		['bbbb', '001,002,003,000'],
		['ssbbbb', '010,020,021,022,023,000'],
		['hsbhfhbh', '000,010,011,000,010,000,001,000'],
		['psbpfpbp', '100,110,111,200,210,000,001,100'],
		['ppp', '100,200,000'],
		['ffffs', '010,020,020,020,100'],
		['ssspfffs', '010,020,100,200,210,220,220,000'],
		['bbbsfbppp', '001,002,003,013,023,000,100,200,000'],
		['sssbbbbsbhsbppp', '010,020,100,101,102,103,100,110,111,100,110,111,200,000,100'],
		['ssffpffssp', '010,020,020,020,100,110,120,200,210,000']
	];

	$baseball = new BASEBALL();
	foreach($test as $key=>$data){
		$answer = $baseball->get($data[0]);
		if($answer !== $data[1]){
			print('えらー');
		}
	}
30分かからずで実装完了。
ひっかかるところが何一つ無かった。
やろうと思えば全サブルーチンを1行で実装可能ですが、そこまで削る必要もないでしょう。


「オフラインリアルタイムどう書く」の一覧


2013/09/16 23:59 | Comments(0) | PHP

<<前のページ | HOME | 次のページ>>
忍者ブログ[PR]