「第18回オフラインリアルタイムどう書くの問題」をPHPで解く

http://nabetani.sakura.ne.jp/hena/ord18notfork/
http://qiita.com/Nabetani/items/ad47666c2f2f44ada1e7

レジに並ぶ問題。

出遅れたので、せっかくだから無駄に頑張った実装をしてみる。

```php
<?php
	
	class NOTFORK{
		/**
		* スーパーのレジ
		* @param String 「42873x.3.」みたいな文字列
		* @return String 「0,4,2,0,0」みたいな文字列
		*/
		public function get($input){
			
			// 処理できる人数
			$a = array(2, 7, 3, 5, 2);
			
			// 処理実行
			$registerList = new RegisterList($a);
			for($i=0;$i<strlen($input);$i++){
				if($input[$i] === '.'){
					// .はレジ処理
					$registerList->pop();
				}elseif($input[$i] === 'x'){
					// xは困ったちゃん
					$registerList->pushLocked();
				}else{
					// その他は数値
					$registerList->push((int)$input[$i]);
				}
			}
			
			// 返却
			return implode(',', $registerList->countCustomers());
		}
	}
	
	class RegisterList{
		// レジのリスト
		private $registers = array();
		
		/**
		* コンストラクタ
		* @param array 処理できる人数の配列
		*/
		public function __construct($numbers){
			foreach($numbers as $key=>$val){
				$this->registers[] = new Register($val);
			}
		}
		
		/**
		* レジに並ぶ
		* @param int 人数
		*/
		public function push($count){
			$this->registers[$this->getLowestRegister()]->push($count);
		}
		
		/**
		* 終わらない人が並ぶ
		*/
		public function pushLocked(){
			$this->registers[$this->getLowestRegister()]->pushLocked();
		}
		
		/**
		* 全レジを処理する
		*/
		public function pop(){
			foreach($this->registers as $key=>$val){
				$val->pop();
			}
		}
		
		/**
		* 並んでいる人が一番少ないレジを取得
		* 同人数の場合は若いレジ
		* @return int 少ないレジのキー
		*/
		private function getLowestRegister(){
			$nowCount = $this->registers[0]->countCustomers();
			$lowest = 0;
			foreach($this->registers as $key=>$val){
				if($nowCount > $val->countCustomers()){
					$nowCount = $val->countCustomers();
					$lowest = $key;
				}
			}
			return $lowest;
		}
		
		/**
		* 全レジの人数を取得
		* @return array 人数の配列
		*/
		public function countCustomers(){
			$ret = [];
			foreach($this->registers as $key=>$val){
				$ret[] = $val->countCustomers();
			}
			return $ret;
		}
	}
	
	class Register{
		// 終わらない人が一番手前に並んでる
		private $isLocked = false;
		// 一回のレジで処理できる人数
		private $number = 1;
		// 並んでる人のリスト
		private $customers = [];
		
		/**
		* コンストラクタ
		* @param int 一回で処理できる人数
		*/
		public function __construct($number){
			$this->number = $number;
		}
		
		/**
		* ロック状態か
		* @return ロックされていればtrue
		*/
		private function isLocked(){
			return $this->isLocked;
		}
		
		/**
		* 並んでいる人数を取得
		* @return 並んでいる人数
		*/
		public function countCustomers(){
			return count($this->customers);
		}
		
		/**
		* 並ぶ
		* @param int 並ぶ人数
		*/
		public function push($count = 1){
			for($i=0;$i<$count;$i++){
				$this->customers[] = new Customer();
			}
		}
		
		/**
		* 終わらない人が並ぶ
		*/
		public function pushLocked(){
			$this->customers[] = new LockedCustomer();
		}
		
		/**
		* レジを処理する
		*/
		public function pop(){
			if($this->isLocked()){ return false; }
			for($i=0;$i<$this->number;$i++){
				if($this->countCustomers() > 0){
					if($this->customers[0]->isLocked()){
						$this->isLocked = true;
						return;
					}else{
						array_shift($this->customers);
					}
				}
			}
		}
		
	}
	class Customer{
		const isLocked = false;
		public function isLocked(){
			return static::isLocked;
		}
	}
	class LockedCustomer extends Customer{
		const isLocked = true;
	}
	
	// 以下はテスト
	$test = [
		['42873x.3.', '0,4,2,0,0'],
		['1', '1,0,0,0,0'],
		['.', '0,0,0,0,0'],
		['x', '1,0,0,0,0'],
		['31.', '1,0,0,0,0'],
		['3x.', '1,1,0,0,0'],
		['99569x', '9,9,6,6,9'],
		['99569x33', '9,9,9,9,9'],
		['99569x33.', '7,2,6,4,7'],
		['99569x33..', '5,0,4,0,5'],
		['12345x3333.', '4,0,3,2,3'],
		['54321x3333.', '3,0,3,0,4'],
		['51423x3333.', '3,4,4,0,4'],
		['12x34x.', '1,0,1,0,2'],
		['987x654x.32', '7,6,4,10,5'],
		['99999999999x99999999.......9.', '20,10,12,5,20'],
		['997', '9,9,7,0,0'],
		['.3.9', '1,9,0,0,0'],
		['832.6', '6,6,0,0,0'],
		['.5.568', '3,5,6,8,0'],
		['475..48', '4,8,0,0,0'],
		['7.2..469', '1,4,6,9,0'],
		['574x315.3', '3,3,1,7,1'],
		['5.2893.x98', '10,9,5,4,1'],
		['279.6xxx..4', '2,1,4,1,1'],
		['1.1.39..93.x', '7,1,0,0,0'],
		['7677749325927', '16,12,17,18,12'],
		['x6235.87.56.9.', '7,2,0,0,0'],
		['4.1168.6.197.6.', '0,0,3,0,0'],
		['2.8.547.25..19.6', '6,2,0,0,0'],
		['.5.3x82x32.1829..', '5,0,5,0,7'],
		['x.1816..36.24.429.', '1,0,0,0,7'],
		['79.2.6.81x..26x31.1', '1,0,2,1,1'],
		['574296x6538984..5974', '14,13,10,15,14'],
		['99.6244.4376636..72.6', '5,6,0,0,3'],
		['1659.486x5637168278123', '17,16,16,18,17'],
		['.5.17797.x626x5x9457.3.', '14,0,3,5,8'],
		['..58624.85623..4.7..23.x', '1,1,0,0,0'],
		['716.463.9.x.8..4.15.738x4', '7,3,5,8,1'],
		['22xx.191.96469472.7232377.', '10,11,18,12,9'],
		['24..4...343......4.41.6...2', '2,0,0,0,0'],
		['32732.474x153.866..4x29.2573', '7,5,7,8,5'],
		['786.1267x9937.17.15448.1x33.4', '4,4,8,4,10'],
		['671714849.149.686852.178.895x3', '13,16,13,10,12'],
		['86x.47.517..29621.61x937..xx935', '7,11,8,8,10'],
		['.2233.78x.94.x59511.5.86x3.x714.', '4,6,10,8,8'],
		['.793...218.687x415x13.1...x58576x', '8,11,8,6,9'],
		['6.6x37.3x51x932.72x4x33.9363.x7761', '15,13,15,12,15'],
		['6..4.x187..681.2x.2.713276.669x.252', '6,7,8,6,5'],
		['.6.xx64..5146x897231.x.21265392x9775', '19,17,19,20,17'],
		['334.85413.263314.x.6293921x3.6357647x', '14,14,12,16,10'],
		['4.1..9..513.266..5999769852.2.38x79.x7', '12,10,13,6,10'],
	];

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

使い回す予定があるならともかく、書き捨てるプログラムでこんなことやっても意味はないのですが。
これでも1時間半で終わったので、普通に書けばもっと簡単だと思われます。