Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- import java.io.FileWriter;
- import java.io.IOException;
- import java.util.LinkedList;
- import java.util.Queue;
- import java.util.Scanner;
- public class Coderun {
- static FileWriter fw;
- /*
- * Sizes of the game field
- */
- private static final int FIELD_COLUMN_COUNT = 25;
- private static final int FIELD_ROW_COUNT = 16;
- /*
- * Values of cells
- */
- private static final char REMOVED_BRICK = '-';
- private static final char LADDER = 'H';
- private static final char BRICK = '=';
- private static final char EMPTY = '.';
- private static final char GOLD = '*';
- /*
- * Contains previous positions used by BFS
- */
- private static Position prevPosition[][] = new Position[FIELD_ROW_COUNT][FIELD_COLUMN_COUNT];
- /*
- * Contains previous moves used by BFS
- */
- private static Move prevMove[][] = new Move[FIELD_ROW_COUNT][FIELD_COLUMN_COUNT];
- /*
- * The game field
- */
- private static char[][] field = new char[FIELD_COLUMN_COUNT][FIELD_ROW_COUNT];
- /*
- * Position queue used by BFS
- */
- private static Queue<Position> queue = new LinkedList<Position>();
- /*
- * Programs of the enemies
- */
- private static String[] enemyPrograms;
- /*
- * Positions of the enemies
- */
- private static Position[] enemies;
- /*
- * Masters of the enemies
- */
- private static int[] masterOfEnemy;
- /*
- * Positions of the runners, our runner is on the first place
- */
- private static Position[] runners;
- /*
- * Some information about the runners
- */
- private static int[] scores;
- private static int[] delays;
- /*
- * Scanner used for data reading
- */
- private static Scanner in;
- /*
- * Enemy near runner position information
- */
- private static Position[] posi;
- /*
- * Check runner on LADDER
- */
- private static boolean LADDER_FLAG;
- // public Coderun() {
- // }
- /*
- * Entry point of player
- */
- public static void main(String[] args) {
- try {
- in = new Scanner(System.in);
- // Read initial state of the world
- int turns = in.nextInt();
- readFirstDescription();
- // Pass through turns
- for (int turnIndex = 0; turnIndex < turns; turnIndex++) {
- int turn = in.nextInt();
- if (turn == -1) {
- break;
- }
- // Read the current state of the world and make a move
- readStateDescription();
- System.out.println(makeMove());
- System.out.flush();
- }
- } catch (Exception e) {
- System.err.println(e.getMessage());
- System.exit(-1);
- }
- }
- /*
- * Calculates the next move for our runner
- */
- private static Move makeMove() {
- posi = new Position[13];
- for (int i = 0; i < 9; i++) {
- posi[i] = new Position(runners[0].getRow() - 1 + i / 3,
- runners[0].getColumn() - 1 + i % 3);
- }
- posi[9] = new Position(runners[0].getRow() - 2, runners[0].getColumn());
- posi[10] = new Position(runners[0].getRow() + 2, runners[0].getColumn());
- posi[11] = new Position(runners[0].getRow(), runners[0].getColumn() - 2);
- posi[12] = new Position(runners[0].getRow(), runners[0].getColumn() + 2);
- LADDER_FLAG = false;
- if (getCell(runners[0]) == LADDER)
- LADDER_FLAG = true;
- // Is our runner died?
- if (!runners[0].correct()) {
- return Move.NONE;
- }
- Move togo = moveToGold();
- Move reverse = reverseMove(togo);
- Position togoposi = moveDirection(togo);
- Position revgoposi = moveDirection(reverse);
- int toEnemy = isNearEnemy(togo);
- int reEnemy = isNearEnemy(reverse);
- if (LADDER_FLAG) {
- if (toEnemy != 0) {
- if (reEnemy != 0) {
- return Jump();
- } else {
- if (isLand()) {
- return Jump();
- }
- if (canGo(getCell(revgoposi)))
- return reverse;
- }
- }
- } else {
- if (toEnemy == 2) {
- if (togo.equals(Move.LEFT)) {
- return Move.DIG_LEFT;
- } else {
- return Move.DIG_RIGHT;
- }
- } else if (toEnemy == 1) {
- if (reEnemy == 0 && canGo(getCell(revgoposi))) {
- return reverse;
- } else {
- if (togo.equals(Move.LEFT)) {
- return Move.DIG_LEFT;
- } else {
- return Move.DIG_RIGHT;
- }
- }
- }
- }
- // Clearing arrays for BFS
- for (int x = 0; x < FIELD_ROW_COUNT; x++) {
- for (int y = 0; y < FIELD_COLUMN_COUNT; y++) {
- prevPosition[x][y] = null;
- prevMove[x][y] = null;
- }
- }
- // BFS
- queue.clear();
- Position target = null;
- // Start BFS from our runner's position to all cells with gold
- update(runners[0], null, Move.NONE);
- while (!queue.isEmpty()) {
- Position position = queue.poll();
- if (getCell(position) == GOLD) {
- target = position;
- break;
- }
- // Iterate through possible moves in order (LEFT, RIGHT, TOP,
- // BOTTOM)
- for (Move move : Move.values()) {
- Position newPosition = move(position, move);
- update(newPosition, position, move);
- }
- }
- // If there is no available gold on the field, then do nothing
- if (target == null) {
- return Move.NONE;
- }
- // Returning back through previous positions from the closest gold
- Position current = target, previous = target;
- while (!current.equals(runners[0])) {
- previous = current;
- current = prevPosition[current.getRow()][current.getColumn()];
- }
- // Make a move to the closest gold
- return prevMove[previous.getRow()][previous.getColumn()];
- }
- /*
- * Returns the next position if a one makes the given move from the given
- * position
- */
- private static Position move(Position currentPosition, Move move) {
- // Move ignoring trapped enemies
- Position newPosition = moveIgnoringEnemies(currentPosition, move, true);
- // Checks for a enemy below in cell with removed brick
- if (!newPosition.equals(currentPosition)
- && getCell(newPosition) == REMOVED_BRICK) {
- for (Position enemy : enemies) {
- if (enemy.equals(newPosition)) {
- // Move without fall down
- Position position = moveIgnoringEnemies(currentPosition,
- move, false);
- if (position.equals(newPosition) && move == Move.BOTTOM) {
- return currentPosition; // Cannot move below to the cell
- // with enemy
- } else {
- return position;
- }
- }
- }
- }
- return newPosition;
- }
- /*
- * Returns the next position if a one makes the given move from the given
- * position, but ignores enemies in cells with removed bricks
- */
- private static Position moveIgnoringEnemies(Position position, Move move,
- boolean canFly) {
- char currentCell = getCell(position);
- Position shiftedTopPosition = position.shift(Move.TOP);
- Position shiftedRightPosition = position.shift(Move.RIGHT);
- Position shiftedBottomPosition = position.shift(Move.BOTTOM);
- Position shiftedLeftPosition = position.shift(Move.LEFT);
- // Is flying?
- if (isEmptyLike(currentCell)
- && isEmptyLike(getCell(shiftedBottomPosition)) && canFly) {
- return shiftedBottomPosition;
- }
- if (move == Move.NONE) {
- return position;
- }
- switch (move) {
- case TOP:
- if (currentCell == LADDER && getCell(shiftedTopPosition) != BRICK) {
- return shiftedTopPosition;
- }
- break;
- case RIGHT:
- if (getCell(shiftedRightPosition) != BRICK) {
- return shiftedRightPosition;
- }
- break;
- case BOTTOM:
- if ((currentCell == LADDER || isEmptyLike(currentCell))
- && (getCell(shiftedBottomPosition) == LADDER || isEmptyLike(getCell(shiftedBottomPosition)))) {
- return shiftedBottomPosition;
- }
- break;
- case LEFT:
- if (getCell(shiftedLeftPosition) != BRICK) {
- return shiftedLeftPosition;
- }
- break;
- }
- return position;
- }
- /*
- * Returns true iff the cell looks like empty
- */
- private static boolean isEmptyLike(char cell) {
- return cell == EMPTY || cell == GOLD || cell == REMOVED_BRICK;
- }
- /*
- * Returns cell iff the position is inside the game field and BRICK
- * otherwise.
- */
- private static char getCell(Position position) {
- if (0 <= position.getRow() && position.getRow() < FIELD_ROW_COUNT) {
- if (0 <= position.getColumn()
- && position.getColumn() < FIELD_COLUMN_COUNT) {
- return field[position.getRow()][position.getColumn()];
- }
- }
- // The given position is out of the field
- return BRICK;
- }
- /*
- * Updates values in BFS
- */
- private static void update(Position position, Position prev, Move move) {
- if (prevMove[position.getRow()][position.getColumn()] == null) {
- prevPosition[position.getRow()][position.getColumn()] = prev;
- prevMove[position.getRow()][position.getColumn()] = move;
- queue.add(position);
- }
- }
- /*
- * Reads per-turn game state
- */
- private static void readStateDescription() {
- // Read the game field
- readGameField();
- // Read descriptions of the runners
- for (int i = 0; i < 2; i++) {
- runners[i] = readPosition();
- scores[i] = in.nextInt();
- delays[i] = in.nextInt();
- }
- // Read descriptions of the enemies
- for (int i = 0; i < enemies.length; i++) {
- enemies[i] = readPosition();
- masterOfEnemy[i] = in.nextInt();
- }
- }
- /*
- * Reads one-time world description
- */
- private static void readFirstDescription() {
- // Read the game field
- readGameField();
- runners = new Position[2];
- scores = new int[2];
- delays = new int[2];
- // Read descriptions of the runners
- readCharactersPositions(runners);
- // Read descriptions of the enemies
- int enemyCount = in.nextInt();
- enemies = new Position[enemyCount];
- enemyPrograms = new String[enemyCount];
- masterOfEnemy = new int[enemyCount];
- for (int i = 0; i < enemies.length; i++) {
- enemies[i] = readPosition();
- enemyPrograms[i] = in.next();
- }
- }
- /*
- * Reads the game field from the scanner
- */
- private static void readGameField() {
- for (int i = 0; i < FIELD_ROW_COUNT; i++) {
- String line = in.next();
- for (int j = 0; j < FIELD_COLUMN_COUNT; j++) {
- field[i] = line.toCharArray();
- }
- }
- }
- /*
- * Reads array of positions from the scanner
- */
- private static void readCharactersPositions(Position[] positions) {
- for (int i = 0; i < positions.length; i++) {
- positions[i] = readPosition();
- }
- }
- /*
- * Reads position from the scanner
- */
- private static Position readPosition() {
- int row = in.nextInt();
- int column = in.nextInt();
- return new Position(row, column);
- }
- /*
- * Class for positions of runners and enemies on the game field
- */
- private static class Position {
- private final int row;
- private final int column;
- private Position(int row, int column) {
- this.row = row;
- this.column = column;
- }
- public int getRow() {
- return row;
- }
- public int getColumn() {
- return column;
- }
- // Correct position isn't equal to "-1 -1"
- public boolean correct() {
- return row >= 0 && column >= 0;
- }
- // Shift position to specific direction
- public Position shift(Move move) {
- if (move == Move.LEFT) {
- return new Position(row, column - 1);
- }
- if (move == Move.RIGHT) {
- return new Position(row, column + 1);
- }
- if (move == Move.TOP) {
- return new Position(row - 1, column);
- }
- if (move == Move.BOTTOM) {
- return new Position(row + 1, column);
- }
- return new Position(row, column);
- }
- @Override
- public String toString() {
- return "(" + row + ", " + column + ")";
- }
- @Override
- public boolean equals(Object o) {
- if (this == o)
- return true;
- if (!(o instanceof Position))
- return false;
- Position position = (Position) o;
- return row == position.row && column == position.column;
- }
- @Override
- public int hashCode() {
- int result = row;
- result = 31 * result + column;
- return result;
- }
- }
- /*
- * Name: getDistance Type: int Parameter: Position p1, Position p2
- * Operation: Return distance from p1 to p2
- */
- public static int getDistance(Position p1, Position p2) {
- return (p1.getRow() - p2.getRow() + p1.getColumn() - p2.getColumn());
- }
- /*
- * Name: Landing Type: int Parameter: Position p Operation: Return distance
- * from the runner to land runner will meet after jumping
- */
- public static int Landing(Position p) {
- for (int i = 0; i < 16; i++) {
- Position tmp = new Position(p.getRow() + i, p.getColumn());
- if (getCell(tmp) == BRICK) {
- return i;
- }
- }
- return 0;
- }
- /*
- * Name: Jump() Type: Move Parameter: void Operation: Return jump when
- * enemies comes to you from both sides.
- */
- public static Move Jump() {
- int left_landing;
- boolean left_flag;
- int left;
- int right_landing;
- boolean right_flag;
- int right;
- Move mtg = moveToGold();
- Move rtg = reverseMove(moveToGold());
- Position toGo = moveDirection(mtg);
- Position reversetoGo = moveDirection(rtg);
- if (isEmptyLike(getCell(posi[3]))) { // left empty
- left_landing = Landing(posi[3]);
- left_flag = LandOkay(posi[3], left_landing);
- left = isNearEnemy(Move.LEFT);
- } else { // left brick
- left_landing = 0;
- left_flag = false;
- left = 0;
- }
- if (isEmptyLike(getCell(posi[5]))) { // right empty
- right_landing = Landing(posi[5]);
- right_flag = LandOkay(posi[5], right_landing);
- right = isNearEnemy(Move.RIGHT);
- } else { // right brick
- right_flag = false;
- right_landing = 0;
- right = 0;
- }
- if (isLand()) { // bottom?
- if (isEmptyLike(getCell(posi[3])) && isEmptyLike(getCell(posi[6]))
- && left == 0) {
- return Move.LEFT;
- } else if (isEmptyLike(getCell(posi[5]))
- && isEmptyLike(getCell(posi[8])) && right == 0) {
- return Move.RIGHT;
- } else {
- if (right != 0 && left > right) {
- return Move.DIG_RIGHT;
- } else if (left != 0 && left <= right) {
- return Move.DIG_LEFT;
- }
- }
- }
- if (left_landing == 0 && right_landing == 0) {
- if (isNearEnemy(mtg) > isNearEnemy(rtg)) {
- return mtg;
- } else if (canGo(getCell(reversetoGo))) {
- return rtg;
- }
- }
- if (left_landing == 1 && right_landing == 1) {
- if (left == 0) {
- if (right == 0)
- return mtg;
- else if (canGo(getCell(posi[3])))
- return Move.LEFT;
- } else if (right == 0 && canGo(getCell(posi[5]))) {
- return Move.RIGHT;
- }
- if (left == 1) {
- if (canDig(Move.RIGHT))
- return Move.DIG_RIGHT;
- return Move.RIGHT;
- } else {
- if (canDig(Move.LEFT))
- return Move.DIG_LEFT;
- if (isNearEnemy(mtg) > isNearEnemy(rtg)) {
- return mtg;
- } else if (canGo(getCell(reversetoGo))) {
- return rtg;
- }
- }
- } else if (left_landing == 1) {
- if (left == 0) {
- return Move.LEFT;
- } else if ((left == 1 || left == 2) && canDig(Move.LEFT)) {
- return Move.DIG_LEFT;
- } else {
- if (LandOkay(posi[5], Landing(posi[5]))
- && inthetrick(Move.RIGHT)) {
- return Move.RIGHT;
- }
- if (isNearEnemy(moveToGold()) == 2) {
- return mtg;
- }
- if (isNearEnemy(reverseMove(moveToGold())) == 2
- && canGo(getCell(reversetoGo))) {
- return rtg;
- }
- return Move.RIGHT;
- }
- } else if (right_landing == 1) {
- if (right == 0) {
- return Move.RIGHT;
- } else if ((right == 1 || right == 2) && canDig(Move.RIGHT)) {
- return Move.DIG_RIGHT;
- } else {
- if (LandOkay(posi[3], Landing(posi[3]))
- && inthetrick(Move.LEFT)) {
- return Move.LEFT;
- }
- if (isNearEnemy(moveToGold()) == 2) {
- return mtg;
- }
- if (isNearEnemy(reverseMove(moveToGold())) == 2
- && canGo(getCell(reversetoGo))) {
- return rtg;
- }
- return Move.LEFT;
- }
- } else {
- if (left_flag) {
- if (right_flag) {
- if (left_landing > right_landing) {
- return Move.RIGHT;
- } else {
- return Move.LEFT;
- }
- }
- return Move.LEFT;
- } else {
- if (right_flag) {
- return Move.RIGHT;
- }
- if (isNearEnemy(moveToGold()) == 2) {
- return mtg;
- }
- if (canGo(getCell(reversetoGo))) {
- }
- return rtg;
- }
- }
- return Move.NONE;
- }
- /*
- * Name: LandOkay Type: boolean Parameter: Position p, int index Operation:
- * Return true when the runner can live after jumping.
- */
- public static boolean LandOkay(Position p, int index) {
- Position tmp = new Position(p.getRow() + index - 1, p.getColumn());
- Position isEL = new Position(tmp.getRow(), tmp.getColumn()
- - (index - 1) / 2);
- Position isELR = new Position(tmp.getRow(), tmp.getColumn()
- - (index - 1) / 2 + 1);
- Position isELL = new Position(tmp.getRow(), tmp.getColumn()
- - (index - 1) / 2 - 1);
- Position isER = new Position(tmp.getRow(), tmp.getColumn()
- + (index - 1) / 2);
- Position isERR = new Position(tmp.getRow(), tmp.getColumn()
- + (index - 1) / 2 + 1);
- Position isERL = new Position(tmp.getRow(), tmp.getColumn()
- + (index - 1) / 2 - 1);
- for (Position e : enemies) {
- if (isEL.equals(e) || isELL.equals(e) || isELR.equals(e)
- || isER.equals(e) || isERL.equals(e) || isERR.equals(e)) {
- return false;
- }
- }
- return true;
- }
- public static int isNearEnemy(Move m) {
- int dir1 = 0, dir2 = 0, dir3 = 0, dir4 = 0;
- int dist = 0;
- int flag = 0;
- if (m.equals(Move.LEFT)) {
- dir1 = 3;
- dir2 = 11;
- } else if (m.equals(Move.RIGHT)) {
- dir1 = 5;
- dir2 = 12;
- } else if (m.equals(Move.TOP)) {
- dir1 = 1;
- dir2 = 9;
- flag = 3;
- } else {
- dir1 = 7;
- dir2 = 10;
- flag = 4;
- }
- for (Position e : enemies) {
- if (posi[dir1].equals(e)) {
- dist = 1;
- break;
- }
- if (posi[dir2].equals(e)) {
- dist = 2;
- }
- }
- if (LADDER_FLAG && dist != 0) {
- switch (flag) {
- case 3:
- dir3 = 0;
- dir4 = 2;
- break;
- case 4:
- dir3 = 6;
- dir4 = 8;
- break;
- }
- if (flag != 0) {
- for (Position e : enemies) {
- if (posi[dir3].equals(e)) {
- dist = 2;
- break;
- }
- if (posi[dir4].equals(e)) {
- dist = 2;
- }
- }
- }
- }
- return dist;
- }
- private static Move moveToGold() {//
- // Clearing arrays for BFS
- for (int x = 0; x < FIELD_ROW_COUNT; x++) {
- for (int y = 0; y < FIELD_COLUMN_COUNT; y++) {
- prevPosition[x][y] = null;
- prevMove[x][y] = null;
- }
- }
- // BFS
- queue.clear();
- Position target = null;
- // Start BFS from our runner's position to all cells with gold
- update(runners[0], null, Move.NONE);
- while (!queue.isEmpty()) {
- Position position = queue.poll();
- if (getCell(position) == GOLD) {
- target = position;
- break;
- }
- // Iterate through possible moves in order (LEFT, RIGHT, TOP,
- // BOTTOM)
- for (Move move : Move.values()) {
- Position newPosition = move(position, move);
- update(newPosition, position, move);
- }
- }
- // If there is no available gold on the field, then do nothing
- if (target == null) {
- return Move.NONE;
- }
- // Returning back through previous positions from the closest gold
- Position current = target, previous = target;
- while (!current.equals(runners[0])) {
- previous = current;
- current = prevPosition[current.getRow()][current.getColumn()];
- }
- // Make a move to the closest gold
- return prevMove[previous.getRow()][previous.getColumn()];
- }
- public static Move reverseMove(Move m) {
- if (m.equals(Move.LEFT)) {
- return Move.RIGHT;
- } else if (m.equals(Move.RIGHT)) {
- return Move.LEFT;
- } else if (m.equals(Move.TOP)) {
- return Move.BOTTOM;
- } else if (m.equals(Move.BOTTOM)) {
- return Move.TOP;
- } else {
- return Move.NONE;
- }
- }
- public static boolean isLand() {
- if (getCell(posi[7]) == BRICK) {
- return true;
- }
- return false;
- }
- public static boolean isEnemy(Position p) {
- for (Position e : enemies) {
- if (p.equals(e)) {
- return true;
- }
- }
- return false;
- }
- private static boolean canDig(Move side) {
- if (runners[0].correct()
- && delays[0] == 0
- && runners[0].getRow() != FIELD_COLUMN_COUNT - 1
- && (getCell(runners[0]) == LADDER
- || getCell(runners[0].shift(Move.BOTTOM)) == LADDER
- || getCell(runners[0].shift(Move.BOTTOM)) == BRICK)
- && getCell(runners[0].shift(Move.BOTTOM).shift(side)) == BRICK
- && getCell(runners[0].shift(side)) != BRICK
- && getCell(runners[0].shift(side)) != LADDER)
- return true;
- else
- return false;
- }
- private static boolean canGo(char cell) {
- return isEmptyLike(cell) || cell == LADDER;
- }
- private static boolean inthetrick(Move move) {
- if (getCell(runners[0].shift(Move.RIGHT)) == REMOVED_BRICK
- && move == Move.RIGHT) {
- return true;
- }
- else if (getCell(runners[0].shift(Move.LEFT)) == REMOVED_BRICK
- && move == Move.LEFT) {
- return true;
- }
- return false;
- }
- private static Position moveDirection(Move m) {
- Position toGo;
- switch (m) {
- case BOTTOM:
- toGo = posi[7];
- break;
- case LEFT:
- toGo = posi[3];
- break;
- case RIGHT:
- toGo = posi[5];
- break;
- case TOP:
- toGo = posi[1];
- break;
- default:
- toGo = new Position(-1, -1);
- break;
- }
- return toGo;
- }
- /*
- * Possible moves of runner
- */
- private static enum Move {
- NONE, LEFT, RIGHT, TOP, BOTTOM, DIG_LEFT, DIG_RIGHT
- }
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement