Problem p00658 (C++) — buggy submission, verdict: Time Limit Exceeded

#include <cctype>
#include <iostream>
#include <sstream>
#include <string>
#include <vector>
using namespace std;

int dx[] = {-1, 0, 1, 0};

int cx[] = {-1, 0, 1};
int W, H, T;
int Gx, Gy;

string field[55];

void dump() {
  for (int i = 0; i < H; i++)
    cout << field[i] << endl;
}

bool isBlock(char c) { return isalnum(c) || c == '#'; }

bool Up(int x, int y, int dir) {
  int hx = x + dx[dir], hy = y;
  if (hx < 0 || hx >= W)
    return false;
  if (!isBlock(field[hy][hx]))
    return false;

  int mx = x, my = y - 1;
  if (my < 0)
    return false;
  if (field[my][mx] != '.' || field[my][hx] != '.')
    return false;

  return true;
}

bool Down(int x, int y, int dir) {
  int hx = x + dx[dir], hy = y;
  if (hx < 0 || hx >= W)
    return false;
  if (field[hy][hx] != '.')
    return false;

  int mx = hx, my = hy + 1;
  if (my >= H)
    return false;
  if (field[my][mx] != '.')
    return false;

  return true;
}

bool canMove(int x, int y, int mx, int dir) {
  if (mx < 0 || mx >= W)
    return false;
  if (field[y][mx] != '.')
    return false;
  if (y == H - 1)
    return true;

  int tx = x;
  while (1) {
    if (!isBlock(field[y + 1][tx]))
      return false;

    if (tx == mx)
      break;
    tx += dx[dir];
  }

  return true;
}

bool cPull(int x, int y, int dir) {
  int tx = x + dx[dir], ty = y;
  int bx = x - dx[dir], by = y;

  if (bx < 0 || bx >= W)
    return false;
  if (!isBlock(field[by][bx]))
    return false;
  if (field[by][bx] == 'C')
    return false;

  if (tx < 0 || tx >= W)
    return false;
  if (field[ty][tx] != '.')
    return false;

  field[y][x] = field[by][bx];
  field[by][bx] = '.';

  return true;
}

bool canPush(int x, int y, int dir) {
  int tx = x, ty = y;
  while (1) {
    tx += dx[dir];

    if (tx < 0 || tx >= W)
      break;
    if (!isBlock(field[ty][tx]))
      break;
    if (field[ty][tx] == 'C')
      return false;
  }

  tx -= dx[dir];

  if (x == tx)
    return false;

  return true;
}

void moveBlock(int x, int y, int dir) {
  char tmp = field[y][x];
  field[y][x] = '.';
  int tx = x + dx[dir], ty = y;

  while (1) {
    if (tx < 0 || tx >= W)
      return;
    if (isBlock(field[ty][tx])) {
      tx -= dx[dir];
      break;
    }
    if (tmp != 'I') {
      if (ty == H - 1)
        break;

      if (field[ty + 1][tx] != 'I')
        break;
    } else {
      if (ty != H - 1) {
        if (field[ty + 1][tx] == '.')
          break;
      }
    }

    tx += dx[dir];
  }

  field[ty][tx] = tmp;
}

void cPush(int x, int y, int dir) {
  int tx = x, ty = y;
  while (1) {
    tx += dx[dir];

    if (tx < 0 || tx >= W)
      break;
    if (!isBlock(field[ty][tx]))
      break;
  }

  tx -= dx[dir];

  while (x != tx) {
    moveBlock(tx, ty, dir);

    tx -= dx[dir];
  }
}

bool countDown(int x, int y, int px, int py) {
  if (x == px && y == py)
    return false;
  if (py == H - 1)
    return false;

  if (!isdigit(field[py + 1][px]))
    return false;

  int cnt = field[py + 1][px] - '0' - 1;
  if (cnt == 0)
    field[py + 1][px] = '.';
  else
    field[py + 1][px] = cnt + '0';

  return true;
}

bool vanish() {
  bool res = false;
  for (int i = 1; i < H; i++)
    for (int j = 0; j < W; j++) {
      if (field[i][j] == 'B') {
        if (field[i - 1][j] != '.') {
          field[i - 1][j] = '.';
          res = true;
        }
      }
    }

  return res;
}

bool fallPlayer(int x, int &y) {
  int tx = x, ty = y;
  while (1) {
    if (ty == H - 1)
      break;
    if (isBlock(field[ty + 1][tx]))
      break;

    ty++;
  }

  if (ty == y)
    return false;

  y = ty;

  return true;
}

bool checkFall(int x, int y) {
  if (y == H - 1)
    return false;

  for (int i = 0; i < 3; i++) {
    int nx = x + cx[i];
    int ny = y + 1;
    if (nx < 0 || ny < 0 || nx >= W || ny >= H)
      continue;
    if (isBlock(field[ny][nx]))
      return false;
  }

  return true;
}

bool fallBlock(int x, int y) {
  if (y == H - 1)
    return false;
  if (!isBlock(field[y][x]))
    return false;

  char tmp = field[y][x];
  int tx = x, ty = y;

  field[y][x] = '.';

  while (checkFall(tx, ty)) {
    ty++;
  }

  field[ty][tx] = tmp;

  return (x != tx || y != ty);
}

bool loopfallBlock() {
  bool res = false;
  for (int i = H - 2; i >= 0; i--)
    for (int j = 0; j < W; j++) {
      res |= fallBlock(j, i);
    }

  return res;
}

void execTurnEnd(int x, int &y, int px, int py) {
  countDown(x, y, px, py);

  while (1) {
    bool moved = false;

    moved |= vanish();
    moved |= fallPlayer(x, y);
    moved |= loopfallBlock();

    if (!moved)
      break;
  }
}

int checkGameOver(int x, int y) {
  if (y != H - 1) {
    if (field[y + 1][x] == 'G')
      return 0;
    if (field[y + 1][x] == 'B')
      return 1;
  }

  if (isBlock(field[y][x]))
    return 2;
  if (field[Gy][Gx] != 'G')
    return 3;

  return -1;
}

void output(int type) {
  if (type == 0)
    cout << "Game Over : Cleared" << endl;
  if (type == 1)
    cout << "Game Over : Death by Hole" << endl;
  if (type == 2)
    cout << "Game Over : Death by Block" << endl;
  if (type == 3)
    cout << "Game Over : Death by Walking Goal" << endl;
  if (type == 4)
    cout << "Game Over : Gave Up" << endl;
}

int parseInt(string a) {
  stringstream ss(a);

  int res;
  ss >> res;

  return res;
}

void doCommand(int sx, int sy, vector<string> &commands) {
  int x = sx, y = sy;

  for (int i = 0; i < commands.size(); i += 2) {
    int px = x, py = y;

    int res = checkGameOver(x, y);
    if (res != -1) {
      output(res);
      return;
    }

    if (commands[i] == "MOVETO") {
      int s = parseInt(commands[i + 1]) - 1;
      int d = (s < x ? 0 : 2);
      if (canMove(x, y, s, d)) {
        x = s;
      }
    }

    if (commands[i] == "PUSH") {
      int d = (commands[i + 1] == "LEFT" ? 0 : 2);
      if (canPush(x, y, d)) {
        cPush(x, y, d);
      }
    }

    if (commands[i] == "PULL") {
      int d = (commands[i + 1] == "LEFT" ? 0 : 2);
      if (cPull(x, y, d)) {
        x += dx[d];
      }
    }

    if (commands[i] == "GETDOWN") {
      int d = (commands[i + 1] == "LEFT" ? 0 : 2);
      if (Down(x, y, d)) {
        x += dx[d];
        y += 1;
      }
    }

    if (commands[i] == "CLIMB") {
      int d = (commands[i + 1] == "LEFT" ? 0 : 2);
      if (Up(x, y, d)) {
        x += dx[d];
        y -= 1;
      }
    }

    res = checkGameOver(x, y);
    if (res != -1) {
      output(res);
      return;
    }

    execTurnEnd(x, y, px, py);
  }

  int res = checkGameOver(x, y);
  if (res != -1) {
    output(res);
    return;
  }
  output(4);
}

int main() {

  while (cin >> H >> W, (W || H)) {
    vector<string> command;
    for (int i = 0; i < H; i++)
      cin >> field[i];

    int sx, sy;
    for (int i = 0; i < H; i++)
      for (int j = 0; j < W; j++) {
        if (field[i][j] == 'S') {
          sx = j;
          sy = i;
          field[i][j] = '.';
        }
        if (field[i][j] == 'G') {
          Gx = j;
          Gy = i;
        }
      }

    cin >> T;
    for (int i = 0; i < T; i++) {
      string a, b;
      cin >> a >> b;
      command.push_back(a);
      command.push_back(b);
    }

    doCommand(sx, sy, command);
  }
}

Error: TLE

Fixed submission:

#include <cctype>
#include <iostream>
#include <string>
#include <vector>
using namespace std;

int dx[] = {-1, 0, 1, 0};
int dy[] = {0, -1, 0, 1};

int cx[] = {-1, 0, 1};
int W, H, T;
int Gx, Gy;

string field[55];

void dump() {
  for (int i = 0; i < H; i++)
    cout << field[i] << endl;
}

bool isBlock(char c) { return isalnum(c) || c == '#'; }

bool Up(int x, int y, int dir) {
  int hx = x + dx[dir], hy = y;
  if (hx < 0 || hx >= W)
    return false;
  if (!isBlock(field[hy][hx]))
    return false;

  int mx = x, my = y - 1;
  if (my < 0)
    return false;
  if (field[my][mx] != '.')
    return false;

  mx += dx[dir];
  if (field[my][mx] != '.')
    return false;

  return true;
}

bool Down(int x, int y, int dir) {
  int hx = x + dx[dir], hy = y;
  if (hx < 0 || hx >= W)
    return false;
  if (field[hy][hx] != '.')
    return false;

  int mx = hx, my = hy + 1;
  if (my >= H)
    return false;
  if (field[my][mx] != '.')
    return false;

  return true;
}

bool canMove(int x, int y, int mx, int dir) {
  if (field[y][mx] != '.')
    return false;
  if (y == H - 1)
    return true;

  int tx = x + dx[dir];
  while (1) {

    if (tx == mx)
      break;
    if (!isBlock(field[y + 1][x]))
      return false;

    tx += dx[dir];
  }

  return true;
}

bool cPull(int x, int y, int dir) {
  int tx = x + dx[dir], ty = y + dy[dir];
  int bx = x - dx[dir], by = y - dy[dir];

  if (bx < 0 || bx >= W)
    return false;
  if (!isBlock(field[by][bx]))
    return false;
  if (field[by][bx] == 'C')
    return false;

  if (tx < 0 || tx >= W)
    return false;
  if (field[ty][tx] != '.')
    return false;

  field[y][x] = field[by][bx];
  field[by][bx] = '.';

  return true;
}

bool canPush(int x, int y, int dir) {
  int tx = x, ty = y;
  while (1) {
    tx += dx[dir];

    if (tx < 0 || tx >= W)
      break;
    if (!isBlock(field[ty][tx]))
      break;
    if (field[ty][tx] == 'C')
      return false;
  }

  tx -= dx[dir];

  if (x == tx)
    return false;

  return true;
}

void moveBlock(int x, int y, int dir) {
  char tmp = field[y][x];
  field[y][x] = '.';
  int tx = x + dx[dir], ty = y;

  while (1) {
    if (tx < 0 || tx >= W)
      return;
    if (isBlock(field[ty][tx])) {
      tx -= dx[dir];
      break;
    }
    if (tmp != 'I') {
      if (ty != H - 1) {
        if (field[ty + 1][tx] != 'I')
          break;
      } else
        break;
    }

    if (ty != H - 1) {
      if (tx != x && field[ty + 1][tx] == '.')
        break;
    }

    tx += dx[dir];
  }

  field[ty][tx] = tmp;
}

void Push(int x, int y, int dir) {
  int tx = x, ty = y;
  while (1) {
    tx += dx[dir];
    if (tx < 0 || tx >= W)
      break;

    if (!isBlock(field[ty][tx]))
      break;
  }

  tx -= dx[dir];

  while (1) {
    if (x == tx)
      break;
    moveBlock(tx, ty, dir);

    tx -= dx[dir];
  }
}

bool cPush(int x, int y, int dir) {
  if (!canPush(x, y, dir))
    return false;

  Push(x, y, dir);

  return true;
}

bool countDown(int x, int y, int px, int py) {
  if (x == px && y == py)
    return false;
  if (py == H - 1)
    return false;

  if (!isdigit(field[py + 1][px]))
    return false;

  int cnt = field[py + 1][px] - '0' - 1;
  if (cnt == 0)
    field[py + 1][px] = '.';
  else
    field[py + 1][px] = cnt + '0';

  return true;
}

bool extinct() {
  for (int i = 1; i < H; i++)
    for (int j = 0; j < W; j++) {
      if (field[i][j] == 'B') {
        if (field[i - 1][j] != '.') {
          field[i - 1][j] = '.';
          return true;
        }
      }
    }

  return false;
}

bool fallPlayer(int x, int &y) {
  int tx = x, ty = y;
  while (1) {
    if (ty == H - 1)
      break;
    if (isBlock(field[ty + 1][tx]))
      break;

    ty++;
  }

  if (ty == y)
    return false;

  y = ty;

  return true;
}

bool checkFall(int x, int y) {
  if (y == H - 1)
    return false;

  for (int i = 0; i < 3; i++) {
    int nx = x + cx[i];
    int ny = y + 1;
    if (nx < 0 || ny < 0 || nx >= W || ny >= H)
      continue;
    if (isBlock(field[ny][nx]))
      return false;
  }

  return true;
}

bool fallBlock(int x, int y) {
  if (y == H - 1)
    return false;
  if (!isBlock(field[y][x]))
    return false;

  char tmp = field[y][x];
  int tx = x, ty = y;

  field[y][x] = '.';

  while (checkFall(tx, ty)) {
    ty++;
  }

  field[ty][tx] = tmp;

  return x != tx || y != ty;
}

bool loopfallBlock() {
  bool res = false;
  for (int i = H - 1; i >= 0; i--)
    for (int j = 0; j < W; j++) {
      res |= fallBlock(j, i);
    }

  return res;
}

void execTurnEnd(int x, int &y, int px, int py) {
  countDown(x, y, px, py);

  while (1) {
    bool moved = false;

    moved |= extinct();
    moved |= fallPlayer(x, y);
    moved |= loopfallBlock();

    if (!moved)
      break;
  }
}

int checkGameOver(int x, int y) {
  if (y != H - 1) {
    if (field[y + 1][x] == 'G')
      return 0;
    if (field[y + 1][x] == 'B')
      return 1;
  }

  if (field[y][x] == '#')
    return 2;
  if (field[Gy][Gx] != 'G')
    return 3;

  return -1;
}

void output(int type) {
  if (type == 0)
    cout << "Game Over : Cleared" << endl;
  if (type == 1)
    cout << "Game Over : Death by Hole" << endl;
  if (type == 2)
    cout << "Game Over : Death by Block" << endl;
  if (type == 3)
    cout << "Game Over : Death by Walking Goal" << endl;
  if (type == 4)
    cout << "Game Over : Gave Up" << endl;
}

int parseInt(string a) {
  int res = 0;
  for (int i = 0; i < a.size(); i++) {
    res *= 10;
    res += a[i] - '0';
  }

  return res;
}

void doCommand(int sx, int sy, vector<string> &commands) {
  int x = sx, y = sy;

  for (int i = 0; i < commands.size(); i += 2) {
    int px = x, py = y;

    int res = checkGameOver(x, y);
    if (res != -1) {
      output(res);
      return;
    }

    if (commands[i] == "MOVETO") {
      int s = parseInt(commands[i + 1]) - 1;
      int d = (s < x ? 0 : 2);

      if (canMove(x, y, s, d))
        x = s;
    }

    if (commands[i] == "PUSH") {
      int d = (commands[i + 1] == "LEFT" ? 0 : 2);
      cPush(x, y, d);
    }

    if (commands[i] == "PULL") {
      int d = (commands[i + 1] == "LEFT" ? 0 : 2);
      if (cPull(x, y, d)) {
        x += dx[d];
        y += dy[d];
      }
    }

    if (commands[i] == "GETDOWN") {
      int d = (commands[i + 1] == "LEFT" ? 0 : 2);
      if (Down(x, y, d)) {
        x += dx[d];
        y += 1;
      }
    }

    if (commands[i] == "CLIMB") {
      int d = (commands[i + 1] == "LEFT" ? 0 : 2);
      if (Up(x, y, d)) {
        x += dx[d];
        y -= 1;
      }
    }

    res = checkGameOver(x, y);
    if (res != -1) {
      output(res);
      return;
    }

    execTurnEnd(x, y, px, py);
  }

  int res = checkGameOver(x, y);
  if (res != -1) {
    output(res);
    return;
  }
  output(4);
}

int main() {

  while (cin >> H >> W, (W || H)) {
    vector<string> command;
    for (int i = 0; i < H; i++)
      cin >> field[i];

    int sx, sy;
    for (int i = 0; i < H; i++)
      for (int j = 0; j < W; j++) {
        if (field[i][j] == 'S') {
          sx = j;
          sy = i;
          field[i][j] = '.';
        }
        if (field[i][j] == 'G') {
          Gx = j;
          Gy = i;
        }
      }

    cin >> T;
    for (int i = 0; i < T; i++) {
      string a, b;
      cin >> a >> b;
      command.push_back(a);
      command.push_back(b);
    }

    doCommand(sx, sy, command);
  }
}