忍者ブログ
[PR]
×

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



2025/01/16 22:57 |
PHP5.3.7 「第7回オフラインリアルタイムどう書くの参考問題」をPHPで解く
http://qiita.com/Nabetani/items/7b08b0eb9ef84d7cfe49
http://nabetani.sakura.ne.jp/hena/ord7xysort/

行列をソートするというもの。
PHPにはarray_multisort()という超絶便利関数があるので、こいつ呼ぶだけで一発だろーはっはっはー、とか思って作り始めたところ、実は全てのソート関数が値が同じときの順番を保証しないという事実が発覚して全滅。
仕方ないので自力でソートする羽目に。なんてこった。

で、キーを維持するユーザ定義ソート関数にはusort()uksort()があるのですが、usort()はコールバックに値しか渡さない、uksort()はキーしか渡さないという意味のわからない仕様。
use使えばいいのですが、デフォでキーと値両方とも渡してくださいマジで。

<?php
	class XYSORT{
		
		/**
		* 二次元でソート
		* @param  String 「AvEx」みたいな文字列
		* @return String 「305027」みたいな文字列
		*/
		public function get($input){
			
			// 初期状態
			$table = [
				[4, 1, 4, 2, 1, 3],
				[7, 3, 2, 0, 5, 0],
				[2, 3, 6, 0, 6, 7],
				[6, 4, 5, 7, 5, 1],
				[3, 1, 6, 6, 2, 4],
				[6, 0, 5, 5, 5, 1]
			];
			// 文字に対応する列
			$map = [
				'A'=>0, 'B'=>1, 'C'=>2, 'D'=>3, 'E'=>4, 'F'=>5,
				'u'=>0, 'v'=>1, 'w'=>2, 'x'=>3, 'y'=>4, 'z'=>5
			];
			
			// 現在のテーブルが縦か横かのフラグ
			$tableCol = true;
			
			// 入力値でくるくる
			for($i=0; $i<strlen($input); $i++){
				// 縦か横か
				$isTableCol = (strtoupper($input[$i]) === $input[$i]);
				
				// 縦横が合ってないときは転置
				if($tableCol !== $isTableCol){
					$tableCol = !$tableCol;
					$table = $this->getTransposed($table);
				}
				
				// ソート基準列
				$columnid = (int)$map[$input[$i]];
				$column = $table[$columnid];
				
				// ソート基準列を、昇順安定ソート
				uksort($column, function($a, $b) use($column){
					if($column[$a] < $column[$b]){
						return -1;
					}elseif($column[$a] > $column[$b]){
						return 1;
					}else{
						return $a > $b;
					}
				});
				
				// テーブルを基準列に合わせてソート
				$tmp = [];
				foreach($column as $key=>$val){
					foreach($table as $row=>$data){
						$tmp[$row][] = $table[$row][$key];
					}
				}
				$table = $tmp;
			}
			
			// 最後に転置されてたら戻す
			if($tableCol === false){
				$table = $this->getTransposed($table);
			}
			
			// 終了
			return implode('', $table[0]);
		}
		
		/**
		* 転置行列を得る
		* {@see http://blog.supermomonga.com/articles/php/array-to-transverse-matrix.html }
		* @param  array 二次元配列
		* @return array 縦横を入れ替え
		*/
		private function getTransposed($array){
			return call_user_func_array('array_map', array_merge(array(null), $array));
		}
	}
	
	// テスト
	$test = [
		['AvEx', '305027'],
		/* 省略 */
	];

	$xysort = new XYSORT();
	foreach($test as $key=>$data){
		$answer = $xysort->get($data[0]);
		if($answer !== $data[1]){
			print('えらー');
		}
	}
いやー、想像以上に残念なコードになってしまった。
array_multisortにコールバックを渡せればねえ。

残念なのですが、いまいちこれよりよさげなアルゴリズムを考えつかないのでとりあえず保留。
またいずれリベンジしたいものですね。

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


2013/08/05 23:59 | Comments(0) | PHP
PHP5.3.7 「第7回オフラインリアルタイムどう書くの問題」をPHPで解く
http://qiita.com/Nabetani/items/4364285801d1c9f370a1
http://nabetani.sakura.ne.jp/hena/ord7selectchair/

トイレとかでよく見る光景です。
<?php
	class CHAIR{
	
		/**
		* 椅子に座る
		* @param  String 「6:NABEbBZn」みたいな文字列
		* @return String 「-ZAB-E」みたいな文字列
		*/
		public function get($input){
			// 入力値を分解
			list($num, $input) = explode(':', $input, 2);
			// 椅子のリスト 前後に門番
			$chairs = str_repeat('-', $num+2);
			
			// 検索用
			$loneliness = '---';
			$teteatete = '--';
			$lotlotlot = '-';
			
			// 順番に繰り返し
			for($i=0; $i<strlen($input); $i++){
			
				// 大文字であれば追加
				if(ctype_upper($input[$i])){
					
					// 両隣が空いてる
					if(($pos = strpos($chairs, $loneliness)) !== false){
						$chairs[$pos+1] = $input[$i];
						continue;
					}
					// 左端が空いてる
					if(substr($chairs, 0, 2) === $teteatete){
						$chairs[1] = $input[$i];
						continue;
					}
					// 右が空いてる (右端含む)
					if(($pos = strpos($chairs, $teteatete, 1)) !== false){
						$chairs[$pos] = $input[$i];
						continue;
					}
					// 両隣に人がいる
					$chairs[strpos($chairs, $lotlotlot, 1)] = $input[$i];
					continue;
				
				// 小文字であれば削除
				}else{
					$chairs = str_replace(strtoupper($input[$i]), '-', $chairs);
					continue;
				}
			}
			
			// 前後の門番を削除して返す
			return substr($chairs, 1, -1);
		}
		
	}
	
	// テスト
	$test = [
		['6:NABEbBZn', '-ZAB-E'],
		/* 省略 */
	];

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

右端は要らないのに左端は特殊な処理が必要というあたりが微妙な感じです。

かかった時間は1時間弱。
左端と右端の門番を別の文字にしてわかりやすくしようとしたらifが増えてわかりにくくなった。

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


2013/08/02 23:29 | Comments(0) | PHP
PHP5.3.7 TwitterOAuthのラッパー
前回「適当にinterface作ってそっちで吸収してくれよと非常に思う」とか言ったので、とりあえず一部だけやってみた。

インターフェイス
<?php
interface ITwitterOAuthWrapper{
	
	/**
	* トークンが有効か+ユーザ情報取得
	* @return stdClass
	*/
	public function verifyCredentials();
	
	/**
	* ツイートする
	* @param String 発言内容
	* @param array  オプション
	* @return stdClass
	*/
	public function tweet($text, $options = array());
	
	/**
	* ユーザ名でユーザ情報を取得
	* @param String ユーザ名
	* @param array  オプション
	* @return stdClass
	*/
	public function getUserInfoFromName($userName, $options = array());
	/**
	* ユーザIDでユーザ情報を取得
	* @param String ユーザID
	* @param array  オプション
	* @return stdClass
	*/
	public function getUserInfoFromId($userId, $options = array());
	
	/* 以下略 */
}

本体
<?php
class TwitterOAuthWrapper extends TwitterOAuth implements ITwitterOAuthWrapper{
	
	public function verifyCredentials(){
		return $this->get('account/verify_credentials');
	}
	public function tweet($text, $options = array()){
		return $this->post('statuses/update', array_merge($options, ['status'=>$text] ));
	}
	public function getUserInfoFromName($userName, $options = array()){
		return $this->get('users/show', array_merge($options, ['screen_name'=>$userName] ));
	}
	public function getUserInfoFromId($userId, $options = array()){
		return $this->get('users/show', array_merge($options, ['user_id'=>$userId] ));
	}
}

使い方
<?php
	// TwitterOAuthWrapper
	require_once('twitteroauth/TwitterOAuthWrapper.php');
	$TwitterOAuth = new TwitterOAuthWrapper('コンシューマキー', 'コンシューマシークレット', 'アクセストークン', 'アクセスシークレット');
	
	// トークンが有効か+ユーザ情報取得
	$user = $TwitterOAuth->verifyCredentials();
	
	// つぶやく
	$status = $TwitterOAuth->tweet('ツイート内容');
	
	// ユーザ情報を取得
	$userinfo = $TwitterOAuth->getUserInfoFromName('ユーザ名');
	$userinfo = $TwitterOAuth->getUserInfoFromId('ユーザID');
	
	// 元々の使い方も一応可能
	$status = $TwitterOAuth->post('statuses/update', ['status' =>'ツイート内容']);

使い方はITwitterOAuthWrapperの解説通りにメソッドを呼び出すだけ。
あとは必要に応じてインターフェイスとその実体を追加していくだけです。

こういう作りにして何がうれしいかというと、仕様変更に強くなる点。
もしツイートするURLが'statuses/update'から他に変わったとします。
元々の作りのように、呼び出し側にこのURLが書いてあった場合、ツイートしているところを全て書き直さなければなりません。
しかしTwitterOAuthWrapperであれば、tweetメソッド一箇所書き換えるだけでおわりです。

まあちょっと適当な作りなので、正直あまり気に入ってないです。
このまま実装を続けると、TwitterOAuthWrapperには延々ほぼ同じ呼び出し方のメソッドが並ぶ羽目になります。
なのでURLやリクエストメソッドなどは設定に持っておいて__callで一括処理とかしたかったわけですよ。
しかしinterfaceのメソッドは必ず実装が必要で、__callで受け取れないという。ぐぬぬ(当たり前)

そこでITwitterOAuthWrapperをimplementsしないというナイスな解決手段を思いついたのだがどうだろう。


2013/07/29 23:08 | Comments(0) | PHP
PHP5.3.7 TwitterOAuthの正しい使い方
PHP TwitterOAuth 1.1」でググると、

> $TwitterOAuth->OAuthRequest("http://api.twitter.com/1.1/statuses/update.json","POST",array("status"=>$tweet));

みたいなコードばっかり引っかかってぅぇぇとなるんですが。
誰かが最初に適当に書いたのをみんながコピペしたという過去が透けて見えるようだ。
まあ、動けばそれでいいというPHPの精神には則っているかもしれませんね。
<?php
	// TwitterOAuth
	require_once('path/to/twitteroauth.php');
	$TwitterOAuth = new TwitterOAuth('コンシューマキー', 'コンシューマシークレット', 'アクセストークン', 'アクセスシークレット');
	
	// 1.1向け。2013/06/12以降の版であれば不要
	$TwitterOAuth->host = 'https://api.twitter.com/1.1/';
	
	// 認証が有効か+ユーザ情報取得
	$user = $TwitterOAuth->get('account/verify_credentials');
	
	// つぶやく
	$status = $TwitterOAuth->post('statuses/update', ['status' =>'ツイート内容']);
	
	// リツイート
	$retweet = $TwitterOAuth->post('statuses/retweet/ツイートID');
	
	// フォロアーを取得
	$followers = $TwitterOAuth->get('followers/list');
	
	// フォローしてる人を取得
	$follows = $TwitterOAuth->get('friends/list');
	
	// ユーザ名でユーザ情報を取得
	$userinfo = $TwitterOAuth->get('users/show', ['screen_name'=> '@以降の表示名']);
	
	// ユーザIDでフォローする
	$follow = $TwitterOAuth->post('friendships/create', ['user_id'=> 'ユーザID']);
APIは他にもたくさんありますが、呼び出し方はどれも同じです。
oAuthRequest()はJSONデコードもされていないし、このメソッドを直接呼ぶ意義は、今のところ全くありません。

さらに、TwitterOAuthは2013/06/12にTwitter API 1.1に対応したので、それ以降のバージョンであれば$connection->hostを書き換える必要すらありません。

ちなみにTwitterOAuth、テストコードがついてくるのですが、これがけっこう間違いがあったりして困りものです。

というか、どうして呼び出し側でget/post判断やURLを渡させるのですかね。
適当にinterface作ってそっちで吸収してくれよと非常に思う。


2013/07/26 23:46 | Comments(0) | PHP
PHP5.3.7 「第8回オフラインリアルタイムどう書くの参考問題」をPHPで解く
http://qiita.com/Nabetani/items/24b9be4ee3bae4c89a95
http://nabetani.sakura.ne.jp/hena/ord8entco/

エントロピー符号とは、Wikipediaの解説は相変わらず意味がわかりませんが、まあ文字を適当に01に割り当てたものです。
有名どころではハフマン符号です。
モールス信号では"11"が"EE"か"I"か区別できませんが、ハフマン符号では正しい値であれば必ず一意に復元可能です。
<?php
	
	class ENTROPY{
	
		/**
		* 符号を解読して返す
		* @param  String 「16d9d4fbd」みたいな文字列
		* @return String 「ethanol:30」みたいな文字列
		*/
		public function get($input){
			
			// マッチ文字列
			$search = ['/^000/', '/^0010/', '/^0011/', '/^0100/', '/^01010/', '/^0101101/', '/^010111/', '/^0110/', '/^0111/', '/^10/', '/^1100/', '/^1101/', '/^111/'];
			$replace = ['t', 's', 'n', 'i', 'd', 'c', 'l', 'o', 'a', 'e', 'r', 'h', 'z'];
			
			// 入力値を2進数に
			$str = '';
			for($i=0; $i<strlen($input); $i++){
				$str.= strrev(str_pad(base_convert($input[$i], 16, 2), 4, '0', STR_PAD_LEFT));
			}
			
			// 内部使用
			$entropy = ''; // できあがる文字列
			$lastmatch = ''; // 最後にマッチした文字
			$strlen = strlen($str); // ビット数カウント用
			
			// マッチする限り繰り返し
			$str = preg_replace($search, $replace, $str, 1, $count);
			while($count>0){
				$lastmatch = $str[0];
				$str = substr($str, 1);
				
				// 引っかかったのがEOFだったら終了
				if($lastmatch === 'z'){
					break;
				}
				
				// 次のループ用
				$entropy .= $lastmatch;
				$str = preg_replace($search, $replace, $str, 1, $count);
			};
			
			// マッチしなかった / EOFがなかった
			if($entropy === '' || $lastmatch !== 'z'){
				return '*invalid*';
			}
			
			// 返却
			return $entropy . ':' . ($strlen - strlen($str));
		}
		
	}
	
	// テスト
	$test = [
		['16d9d4fbd', 'ethanol:30'],
		/* 省略 */
	];

	$entropy = new ENTROPY();
	foreach($test as $key=>$data){
		$answer = $entropy->get($data[0]);
		if($answer !== $data[1]){
			print('えらー');
		}
	}
2進数にするところで、通常"0x1"は"0001"になりますが、今回は"1000"にしないといけないので妙なことになってます。
検索ループはwhile(strpos()===0)とかwhile(preg_match())みたいにしたかったのですが、いまいちうまくいかなかったのでpreg_replaceを使って微妙なことに。
あとarray_shift()の文字列版ってないのだろうか。

かかった時間は2時間くらい。
どうマッチするかのところで相当時間をくってしまいました。
もうelseif繋げたほうが手っ取り早かったんじゃないかな。


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


2013/07/22 22:48 | Comments(1) | PHP
PHP5.3.7 「第8回オフラインリアルタイムどう書くの問題」をPHPで解く
http://qiita.com/Nabetani/items/709d61dff282cff7a890
http://nabetani.sakura.ne.jp/hena/ord8biboma/

ボンバーマンで爆風が到達する場所を図示せよというお題。

解ける人はたぶんビット演算とかでずばしゃー!と解くのでしょうけど、私はそのあたりがよくわからないんですよね。
なので懇切丁寧に、2次元表になおすという人間に優しい解き方をしてみようと思います。
<?php

	class BOMBERMAN{
	
		/**
		* 爆風の範囲を返す
		* @param  String 「802b1200/01400c20」みたいな文字列
		* @return String 「53c40cfc」みたいな文字列
		*/
		public function get($input){
			
			// 入力値を2次元表に分解
			$array = explode('/', $input);
			$wall = str_split(substr(str_pad(base_convert($array[0], 16, 2), 32, '0', STR_PAD_LEFT), 0, -2), 6);
			$bomb = str_split(substr(str_pad(base_convert($array[1], 16, 2), 32, '0', STR_PAD_LEFT), 0, -2), 6);
			
			// 爆風の位置
			$blast = $bomb;
			
			// 爆弾の行でくるくる
			foreach($bomb as $key=>$val){
				// 爆弾の列でくるくる
				for($i=0; $i<strlen($val); $i++){
					// 爆弾があれば爆発
					if($val[$i] === '1'){
						$this->explosion($blast, $wall, $key, $i);
					}
				}
			}
			
			// 16進数に戻す
			return str_pad(base_convert(implode('', $blast) . '00', 2, 16), 8, '0', STR_PAD_LEFT);
		}
		
		/**
		* ば く は つ するーーー!
		* @param &array 爆風が通った場所が1になる
		* @param array 壁
		* @param int 列
		* @param int 行
		*/
		private function explosion(&$blast, $wall, $column, $row){
			// 行を1埋め
			$key1 = $key2 = $row;
			// 爆弾より右が壁にぶつかるまで1で埋める。以下同じ
			while(@$wall[$column][$key1] === '0'){
				$blast[$column][$key1++] = '1';
			}
			while(@$wall[$column][$key2] === '0'){
				$blast[$column][$key2--] = '1';
			}
			// 列を1埋め
			$key1 = $key2 = $column;
			while(@$wall[$key1][$row] === '0'){
				$blast[$key1++][$row] = '1';
			}
			while(@$wall[$key2][$row] === '0'){
				$blast[$key2--][$row] = '1';
			}
		}
		
	}
	
	// テスト
	$test = [
		['802b1200/01400c20', '53c40cfc'],
		/* 省略 */
	];

	$bomberman = new BOMBERMAN();
	foreach($test as $key=>$data){
		$answer = $bomberman->get($data[0]);
		if($answer !== $data[1]){
			print('えらー');
		}
	}
爆弾と壁と爆風の表も別々にする必要がなく、値を1,2,4とかにすれば1枚で済むのですが、面倒なのでわかりやすくするために別にしています。
実際計算中の値は以下のようになっており、
$wall = array(5) {
  [0]=>
  string(6) "100000"
  [1]=>
  string(6) "000010"
  [2]=>
  string(6) "101100"
  [3]=>
  string(6) "010010"
  [4]=>
  string(6) "000000"
}
$bomb = array(5) {
  [0]=>
  string(6) "000000"
  [1]=>
  string(6) "010100"
  [2]=>
  string(6) "000000"
  [3]=>
  string(6) "001100"
  [4]=>
  string(6) "001000"
}
$blast = array(5) {
  [0]=>
  string(6) "010100"
  [1]=>
  string(6) "111100"
  [2]=>
  string(6) "010000"
  [3]=>
  string(6) "001100"
  [4]=>
  string(6) "111111"
}
実に人間に優しい形で確認することができます。
かかった時間は3時間くらい。
ビット演算はわかんないとか言いつつ実際やってみようと延々挑戦したあげく挫折したとかいう歴史があったりなかったり。

なおgmp_scan1()とかの使いどころを探してみたがちょっと無理だった。


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


2013/07/19 23:59 | Comments(0) | PHP
PHP5.3.7 「第9回オフラインリアルタイムどう書くの参考問題」をPHPで解く
http://qiita.com/Nabetani/items/7c46e8409c456e8fabd1
http://nabetani.sakura.ne.jp/hena/ord9nummake/

与えられたカードから4桁の順列を作る問題です。
解く方法は、カードから順列を作成する方法と、全数探査のふたつにおおまかにわけられるでしょう。
Rubyだとpermutationなどという反則メソッドがありますが、何故かPHPにはありません。
全数探査で解いてみます。
<?php
	class NUMMAKE{
		
		/**
		* 4桁の数を作って指定番目の値を返す
		* @param String 「13:01167」みたいな文字列
		* @return String 1109 (01167で作れる数のうち13番目)、無しの場合は「-」
		*/
		public function get($input){
			$nowCount = 0;
			
			// 入力を分解
			list($count, $tmp) = explode(':', $input);
			$tmp = str_replace('9', '6', $tmp);
			$nums = array_fill(0, 9, 0);
			for($i=0; $i<strlen($tmp); $i++){
				$nums[$tmp[$i]]++;
			}
			
			foreach(range('1000', '9999') as $int){
				$numbers = $nums;
				$str = str_replace('9', '6', $int);
				
				// 適合しなければ次に進む
				for($i=0; $i<strlen($str); $i++){
					if($numbers[$str[$i]]-- <= 0){
						continue 2;
					}
				}
				
				if(++$nowCount >= $count){
					// 規定番目がみつかった
					return (string)$int;
				}
			}
			
			// 見つからなかった
			return '-';
		}
	}
	
	// テスト
	$test = [
		['13:01167', '1109'],
		/* 省略 */
	];

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

今回は全数が9000個しかなかったので手っ取り早くforeachで回してます。
これが今度は6桁7桁の順列を作る、とかになったらカードから順列を作成する方法を取らないといけなくなるでしょう。

かかった時間は2時間程度。
最初カードから順列で作ろうとしてめんどくさいことになり、全数探査で作り直したら30分で終わったとかいう。


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


2013/07/15 20:55 | Comments(0) | PHP
PHP5.3.7 「第12回オフラインリアルタイムどう書くの問題」をPHPで解く
http://qiita.com/Nabetani/items/f3cca410428f90333e28
http://nabetani.sakura.ne.jp/hena/ord12rotdice/

さいころを転がして出た目を記録します。
単純に考えれば配列に全ての面を入れておけばいいだけなので、その方針にしたがって実装します。
世の中にはすごいことを考える人もいますが、私ががんばってこういうコードを書いたとして、後から見直したら絶対意味がわからない自信がある。

<?php
	class DICE{
	
		/**
		* さいころをコロコロして歩いた目を返す
		* @param String 「NNESWWS」みたいな文字列
		* @return String 「15635624」みたいな文字列
		*/
		public function get($input){
			// 初期値 順に上下東西南北
			$dice = [1, 6, 4, 3, 5, 2];
			$ret = (string)$dice[0];
			
			// 進む方向
			$next = [
				 'N' => [5,4,2,3,0,1]
				,'S' => [4,5,2,3,1,0]
				,'W' => [3,2,0,1,5,6]
				,'E' => [2,3,1,0,5,6]
			];
			
			// 順番に進むだけ
			for($i=0; $i<strlen($input); $i++){
				$dice = array_combine($next[$input[$i]], $dice);
				ksort($dice);
				$ret .= $dice[0];
			}
			
			// 終了
			return $ret;
		}
	}
	
	// テスト
	$test = [
		['NNESWWS', '15635624'],
		/* 省略 */
	];

	$dice = new DICE();
	foreach($test as $key=>$data){
		$answer = $dice->get($data[0]);
		if($answer !== $data[1]){
			print('えらー');
		}
	}
20分くらいですぐに終わりました。
まあ、実は昔同じことをやったことがあるので、そのときの知識を流用しただけです。
やったことがなければもう少しかかってたかと思われます。

$nextは、さいころが転がったときに、どの面がどの方向に移動するかを表す表です。
北(N)に転がったとしたら、そのときに上を向いていた面(方向0)は北(方向5)に向き直る、という形です。

ksortが微妙だな。
こいつは参照渡しなので$dice = ksort(array_combine($next[$input[$i]], $dice))とか書けないんですよね。


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


2013/07/12 23:51 | Comments(0) | PHP
PHP5.3.7 「第9回オフラインリアルタイムどう書くの問題」をPHPで解く
http://qiita.com/Nabetani/items/84255ac417ef25069a3b
http://nabetani.sakura.ne.jp/hena/ord9busfare/

順番からいうと「第10回オフラインリアルタイムどう書くの参考問題」ですが、どうも泥臭い方法しか考えつかないのでとりあえず保留します。
今回は年齢区分によるバス代の算出です。
大人一人で幼児二人無料といった割引を考慮して算出する必要があります。
<?php
	class BUS{
		/**
		* バス代を算出
		* @param String 「210:Cn,In,Iw,Ap,Iw」みたいな文字列
		* @param int バス代
		*/
		public function get($input){
			// 入力値を分解
			list($adlultPrice, $persons) = explode(':', $input);
			
			// 料金を算出
			$prices = ['Ap'=>0, 'Cp'=>0, 'Ip'=>0];
			$prices['An'] = (int)$adlultPrice;
			$prices['Cn'] = $prices['In'] = $prices['Aw'] = (int)ceil($adlultPrice/20)*10;
			$prices['Cw'] = $prices['Iw'] = (int)ceil($prices['Cn']/20)*10;
			
			// 客をACI,nwの順にソート
			$persons = explode(',', $persons);
			usort($persons, function($a, $b){
				if(($tmp = strcmp($a[0], $b[0])) === 0){
					return strcmp($a[1], $b[1]);
				}
				return $tmp;
			});
			
			// 順番に処理
			$sumPrice = 0;
			$adultCount = 0;
			foreach($persons as $person){
				// 大人割引
				if($person[0] === 'A'){
					$adultCount+=2;
				}elseif($person[0] === 'I' && $person[1] !== 'p' && $adultCount>0){
					$adultCount--;
					continue;
				}
				// 合計金額
				$sumPrice += $prices[$person];
			}
			
			// 終了
			return $sumPrice;
		}
	}
	
	// テスト
	$test = [
		['210:Cn,In,Iw,Ap,Iw', '170'],
		/* 省略 */
	];

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

なんつーか、特筆することが極めて無い中身になった。
なおソートするところで'p'を無視していますが、こいつは0円なので何処に出てこようが気にする必要はありません。
一見幼児割引のところでチェックする必要がある気がしますが、実は単に弾くだけで問題無いです。

かかった時間は一時間くらい。
最初$personsをさらに年齢区分と料金区分の配列にして処理してたけど、意味がないなと削ったので多少無駄な時間があります。


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


2013/07/08 22:14 | Comments(0) | PHP
PHP5.3.7 「第10回オフラインリアルタイムどう書くの問題」をPHPで解く
http://qiita.com/Nabetani/items/55641767510c2f9f235f
http://nabetani.sakura.ne.jp/hena/ord10haniwa/

第10回はハニカム歩きです。
ていうかこれ、第12回の道なりの亀と同じだよな。
ただし進行方向が6方向と、二次元配列で解くには少々面倒になっています。
ということで手っ取り早く進行先を全部持たせることにします。

 'BCDEFG','B' => 'HICAGS','C' => 'IJKDAB','D' => 'CKLMEA','E' => 'ADMNOF','F' => 'GAEOPQ',
			'G' => 'SBAFQR','H' => 'TUIBSk','I' => 'UVJCBH','J' => 'VWXKCI','K' => 'JXYLDC','L' => 'KYZaMD',
			'M' => 'DLabNE','N' => 'EMbcdO','O' => 'FENdeP','P' => 'QFOefg','Q' => 'RGFPgh','R' => 'jSGQhi',
			'S' => 'kHBGRj','T' => '!!UHk!','U' => '!!VIHT','V' => '!!WJIU','W' => '!!!XJV','X' => 'W!!YKJ',
			'Y' => 'X!!ZLK','Z' => 'Y!!!aL','a' => 'LZ!!bM','b' => 'Ma!!cN','c' => 'Nb!!!d','d' => 'ONc!!e',
			'e' => 'POd!!f','f' => 'gPe!!!','g' => 'hQPf!!','h' => 'iRQg!!','i' => '!jRh!!','j' => '!kSRi!','k' => '!THSj!'
		];
		
		/**
		* はにかむ構造を解いて返す
		* @param String 「135004」みたいな文字列
		* @param String 「ACDABHS」みたいな文字列
		*/
		public function get($route){
			$ret = $now = 'A';
			foreach(str_split($route) as $val){
				$next = $this->next[$now][$val];
				$ret.= $next;
				// !の場合は先に進まない
				if($next !== '!'){
					$now = $next;
				}
			}
			return $ret;
		}
	}
	
	// テスト
	$test = [
		[ '135004', 'ACDABHS' ],
		/* 省略 */
	];

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

今回はえらい簡単でした。
20分くらいで終わった。
もしかしたら第12回もこの方法でやった方が簡単だったかもしれぬ。

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


2013/07/05 22:15 | Comments(0) | PHP

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