fork(2) download
  1. import java.awt.BorderLayout;
  2. import java.awt.Color;
  3. import java.awt.Dimension;
  4. import java.awt.Graphics;
  5. import java.awt.Graphics2D;
  6. import java.awt.RenderingHints;
  7. import java.awt.Toolkit;
  8. import java.awt.datatransfer.StringSelection;
  9. import java.awt.event.KeyAdapter;
  10. import java.awt.event.KeyEvent;
  11. import java.util.ArrayList;
  12. import java.util.Formatter;
  13. import java.util.List;
  14. import java.util.concurrent.atomic.AtomicBoolean;
  15. import java.util.concurrent.atomic.AtomicInteger;
  16.  
  17. import javax.swing.JFrame;
  18. import javax.swing.JLabel;
  19. import javax.swing.JPanel;
  20. import javax.swing.WindowConstants;
  21.  
  22. /**
  23.  * メインクラス
  24.  */
  25. public class Main {
  26.  
  27. /**
  28. * 1体の敵
  29. */
  30. static class Enemy {
  31.  
  32. /**
  33. * 敵の種別
  34. */
  35. enum Kind {
  36. /**
  37. * 敵V
  38. */
  39. V,
  40. /**
  41. * 敵H
  42. */
  43. H,
  44. /**
  45. * 敵L
  46. */
  47. L,
  48. /**
  49. * 敵R
  50. */
  51. R,
  52. /**
  53. * 敵Jが敵Lになっている状態
  54. */
  55. JL,
  56. /**
  57. * 敵Jが敵Rになっている状態
  58. */
  59. JR,
  60. }
  61.  
  62. /**
  63. * X座標
  64. */
  65. int x;
  66. /**
  67. * Y座標
  68. */
  69. int y;
  70. /**
  71. * 直前のX座標
  72. */
  73. int lastX;
  74. /**
  75. * 直前のY座標
  76. */
  77. int lastY;
  78. /**
  79. * 種類
  80. */
  81. Kind kind;
  82.  
  83. /**
  84. * 敵を初期化
  85. * @param x X座標
  86. * @param y Y座標
  87. * @param kind 種類
  88. */
  89. Enemy(final int x, final int y, final Kind kind) {
  90. this.x = x;
  91. this.y = y;
  92. this.lastX = x;
  93. this.lastY = y;
  94. this.kind = kind;
  95. }
  96.  
  97. /**
  98. * 移動
  99. * @param data データ
  100. * @param player プレイヤ
  101. * @param time 時刻
  102. */
  103. void move(final char[][] data, final Player player, final AtomicInteger time) {
  104. final char down = data[this.y + 1][this.x];
  105. final char left = data[this.y][this.x - 1];
  106. final char up = data[this.y - 1][this.x];
  107. final char right = data[this.y][this.x + 1];
  108. if (time.get() == 0) {
  109. /*
  110. * 時刻 t = 0 においては、初期位置の 下、左、上、右 の順で最初に進入可能なマスの方向に移動します。
  111. */
  112. if (down != '#') {
  113. this.y++;
  114. } else if (left != '#') {
  115. this.x--;
  116. } else if (up != '#') {
  117. this.y--;
  118. } else if (right != '#') {
  119. this.x++;
  120. } else {
  121. System.err.printf("動けません。t = %d, x = %d, y = %d, kind = %s\n", time.get(),
  122. this.x, this.y, this.kind);
  123. }
  124. } else {
  125. final int numOfWalls = (down == '#' ? 1 : 0) + (left == '#' ? 1 : 0)
  126. + (up == '#' ? 1 : 0) + (right == '#' ? 1 : 0);
  127. if (numOfWalls == 3) {
  128. /*
  129. * 行き止まりマスの場合、唯一進入可能な隣接マスに移動します。
  130. */
  131. if (down != '#') {
  132. this.y++;
  133. } else if (left != '#') {
  134. this.x--;
  135. } else if (up != '#') {
  136. this.y--;
  137. } else if (right != '#') {
  138. this.x++;
  139. } else {
  140. System.err.printf("動けません。t = %d, x = %d, y = %d, kind = %s\n", time.get(),
  141. this.x, this.y, this.kind);
  142. }
  143. } else if (numOfWalls == 2) {
  144. /*
  145. * 通路マスの場合、時刻 t-1 に居たマス以外の進入可能な隣接するマスに移動します。
  146. */
  147. if (down != '#' && this.lastY != this.y + 1) {
  148. this.y++;
  149. } else if (left != '#' && this.lastX != this.x - 1) {
  150. this.x--;
  151. } else if (up != '#' && this.lastY != this.y - 1) {
  152. this.y--;
  153. } else if (right != '#' && this.lastX != this.x + 1) {
  154. this.x++;
  155. } else {
  156. System.err.printf("動けません。t = %d, x = %d, y = %d, kind = %s\n", time.get(),
  157. this.x, this.y, this.kind);
  158. }
  159. } else if (numOfWalls == 1 || numOfWalls == 0) {
  160. /*
  161. * 交差点マスの場合は、敵の種別に応じたアルゴリズムに応じて移動方向を決定します。
  162. */
  163. final int dX = player.lastX - this.x;
  164. final int dY = player.lastY - this.y;
  165. final int signDX = (int) Math.signum(dX);
  166. final int signDY = (int) Math.signum(dY);
  167. switch (this.kind) {
  168. case V:
  169. /*
  170. * 敵から見た自機の相対位置を (dx, dy) と表すものとします。次のルールを上から順に適用し、最初に選ばれた方向に移動します。
  171. * 1. dy ≠ 0 でかつ dy の符号方向にあるマスが進入可能であれば、その方向に移動します。
  172. * 2. dx ≠ 0 でかつ dx の符号方向にあるマスが進入可能であれば、その方向に移動します。
  173. * 3. 現在位置の 下、左、上、右 の順で最初に進入可能なマスの方向に移動する。
  174. */
  175. if (dY != 0 && data[this.y + signDY][this.x] != '#') {
  176. this.y += signDY;
  177. } else if (dX != 0 && data[this.y][this.x + signDX] != '#') {
  178. this.x += signDX;
  179. } else {
  180. if (down != '#') {
  181. this.y++;
  182. } else if (left != '#') {
  183. this.x--;
  184. } else if (right != '#') {
  185. this.x++;
  186. } else if (up != '#') {
  187. this.y--;
  188. } else {
  189. System.err.printf("動けません。t = %d, x = %d, y = %d, kind = %s\n",
  190. time.get(), this.x, this.y, this.kind);
  191. }
  192. }
  193. break;
  194. case H:
  195. /*
  196. * 敵 V とほぼ同じです。唯一異なるのは 、進行方向を決めるルールのうち、
  197. * 最初の二つのルールの適用順序が入れ替わるところです。
  198. * すなわち、先に dx ≠ 0 のチェックを行ない、次に dy ≠ 0 のチェックを行います。
  199. */
  200. if (dX != 0 && data[this.y][this.x + signDX] != '#') {
  201. this.x += signDX;
  202. } else if (dY != 0 && data[this.y + signDY][this.x] != '#') {
  203. this.y += signDY;
  204. } else {
  205. if (down != '#') {
  206. this.y++;
  207. } else if (left != '#') {
  208. this.x--;
  209. } else if (right != '#') {
  210. this.x++;
  211. } else if (up != '#') {
  212. this.y--;
  213. } else {
  214. System.err.printf("動けません。t = %d, x = %d, y = %d, kind = %s\n",
  215. time.get(), this.x, this.y, this.kind);
  216. }
  217. }
  218. break;
  219. case L:
  220. case JL:
  221. /*
  222. * 現在位置への進入方向から見て相対的に 左、前、右 の順で最初に進入可能なマスの方向に移動します。
  223. */
  224. if (this.lastY + 1 == this.y) {
  225. if (right != '#') {
  226. this.x++;
  227. } else if (down != '#') {
  228. this.y++;
  229. } else if (left != '#') {
  230. this.x--;
  231. } else {
  232. System.err.printf("動けません。t = %d, x = %d, y = %d, kind = %s\n",
  233. time.get(), this.x, this.y, this.kind);
  234. }
  235. } else if (this.lastX - 1 == this.x) {
  236. if (down != '#') {
  237. this.y++;
  238. } else if (left != '#') {
  239. this.x--;
  240. } else if (up != '#') {
  241. this.y--;
  242. } else {
  243. System.err.printf("動けません。t = %d, x = %d, y = %d, kind = %s\n",
  244. time.get(), this.x, this.y, this.kind);
  245. }
  246. } else if (this.lastY - 1 == this.y) {
  247. if (left != '#') {
  248. this.x--;
  249. } else if (up != '#') {
  250. this.y--;
  251. } else if (right != '#') {
  252. this.x++;
  253. } else {
  254. System.err.printf("動けません。t = %d, x = %d, y = %d, kind = %s\n",
  255. time.get(), this.x, this.y, this.kind);
  256. }
  257. } else if (this.lastX + 1 == this.x) {
  258. if (up != '#') {
  259. this.y--;
  260. } else if (right != '#') {
  261. this.x++;
  262. } else if (down != '#') {
  263. this.y++;
  264. } else {
  265. System.err.printf("動けません。t = %d, x = %d, y = %d, kind = %s\n",
  266. time.get(), this.x, this.y, this.kind);
  267. }
  268. } else {
  269. System.err.printf("止まっていた?t = %d, x = %d, y = %d, kind = %s\n",
  270. time.get(), this.x, this.y, this.kind);
  271. }
  272. break;
  273. case R:
  274. case JR:
  275. /*
  276. * 現在位置への進入方向から見て相対的に 右、前、左 の順で最初に進入可能なマスの方向に移動します。
  277. */
  278. if (this.lastY + 1 == this.y) {
  279. if (left != '#') {
  280. this.x--;
  281. } else if (down != '#') {
  282. this.y++;
  283. } else if (right != '#') {
  284. this.x++;
  285. } else {
  286. System.err.printf("動けません。t = %d, x = %d, y = %d, kind = %s\n",
  287. time.get(), this.x, this.y, this.kind);
  288. }
  289. } else if (this.lastX - 1 == this.x) {
  290. if (up != '#') {
  291. this.y--;
  292. } else if (left != '#') {
  293. this.x--;
  294. } else if (down != '#') {
  295. this.y++;
  296. } else {
  297. System.err.printf("動けません。t = %d, x = %d, y = %d, kind = %s\n",
  298. time.get(), this.x, this.y, this.kind);
  299. }
  300. } else if (this.lastY - 1 == this.y) {
  301. if (right != '#') {
  302. this.x++;
  303. } else if (up != '#') {
  304. this.y--;
  305. } else if (left != '#') {
  306. this.x--;
  307. } else {
  308. System.err.printf("動けません。t = %d, x = %d, y = %d, kind = %s\n",
  309. time.get(), this.x, this.y, this.kind);
  310. }
  311. } else if (this.lastX + 1 == this.x) {
  312. if (down != '#') {
  313. this.y++;
  314. } else if (right != '#') {
  315. this.x++;
  316. } else if (up != '#') {
  317. this.y--;
  318. } else {
  319. System.err.printf("動けません。t = %d, x = %d, y = %d, kind = %s\n",
  320. time.get(), this.x, this.y, this.kind);
  321. }
  322. } else {
  323. System.err.printf("止まっていた?t = %d, x = %d, y = %d, kind = %s\n",
  324. time.get(), this.x, this.y, this.kind);
  325. }
  326. break;
  327. }
  328. /*
  329. * 交差点マスに入るたびに、最初は敵Lの行動、次回は敵Rの行動、さらに次回はまた敵Lの行動、と繰り返します。
  330. */
  331. this.kind = this.kind == Kind.JL ? Kind.JR : (this.kind == Kind.JR ? Kind.JL
  332. : this.kind);
  333. } else {
  334. System.err.printf("動けません。t = %d, x = %d, y = %d, kind = %s\n", time.get(),
  335. this.x, this.y, this.kind);
  336. }
  337. }
  338. }
  339.  
  340. /**
  341. * @param player プレイヤ
  342. * @return 殺したかどうか
  343. */
  344. boolean killed(final Player player) {
  345. if (this.x == player.x && this.y == player.y) {
  346. return true;
  347. } else if (this.x == player.lastX && this.y == player.lastY && this.lastX == player.x
  348. && this.lastY == player.y) {
  349. return true;
  350. } else {
  351. return false;
  352. }
  353. }
  354.  
  355. @Override
  356. public String toString() {
  357. return new Formatter().format("[x = %d, y = %d, kind = %s]", this.x, this.y, this.kind)
  358. .toString();
  359. }
  360. }
  361.  
  362. /**
  363. * プレイヤ
  364. */
  365. static class Player {
  366. /**
  367. * X座標
  368. */
  369. int x = -1;
  370. /**
  371. * Y座標
  372. */
  373. int y = -1;
  374. /**
  375. * 直前のX座標
  376. */
  377. int lastX = -1;
  378. /**
  379. * 直前のY座標
  380. */
  381. int lastY = -1;
  382.  
  383. /**
  384. * 上へ移動
  385. * @param data データ
  386. * @param log ログ
  387. */
  388. void moveDown(final char[][] data, final StringBuilder log) {
  389. this.lastX = this.x;
  390. this.lastY = this.y;
  391. if (data[this.y + 1][this.x] != '#') {
  392. this.y++;
  393. }
  394. log.append('j');
  395. }
  396.  
  397. /**
  398. * 左へ移動
  399. * @param data データ
  400. * @param log ログ
  401. */
  402. void moveLeft(final char[][] data, final StringBuilder log) {
  403. this.lastX = this.x;
  404. this.lastY = this.y;
  405. if (data[this.y][this.x - 1] != '#') {
  406. this.x--;
  407. }
  408. log.append('h');
  409. }
  410.  
  411. /**
  412. * 上へ移動
  413. * @param data データ
  414. * @param log ログ
  415. */
  416. void moveUp(final char[][] data, final StringBuilder log) {
  417. this.lastX = this.x;
  418. this.lastY = this.y;
  419. if (data[this.y - 1][this.x] != '#') {
  420. this.y--;
  421. }
  422. log.append('k');
  423. }
  424.  
  425. /**
  426. * 右へ移動
  427. * @param data データ
  428. * @param log ログ
  429. */
  430. void moveRight(final char[][] data, final StringBuilder log) {
  431. this.lastX = this.x;
  432. this.lastY = this.y;
  433. if (data[this.y][this.x + 1] != '#') {
  434. this.x++;
  435. }
  436. log.append('l');
  437. }
  438.  
  439. /**
  440. * 留まる
  441. * @param log ログ
  442. */
  443. void stay(final StringBuilder log) {
  444. this.lastX = this.x;
  445. this.lastY = this.y;
  446. log.append('.');
  447. }
  448.  
  449. @Override
  450. public String toString() {
  451. return new Formatter().format("[x = %d, y = %d, lX = %d, lY = %d]", this.x, this.y,
  452. this.lastX, this.lastY).toString();
  453. }
  454. }
  455.  
  456. /**
  457. * ステージ
  458. */
  459. enum Stage {
  460. /**
  461. * 入力1
  462. */
  463. LV1(50, 11, 7, "###########" + "#.V..#..H.#" + "#.##...##.#" + "#L#..#..R.#"
  464. + "#.#.###.#.#" + "#....@....#" + "###########"),
  465. /**
  466. * 入力2
  467. */
  468. LV2(300, 20, 17, "####################" + "###.....L..........#" + "###.##.##.##L##.##.#"
  469. + "###.##.##.##.##.##.#" + "#.L................#" + "#.##.##.##.##.##.###"
  470. + "#.##.##L##.##.##.###" + "#.................L#" + "#.#.#.#J####J#.#.#.#"
  471. + "#L.................#" + "###.##.##.##.##.##.#" + "###.##.##R##.##.##.#"
  472. + "#................R.#" + "#.##.##.##.##R##.###" + "#.##.##.##.##.##.###"
  473. + "#@....R..........###" + "####################"),
  474. /**
  475. * 入力3
  476. */
  477. LV3(700, 58, 17, "##########################################################"
  478. + "#........................................................#"
  479. + "#.###.#########.###############.########.###.#####.#####.#"
  480. + "#.###.#########.###############.########.###.#####.#####.#"
  481. + "#.....#########....J.............J.......###.............#"
  482. + "#####.###.......#######.#######.########.###.#######.#####"
  483. + "#####.###.#####J#######.#######.########.###.## ##.#####"
  484. + "#####.###L#####.## ##L## ##.## ##.###.## ##.#####"
  485. + "#####.###..H###.## ##.## ##.########.###.#######J#####"
  486. + "#####.#########.## ##L## ##.########.###.###V....#####"
  487. + "#####.#########.#######.#######..........###.#######.#####"
  488. + "#####.#########.#######.#######.########.###.#######.#####"
  489. + "#.....................L.........########..........R......#"
  490. + "#L####.##########.##.##########....##....#########.#####.#"
  491. + "#.####.##########.##.##########.##.##.##.#########.#####.#"
  492. + "#.................##............##..@.##...............R.#"
  493. + "##########################################################");
  494. /**
  495. * 制限時間
  496. */
  497. int timeLimit;
  498. /**
  499. * 幅
  500. */
  501. int width;
  502. /**
  503. * 高さ
  504. */
  505. int height;
  506. /**
  507. * データ
  508. */
  509. char[][] data;
  510. /**
  511. * 点
  512. */
  513. int dots;
  514.  
  515. /**
  516. * ステージを初期化
  517. * @param timeLimit 制限時間
  518. * @param width 幅
  519. * @param height 高さ
  520. * @param string 入力文字列
  521. */
  522. Stage(final int timeLimit, final int width, final int height, final String string) {
  523. this.timeLimit = timeLimit;
  524. this.width = width;
  525. this.height = height;
  526. this.data = new char[height][width];
  527. this.dots = 0;
  528. for (int i = 0; i < height; i++) {
  529. for (int j = 0; j < width; j++) {
  530. final char character = string.charAt(i * width + j);
  531. this.data[i][j] = character;
  532. if (character == '.') {
  533. this.dots++;
  534. }
  535. }
  536. }
  537. };
  538. }
  539.  
  540. /**
  541. * メインメソッド
  542. * @param args コマンドライン引数
  543. * @throws InterruptedException 割り込み例外
  544. */
  545. public static void main(final String[] args) throws InterruptedException {
  546. final Stage stage = Stage.LV3;
  547. final int timeLimit = stage.timeLimit;
  548. final int width = stage.width;
  549. final int height = stage.height;
  550. final char[][] data = new char[height][width];
  551. final Player player = new Player();
  552. final List<Enemy> enemies = new ArrayList<Enemy>();
  553. final AtomicInteger time = new AtomicInteger();
  554. final AtomicInteger dots = new AtomicInteger();
  555. final StringBuilder log = new StringBuilder();
  556. final AtomicBoolean isDead = new AtomicBoolean();
  557. final JFrame frame = new JFrame(stage.toString());
  558. final int size = 20;
  559. final JLabel statusLabel = new JLabel("ここに現在の状態が表示されます。");
  560. statusLabel.setOpaque(true);
  561. statusLabel.setBackground(Color.WHITE);
  562. frame.add(statusLabel, BorderLayout.NORTH);
  563. final JPanel playPanel = new JPanel() {
  564. @Override
  565. protected void paintComponent(final Graphics graphics) {
  566. super.paintComponent(graphics);
  567. final Graphics2D g = (Graphics2D) graphics;
  568. g.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
  569. RenderingHints.VALUE_ANTIALIAS_ON);
  570. g.setColor(Color.RED);
  571. g.fillOval(player.x * size, player.y * size, size, size);
  572. for (final Enemy enemy : enemies) {
  573. switch (enemy.kind) {
  574. case V:
  575. g.setColor(Color.GREEN);
  576. break;
  577. case H:
  578. g.setColor(Color.BLUE);
  579. break;
  580. case L:
  581. g.setColor(Color.ORANGE);
  582. break;
  583. case R:
  584. g.setColor(Color.PINK);
  585. break;
  586. case JL:
  587. case JR:
  588. g.setColor(Color.CYAN);
  589. break;
  590. default:
  591. g.setColor(Color.BLACK);
  592. }
  593. g.fillOval(enemy.x * size, enemy.y * size, size, size);
  594. }
  595. g.setColor(Color.BLACK);
  596. for (final Enemy enemy : enemies) {
  597. g.drawString(enemy.kind.toString(), enemy.x * size + size / 2
  598. - g.getFontMetrics().stringWidth(enemy.kind.toString()) / 2, enemy.y
  599. * size + g.getFontMetrics().getAscent());
  600. }
  601. g.drawString("P", player.x * size + size / 2 - g.getFontMetrics().stringWidth("P")
  602. / 2, player.y * size + g.getFontMetrics().getAscent());
  603. for (int i = 0; i < height; i++) {
  604. for (int j = 0; j < width; j++) {
  605. switch (data[i][j]) {
  606. case '#':
  607. g.setColor(Color.GRAY);
  608. g.fillRect(j * size, i * size, size, size);
  609. break;
  610. case '.':
  611. g.setColor(Color.BLACK);
  612. g.fillOval(j * size + size / 2 - 2, i * size + size / 2 - 2, 4, 4);
  613. break;
  614. }
  615. }
  616. }
  617. }
  618. };
  619. playPanel.setFocusable(true);
  620. playPanel.addKeyListener(new KeyAdapter() {
  621. @Override
  622. public void keyPressed(final KeyEvent e) {
  623. switch (e.getKeyCode()) {
  624. case KeyEvent.VK_ESCAPE:
  625. initialize(width, height, data, stage, player, enemies, time, dots, log,
  626. isDead, statusLabel, timeLimit);
  627. playPanel.repaint();
  628. break;
  629. case KeyEvent.VK_Z:
  630. playBack(log.toString().replaceFirst(".$", ""), stage, timeLimit, width,
  631. height, data, player, enemies, time, dots, log, isDead, statusLabel,
  632. playPanel);
  633. playPanel.repaint();
  634. updateStatusLabel(statusLabel, stage, timeLimit, time, dots, log);
  635. break;
  636. case KeyEvent.VK_1:
  637. break;
  638. case KeyEvent.VK_2:
  639. break;
  640. case KeyEvent.VK_3:
  641. }
  642. if (!isDead.get()) {
  643. switch (e.getKeyCode()) {
  644. case KeyEvent.VK_DOWN:
  645. case KeyEvent.VK_J:
  646. player.moveDown(data, log);
  647. break;
  648. case KeyEvent.VK_LEFT:
  649. case KeyEvent.VK_H:
  650. player.moveLeft(data, log);
  651. break;
  652. case KeyEvent.VK_UP:
  653. case KeyEvent.VK_K:
  654. player.moveUp(data, log);
  655. break;
  656. case KeyEvent.VK_RIGHT:
  657. case KeyEvent.VK_L:
  658. player.moveRight(data, log);
  659. break;
  660. case KeyEvent.VK_SPACE:
  661. case KeyEvent.VK_ENTER:
  662. case KeyEvent.VK_PERIOD:
  663. player.stay(log);
  664. break;
  665. default:
  666. return;
  667. }
  668. moveEnemies(data, player, enemies, time, isDead);
  669. getDot(data, player, dots);
  670. time.incrementAndGet();
  671. if (time.get() >= timeLimit) {
  672. isDead.set(true);
  673. }
  674. if (dots.get() == stage.dots) {
  675. System.out.printf("(cleared)time: %d/%d, score: %d/%d, log: %s\n",
  676. time.get(), timeLimit, dots.get(), stage.dots, log);
  677. isDead.set(true);
  678. }
  679. playPanel.repaint();
  680. updateStatusLabel(statusLabel, stage, timeLimit, time, dots, log);
  681. if (isDead.get()) {
  682. statusLabel.setText((dots.get() == stage.dots ? "(cleared)" : "(dead)")
  683. + statusLabel.getText());
  684. Toolkit.getDefaultToolkit().getSystemClipboard()
  685. .setContents(new StringSelection(log.toString()), null);
  686. }
  687. }
  688. }
  689. });
  690. playPanel.setPreferredSize(new Dimension(width * size, height * size));
  691. playPanel.setBackground(Color.WHITE);
  692. frame.add(playPanel);
  693. frame.pack();
  694. frame.setLocationByPlatform(true);
  695. frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
  696. initialize(width, height, data, stage, player, enemies, time, dots, log, isDead,
  697. statusLabel, timeLimit);
  698. frame.setVisible(true);
  699. }
  700.  
  701. /**
  702. * 初期化
  703. * @param width 幅
  704. * @param height 高さ
  705. * @param data データ
  706. * @param stage ステージ
  707. * @param player プレイヤ
  708. * @param enemies 敵
  709. * @param time 時刻
  710. * @param dots 点
  711. * @param log ログ
  712. * @param isDead 死んでいるかどうか
  713. * @param statusLabel ラベル
  714. * @param timeLimit 制限時間
  715. */
  716. static void initialize(final int width, final int height, final char[][] data,
  717. final Stage stage, final Player player, final List<Enemy> enemies,
  718. final AtomicInteger time, final AtomicInteger dots, final StringBuilder log,
  719. final AtomicBoolean isDead, final JLabel statusLabel, final int timeLimit) {
  720. enemies.clear();
  721. for (int i = 0; i < height; i++) {
  722. for (int j = 0; j < width; j++) {
  723. final char kind = stage.data[i][j];
  724. switch (kind) {
  725. case 'V':
  726. data[i][j] = ' ';
  727. enemies.add(new Enemy(j, i, Enemy.Kind.V));
  728. break;
  729. case 'H':
  730. data[i][j] = ' ';
  731. enemies.add(new Enemy(j, i, Enemy.Kind.H));
  732. break;
  733. case 'L':
  734. data[i][j] = ' ';
  735. enemies.add(new Enemy(j, i, Enemy.Kind.L));
  736. break;
  737. case 'R':
  738. data[i][j] = ' ';
  739. enemies.add(new Enemy(j, i, Enemy.Kind.R));
  740. break;
  741. case 'J':
  742. data[i][j] = ' ';
  743. enemies.add(new Enemy(j, i, Enemy.Kind.JL));
  744. break;
  745. case '@':
  746. data[i][j] = ' ';
  747. player.x = j;
  748. player.y = i;
  749. player.lastX = player.x;
  750. player.lastY = player.y;
  751. break;
  752. case '#':
  753. case '.':
  754. case ' ':
  755. data[i][j] = stage.data[i][j];
  756. break;
  757. default:
  758. System.err.printf("unknown data: '%s', x = %d, y = %d\n", stage.data[i][j], j,
  759. i);
  760. }
  761. }
  762. }
  763. time.set(0);
  764. dots.set(0);
  765. log.setLength(0);
  766. isDead.set(false);
  767. updateStatusLabel(statusLabel, stage, timeLimit, time, dots, log);
  768. }
  769.  
  770. /**
  771. * リプレイ
  772. * @param string 動作を指示する文字列
  773. * @param stage ステージ
  774. * @param timeLimit 制限時間
  775. * @param width 幅
  776. * @param height 高さ
  777. * @param data データ
  778. * @param player プレイヤ
  779. * @param enemies 敵
  780. * @param time 時刻
  781. * @param dots 点
  782. * @param log ログ
  783. * @param isDead 死んでいるかどうか
  784. * @param statusLabel ラベル
  785. * @param playPanel パネル
  786. */
  787. static void playBack(final String string, final Stage stage, final int timeLimit,
  788. final int width, final int height, final char[][] data, final Player player,
  789. final List<Enemy> enemies, final AtomicInteger time, final AtomicInteger dots,
  790. final StringBuilder log, final AtomicBoolean isDead, final JLabel statusLabel,
  791. final JPanel playPanel) {
  792. initialize(width, height, data, stage, player, enemies, time, dots, log, isDead,
  793. statusLabel, timeLimit);
  794. for (int i = 0; i < string.length(); i++) {
  795. if (!isDead.get()) {
  796. switch (string.charAt(i)) {
  797. case 'j':
  798. player.moveDown(data, log);
  799. break;
  800. case 'h':
  801. player.moveLeft(data, log);
  802. break;
  803. case 'k':
  804. player.moveUp(data, log);
  805. break;
  806. case 'l':
  807. player.moveRight(data, log);
  808. break;
  809. case '.':
  810. player.stay(log);
  811. break;
  812. default:
  813. System.err.printf("unknown data: %s\n", string.charAt(i));
  814. }
  815. moveEnemies(data, player, enemies, time, isDead);
  816. getDot(data, player, dots);
  817. time.incrementAndGet();
  818. if (time.get() >= timeLimit) {
  819. isDead.set(true);
  820. }
  821. }
  822. }
  823. }
  824.  
  825. /**
  826. * 点を食べる
  827. * @param data データ
  828. * @param player プレイヤ
  829. * @param dots 点
  830. */
  831. static void getDot(final char[][] data, final Player player, final AtomicInteger dots) {
  832. if (data[player.y][player.x] == '.') {
  833. data[player.y][player.x] = ' ';
  834. dots.incrementAndGet();
  835. }
  836. }
  837.  
  838. /**
  839. * 敵を移動
  840. * @param data データ
  841. * @param player プレイヤ
  842. * @param enemies 敵
  843. * @param time 時刻
  844. * @param isDead 死んでいるかどうか
  845. */
  846. static void moveEnemies(final char[][] data, final Player player, final List<Enemy> enemies,
  847. final AtomicInteger time, final AtomicBoolean isDead) {
  848. for (final Enemy enemy : enemies) {
  849. final int x = enemy.x;
  850. final int y = enemy.y;
  851. enemy.move(data, player, time);
  852. enemy.lastX = x;
  853. enemy.lastY = y;
  854. if (enemy.killed(player)) {
  855. isDead.set(true);
  856. }
  857. }
  858. }
  859.  
  860. /**
  861. * 現在の状態を表示するラベルを更新
  862. * @param statusLabel ラベル
  863. * @param stage ステージ
  864. * @param timeLimit 制限時間
  865. * @param time 時刻
  866. * @param dots 点
  867. * @param log ログ
  868. */
  869. static void updateStatusLabel(final JLabel statusLabel, final Stage stage, final int timeLimit,
  870. final AtomicInteger time, final AtomicInteger dots, final StringBuilder log) {
  871. statusLabel.setText(new Formatter().format("time: %d/%d, score: %d/%d, log: %s",
  872. time.get(), timeLimit, dots.get(), stage.dots, log).toString());
  873. }
  874. }
Not running #stdin #stdout 0s 0KB
stdin
Standard input is empty
stdout
Standard output is empty