Skip to content
Snippets Groups Projects
board.cpp 6.47 KiB
Newer Older
#include "board.h"
#include "colors.h"

std::string ship_names[] = { "Aircraft Carrier", "Battleship", "Cruiser", "Submarine", "Destroyer" };
int ship_sizes[] = { 5, 4, 3, 3, 2 };

board::board(int side) : side(side) {
  int i, j, k;
  
  for (i = 0; i < 10; i++) {
    for (j = 0; j < 10; j++) {
      guesses[i][j] = 0;
    }
  }
  
  for (i = 0; i < 5; i++) {
    while (true) {
      int dir = randrange(0, 3);
      int x = randrange(0, 9);
      int y = randrange(0, 9);
      
      int dx = 0;
      int dy = 0;

      if (dir == UP) {
        dy = -1;
      } else if (dir == DOWN) {
        dy = 1;
      } else if (dir == LEFT) {
        dx = -1;
      } else if (dir == RIGHT) {
        dx = 1;
      }
      
      bool valid = true;
      for (j = 0; j < ship_sizes[i]; j++) {
        int tmpx = x + (j * dx);
        int tmpy = y + (j * dy);
        
        if (tmpx < 0 || tmpx > 9 || tmpy < 0 || tmpy > 9) {
          valid = false;
          break;
        }
        
        bool collides = false;
        for (k = 0; k < (int)ships.size(); k++) {
          if (ships[k]->contains(tmpx, tmpy)) collides = true;
        }
        if (collides) {
          valid = false;
          break;
        }
      }
      if (!valid) continue;
      
      ships.push_back(new ship(x, y, dir, ship_sizes[i], ship_names[i]));
      break;
    }
  }
  
  cursor_x = 0;
  cursor_y = 0;
  show_cursor = false;
}

board::board(int side, std::string &board_description) : side(side) {
  int i, j;
  
  for (i = 0; i < 10; i++) {
    for (j = 0; j < 10; j++) {
      guesses[i][j] = 0;
    }
  }
  
  for (i = 0; i < 5; i++) {
    int y = board_description[(i * 3) + 0] - 'A';
    int x = board_description[(i * 3) + 1] - '0';
    int dir = board_description[(i * 3) + 2] - '0';
    
    ships.push_back(new ship(x, y, dir, ship_sizes[i], ship_names[i]));
  }
  
  cursor_x = 0;
  cursor_y = 0;
  show_cursor = false;
}

std::string board::get_description() {
  std::string result;
  
  for (int i = 0; i < 5; i++) {
    result.push_back('A' + ships[i]->get_y());
    result.push_back('0' + ships[i]->get_x());
    result.push_back('0' + ships[i]->get_dir());
  }
  
  return result;
}

board::~board() {
  for (int i = 0; i < (int)ships.size(); i++) {
    delete ships[i];
  }
  ships.clear();
}

bool board::has_lost() {
  for (int i = 0; i < (int)ships.size(); i++) {
    if (!ships[i]->is_sunk()) return false;
  }
  return true;
}

void board::make_move(std::string position) {
  int y = position[0] - 'A';
  int x = position[1] - '1';
  
Jake Feddersen's avatar
Jake Feddersen committed
  bool resultHit = false;
  
  for (int i = 0; i < (int)ships.size(); i++) {
Jake Feddersen's avatar
Jake Feddersen committed
    if (ships[i]->contains(x, y)) {
      resultHit = true;
      ships[i]->hit();
    }
  }
  
  int x_offset = 0;
  
  if (side == PLAYER) {
    x_offset = 57;
  }
  
  attron(COLOR_PAIR(TEXT_WHITE));
  mvprintw(14, x_offset, "                      ");
  mvprintw(14, x_offset, "Last Move: %c%d", 'A' + y, x + 1);
  attroff(COLOR_PAIR(TEXT_WHITE));
  
  if (resultHit) {
    attron(COLOR_PAIR(TEXT_RED));
    mvprintw(14, x_offset + 20, "HIT");
    attroff(COLOR_PAIR(TEXT_RED));
  } else {
    attron(COLOR_PAIR(TEXT_WHITE));
    mvprintw(14, x_offset + 19, "MISS");
    attroff(COLOR_PAIR(TEXT_WHITE));
  }
  
  guesses[y][x] = true;
}

int board::get_position_color(int x, int y) {
  if (side == OPPONENT) {
    if (show_cursor && x == cursor_x && y == cursor_y) {
      return BG_GREEN;
    }
    
    if (guesses[y][x]) {
      for (int i = 0; i < (int)ships.size(); i++) {
        if (ships[i]->contains(x, y)) {
          return BG_RED;
        }
      }
      return BG_WHITE;
    return BG_BLACK;
  } else {
    if (guesses[y][x]) {
      for (int i = 0; i < (int)ships.size(); i++) {
        if (ships[i]->contains(x, y)) {
          return BG_RED;
        }
      }
      return BG_WHITE;
    } else {
      for (int i = 0; i < (int)ships.size(); i++) {
        if (ships[i]->contains(x, y)) {
          return BG_BLACK;
        }
      }
      return BG_CYAN;
    }
  }
}

void board::draw() {
  int x_offset = 0;
  
  if (side == PLAYER) {
    x_offset = 57;
  }
  
  attron(COLOR_PAIR(TEXT_WHITE));
  
  mvprintw(0, 4, "Opponent's Ships");
  mvprintw(0, 64, "Your Ships");
  
  mvprintw(1, x_offset, "  1 2 3 4 5 6 7 8 9 10 ");
  for (int i = 0; i < 10; i++) {
    mvaddch(3 + i, x_offset, 'A' + i);
    mvaddch(3 + i, x_offset+1, '|');
    mvaddch(3 + i, x_offset+22, '|');
  }
  
  for (int i = 0; i < 22; i++) {
    mvaddch(2, x_offset+i+1, '-');
    mvaddch(13, x_offset+i+1, '-');
  attroff(COLOR_PAIR(TEXT_WHITE));
  
  for (int i = 0; i < 10; i++) {
    for (int j = 0; j < 10; j++) {
      int color = get_position_color(j, i);
      attron(COLOR_PAIR(color));
      mvprintw(i+3, x_offset + 2 + (j*2), "  ");
      attroff(COLOR_PAIR(color));
    }
  }
  
  for (int i = 0; i < 5; i++) {
Jake Feddersen's avatar
Jake Feddersen committed
    ships[i]->print_ship(x_offset, 16+i);
  }
  
  refresh();
}

void board::draw_game_over() {
  int x_offset = 0;
  
  if (side == PLAYER) {
    x_offset = 57;
  }
  
  attron(COLOR_PAIR(TEXT_WHITE));
  
  mvprintw(0, 4, "Opponent's Ships");
  mvprintw(0, 64, "Your Ships");
  
  mvprintw(1, x_offset, "  1 2 3 4 5 6 7 8 9 10 ");
  for (int i = 0; i < 10; i++) {
    mvaddch(3 + i, x_offset, 'A' + i);
    mvaddch(3 + i, x_offset+1, '|');
    mvaddch(3 + i, x_offset+22, '|');
  }
  
  for (int i = 0; i < 22; i++) {
    mvaddch(2, x_offset+i+1, '-');
    mvaddch(13, x_offset+i+1, '-');
  }
  
  attroff(COLOR_PAIR(TEXT_WHITE));
  
  // Nuke the side variable since now we want to see the ships on both sides
  side = PLAYER;
  
  for (int i = 0; i < 10; i++) {
    for (int j = 0; j < 10; j++) {
      int color = get_position_color(j, i);
      attron(COLOR_PAIR(color));
      mvprintw(i+3, x_offset + 2 + (j*2), "  ");
      attroff(COLOR_PAIR(color));
    }
  }
  
  for (int i = 0; i < 5; i++) {
    ships[i]->print_ship(x_offset, 16+i);
  refresh();
}

std::string board::get_move() {
  show_cursor = true;
  draw();
  
  while(true) {
    int key = getch();
    
Jake Feddersen's avatar
Jake Feddersen committed
    if (key == ' ') {
      if (!guesses[cursor_y][cursor_x]) break;
    }
    
    else if (key == KEY_UP) cursor_y--;
    else if (key == KEY_DOWN) cursor_y++;
    else if (key == KEY_LEFT) cursor_x--;
    else if (key == KEY_RIGHT) cursor_x++;
    
    else continue;
    
    cursor_x = std::min(9, cursor_x);
    cursor_x = std::max(0, cursor_x);
    
    cursor_y = std::min(9, cursor_y);
    cursor_y = std::max(0, cursor_y);
    
    draw();
  }
  
  std::string move;
  
  move.push_back('A' + cursor_y);
  move.push_back('1' + cursor_x);
  
  show_cursor = false;
  
  return move;
}