忍者ブログ
[PR]
×

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



2025/07/26 00:01 |
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
買ったものリスト 2013/08/04
Minecraft1.6.2のMOD、「俺の世界は幅3ブロック」を公開しました。
あなたの世界が幅3ブロックに制限されます。
元ネタは同名のMinecraftゆっくり実況シリーズです。


がっこうぐらし!1 海法 紀光
がっこうぐらし!2
☆☆☆☆☆

学校で楽しく合宿クラブ、開幕。
第一話試し読み冊子があって、てっきりほのぼの学園ものかと思ってたら最後のページがえらいことになっていたので光の速さで購入。
と思ったら2巻では普通に表紙でバレバレになってました。
進展がかなり遅いのが難点です。
2巻とか買い物に出かけて帰ってきただけだしな。
終わり方というか話の収拾を考えているのかが気になるところですが、まあN+だしそう酷いことにはならないでしょう。

ところで1巻のP12とP90でレイアウトが違うのは意味があるのだろうか。


黄昏乙女×アムネジア9 めいびい
☆☆☆☆

ついに明かされる夕子さんの真実。
忘れてしまっていた、否、自ら捨て去っていた過去を取り戻した夕子さんの選択、それはもちろん…

しかしその風習、とても数十年前の出来事だとは思えないんだがどうなんだ。



朱月のアゲハ2 桐原 小鳥
☆☆☆☆
おぃぃ伏線全部投げっぱで終わりとかどうすんだよこれ。
と思ったらタイトルを変えて続いているようです。
色々と気になるところが多すぎて困ります。
きちんと全て回収しきれるんだろうなこれ。
回収し切れたら☆+1、しきれなかったら-4ということで。

ミリタリーナレッジレポーツ3 スナイパー理論と実戦Part1 友清 仁
☆☆☆

誰だよこんな本書こうとか考えた奴。
なかなか面白かったのだが、しかし校正をしっかりしていないせいで誤字脱字が非常に目立ってしまうところが非常に残念です。
この手の本で間違いって致命的じゃないのか?
なおググると「スナイパー理論と実践」ばかりが引っかかりますが、「実戦」が正解です。


2013/08/04 20:10 | Comments(0) | 買ったもの
今週の実績 2013/08/04
2013/08/03の実績

地球防衛軍4

マスターフェンサー 15
フェンサーの体力が1250に到達


2013/08/04 19:59 | Comments(0) | 実績
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
今週の実績 2013/07/28
2013/07/26の実績

地球防衛軍4

スパイダー・ハンター 15
蜘蛛系巨大生物を12000体倒す

2013/07/23の実績

地球防衛軍4

マスターレンジャー 15
レンジャーの体力が1000に到達

2013/07/21の実績

地球防衛軍4

武器入手50% 20
武器の入手率が50%


2013/07/28 20:13 | Comments(0) | 実績
買ったものリスト 2013/07/28
地球防衛が終わりません。


ソード・ワールド2.0リプレイ 七剣刃クロニクル2 秋田 みやび
ソード・ワールド2.0リプレイ 七剣刃クロニクル3
☆☆☆

現行シリーズではUSAの次に安定してるかな。
あーでも純血云々は抑えめにしてください。
リプレイ第三部のあとがきをいつも思い出してしまう。


ソード・ワールド2.0リプレイ カルディアカーニバル 田中 公侍
☆☆☆

新種族オンリー、経験点12000点スタートと、新要素紹介の意味が強いリプレイ。
なかなか面白かったのですが、なんといっても薄い。
他のリプレイの下手すれば半分しかありません。
これで価格が同じなのはわりかし残念なので、せめてもう一話入れてほしかったですね。


ソード・ワールド2.0リプレイ ルーン・うぉーかーズ1 藤澤 さなえ
☆☆☆

全員ルーンフォーク、さらに1年分の記憶がない、と特殊すぎる状況から始まるリプレイ。
この手のあまりに決め過ぎちゃっているリプレイは基本的にあまり好きではないのですが、藤澤さなえだけあってそれなりに読める内容にはなっています。


ソード・ワールド2.0リプレイ with BRAVE(2) 戦乙女のオデッセイ 北沢 慶
☆☆

なんかもうね……このシリーズはリプレイ史上一番微妙だな。


2013/07/28 20:11 | Comments(0) | 買ったもの
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
買ったものリスト 2013/07/21

彼氏ってどこに行ったら買えますの!?1 火曜
☆☆☆

深い話は何もないし、毎回展開が全く同じですが、疲れたときに読むと脳の疲労がマッハで明後日に吹き飛びます。
ただ、今後もずっと同じ展開が続くなら作者の語彙があまりにも少ないのが問題になってきそう。
2巻でどうなるかだな。


アリスと蔵六1 今井 哲也
☆☆☆

魔法少女ものを見るたびに、誰しもが考えていただろうことがあります。
流れ弾とかどうなってんだよ。あと警察。

本書の主人公は魔法少女を拳骨で鉄拳制裁する頑固爺。
同年代男子ではなく大人を出したことで、魔法少女もののお約束が通用しないリアルな事情が関わってきます。
ファンタジーと現実の狭間を行ったり来たりしつつ、何処に向かうのか楽しみな作品。


アクセル・ワールド12 ―赤の紋章― 川原 礫
アクセル・ワールド13 ―水際の号火―
アクセル・ワールド14 ―激光の大天使―
☆☆☆☆

よくよく考えると展開に相当無理があったりするのだが、読んでる間は面白いので全く気にならない。
気合いでプログラム上書きってなんだよ。
でも恋愛フラグはちょっともういらないです。
んで、この世界に科学者を一年突っ込んでおけば1000年分の研究ができるぜ。
ていうか早く実現化してください。いやほんと。


2013/07/21 21:40 | Comments(0) | 買ったもの

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