fork download
  1. <?php
  2. class Snake
  3. {
  4.  
  5. /**
  6.   * holds info about snake's direction
  7.   * F - forward, D - down, U - up, B - back
  8.   * @var string
  9.   */
  10. protected $_direction = 'F';
  11.  
  12. /**
  13.   * Holds information about how long a snake is at the beginning
  14.   * @var int
  15.   */
  16. protected $_init_length = 1;
  17.  
  18. /**
  19.   * keeps position for actual snake
  20.   * @var array
  21.   */
  22. protected $_positions = array();
  23.  
  24. /**
  25.   * counter how many steps a snake has done so far
  26.   * @var int
  27.   */
  28. protected $_steps = 0;
  29.  
  30. /**
  31.   * Class constructor
  32.   *
  33.   * @param array $params - additional params for the snake,
  34.   * e.g. init_length set how long a snake is at the beginning.
  35.   */
  36. public function __construct(array $params = array())
  37. {
  38. if(isset($params['init_length'])) {
  39. $this->_init_length = (int)$params['init_length'];
  40. }
  41.  
  42. // Init snake.
  43. $this->_init_snake();
  44. }
  45.  
  46. /**
  47.   * Reset snake
  48.   * brings snake to the default position.
  49.   */
  50. public function reset()
  51. {
  52. $this->_init_snake();
  53. $this->_steps = 0;
  54. }
  55.  
  56. /**
  57.   * Moves snake forward
  58.   *
  59.   * @param bool $eat - did snake eat?
  60.   * @return bool
  61.   */
  62. public function move_forward($eat = false)
  63. {
  64. $snake_head = $this->_get_snake_head();
  65.  
  66. if($this->_going_forward()) {
  67. $next_step = array(
  68. ++$snake_head[0], $snake_head[1]
  69. );
  70. } else if($this->_going_down()) {
  71. $next_step = array(
  72. $snake_head[0], --$snake_head[1]
  73. );
  74. } else if($this->_going_up()) {
  75. $next_step = array(
  76. $snake_head[0], ++$snake_head[1]
  77. );
  78. } else if($this->_going_back()) {
  79. $next_step = array(
  80. --$snake_head[0], $snake_head[1]
  81. );
  82. }
  83.  
  84. return $this->_move_snake_to($next_step, 'F', !$eat);
  85. }
  86.  
  87. /**
  88.   * Moves snake to the left.
  89.   *
  90.   * @return bool
  91.   */
  92. public function move_left()
  93. {
  94. $snake_head = $this->_get_snake_head();
  95.  
  96. if($this->_going_forward()) {
  97. $next_step = array(
  98. $snake_head[0], ++$snake_head[1]
  99. );
  100. } else if($this->_going_down()) {
  101. $next_step = array(
  102. ++$snake_head[0], $snake_head[1]
  103. );
  104. } else if($this->_going_up()) {
  105. $next_step = array(
  106. --$snake_head[0], $snake_head[1]
  107. );
  108. } else if($this->_going_back()) {
  109. $next_step = array(
  110. $snake_head[0], --$snake_head[1]
  111. );
  112. }
  113.  
  114. return $this->_move_snake_to($next_step, 'L');
  115. }
  116.  
  117. /**
  118.   * Moves snake to the fight
  119.   *
  120.   * @return bool
  121.   */
  122. public function move_right()
  123. {
  124. $snake_head = $this->_get_snake_head();
  125.  
  126. if($this->_going_forward()) {
  127. $next_step = array(
  128. $snake_head[0], --$snake_head[1]
  129. );
  130. } else if($this->_going_down()) {
  131. $next_step = array(
  132. --$snake_head[0], $snake_head[1]
  133. );
  134. } else if($this->_going_up()) {
  135. $next_step = array(
  136. ++$snake_head[0], $snake_head[1]
  137. );
  138. } else if($this->_going_back()) {
  139. $next_step = array(
  140. $snake_head[0], ++$snake_head[1]
  141. );
  142. }
  143.  
  144. return $this->_move_snake_to($next_step, 'R');
  145. }
  146.  
  147. /**
  148.   * Moves snake according to specified path
  149.   *
  150.   * @param string $path - string of path
  151.   * F - forward, L - left, R - right, E - eat
  152.   * @return int -1: move successful, any other number: snake was not able
  153.   * to move this way, return number of steps he has made so far
  154.   * @throws \Ptx\SnakeException
  155.   */
  156. public function move_snake($path)
  157. {
  158. $survived = true;
  159. for($i = 0; $i < strlen($path); $i++) {
  160. switch($path[$i]) {
  161. case 'E':
  162. $survived *= $this->move_forward(true);
  163. break;
  164. case 'F':
  165. $survived *= $this->move_forward();
  166. break;
  167. case 'L':
  168. $survived *= $this->move_left();
  169. break;
  170. case 'R':
  171. $survived *= $this->move_right();
  172. break;
  173. default:
  174. throw new SnakeException('Unknown move ' . $path[$i], 101);
  175. }
  176.  
  177. if(!$survived) {
  178. break;
  179. }
  180. }
  181.  
  182. if($survived) {
  183. return -1;
  184. } else {
  185. return $this->get_steps();
  186. }
  187. }
  188.  
  189. /**
  190.   * @return array
  191.   */
  192. public function get_positions()
  193. {
  194. return $this->_positions;
  195. }
  196.  
  197. /**
  198.   * @return int
  199.   */
  200. public function get_steps()
  201. {
  202. return $this->_steps;
  203. }
  204.  
  205. /**
  206.   * Add positions for a snake
  207.   *
  208.   * @param array $position - position
  209.   * @param bool $remove_last - remove last
  210.   */
  211. protected function _add_position($position, $remove_last)
  212. {
  213. $this->_positions[] = $position;
  214.  
  215. if ($remove_last) { // Remove last - basically snake didn't eat in this step.
  216. array_shift($this->_positions);
  217. }
  218. }
  219.  
  220. /**
  221.   * @return array actual position of snake head
  222.   */
  223. protected function _get_snake_head()
  224. {
  225. return end($this->_positions);
  226. }
  227.  
  228. /**
  229.   * Initialize snake
  230.   *
  231.   * takes $this->_init_length and creates snake
  232.   * which is as long as requested.
  233.   */
  234. protected function _init_snake()
  235. {
  236. $this->_positions = array(
  237. array(0,0)
  238. );
  239.  
  240. for($i = 0; $i < $this->_init_length; $i++) {
  241. $this->_positions[] = array(
  242. $i + 1, 0
  243. );
  244. }
  245. }
  246.  
  247. /**
  248.   * Moves snake to another position
  249.   *
  250.   * @param array $position - new position
  251.   * @param string $direction - direction
  252.   * @param bool $remove_last - remove last position
  253.   * @return bool
  254.   */
  255. protected function _move_snake_to($position, $direction, $remove_last = true) {
  256. $this->_steps++; // Add another step
  257.  
  258. $success = false;
  259. if($this->_validate_step($position)) {
  260. $success = true; // Mark step as successful
  261.  
  262. $this->_update_direction($direction); // Update direction
  263. $this->_add_position($position, $remove_last); // Add position for snake
  264. }
  265.  
  266. return $success;
  267. }
  268.  
  269. /**
  270.   * Update direction base on snake's move
  271.   * @param $move - snake move
  272.   */
  273. protected function _update_direction($move)
  274. {
  275. if($move == 'L') {
  276. switch($this->_direction) {
  277. case 'F':
  278. $this->_direction = 'U';
  279. break;
  280. case 'U':
  281. $this->_direction = 'B';
  282. break;
  283. case 'D':
  284. $this->_direction = 'F';
  285. break;
  286. case 'B':
  287. $this->_direction = 'D';
  288. break;
  289. }
  290. } else if($move == 'R') {
  291. switch($this->_direction) {
  292. case 'F':
  293. $this->_direction = 'D';
  294. break;
  295. case 'U':
  296. $this->_direction = 'F';
  297. break;
  298. case 'D':
  299. $this->_direction = 'B';
  300. break;
  301. case 'B':
  302. $this->_direction = 'U';
  303. break;
  304. }
  305. }
  306. }
  307.  
  308. /**
  309.   * @param $step
  310.   * @return bool
  311.   */
  312. protected function _validate_step($step)
  313. {
  314. $key = array_search($step, $this->_positions);
  315. return is_numeric($key) ? false : true;
  316. }
  317.  
  318. /**
  319.   * @return bool
  320.   */
  321. protected function _going_forward()
  322. {
  323. return $this->_direction == 'F';
  324. }
  325.  
  326. /**
  327.   * @return bool
  328.   */
  329. protected function _going_down()
  330. {
  331. return $this->_direction == 'D';
  332. }
  333.  
  334. /**
  335.   * @return bool
  336.   */
  337. protected function _going_up()
  338. {
  339. return $this->_direction == 'U';
  340. }
  341.  
  342. /**
  343.   * @return bool
  344.   */
  345. protected function _going_back()
  346. {
  347. return $this->_direction == 'B';
  348. }
  349. }
  350.  
  351. $inputs = array();
  352. while($f = fgets(STDIN)) {
  353. $inputs[] = $f;
  354. }
  355.  
  356. $number_of_tests = $inputs[0];
  357. $outputs = null;
  358. for($i = 1; $i <= $number_of_tests; $i++) {
  359. list($steps, $path) = explode(' ', $inputs[$i]);
  360.  
  361. $snake_obj = new Snake();
  362. $survive = $snake_obj->move_snake(trim($path));
  363.  
  364. if($survive == -1) {
  365. $outputs .= 'YES';
  366. } else {
  367. $outputs .= $survive;
  368. }
  369.  
  370. if($i < $number_of_tests) {
  371. $outputs .= "\n";
  372. }
  373. }
  374.  
  375. $stdout = fopen('php://stdout', 'w');
  376. fwrite($stdout, $outputs);
  377. fclose($stdout);
Success #stdin #stdout 0.02s 24400KB
stdin
2
6 FLERFF
8 EEEELLLL
stdout
YES
7