the possible boats function

master
Alec 4 years ago
commit c0a4bb93cd

@ -1,5 +1,6 @@
import {Component} from '../../lib/vues6.js'
import {Player} from '../module/util.js'
import {ShipType, isShipCell} from '../module/util.js'
import game_service from '../services/GameState.service.js'
/*
* This is the HTML/JavaScript for the game board component.
@ -20,7 +21,7 @@ import {Player} from '../module/util.js'
* Battleship grid is 14x14.
*/
const template = `
<div class="game-board-component" v-if="ready">
<div class="game-board-component" v-if="ready" @mouseleave="on_mouse_leave">
<div class="grid-container">
<div class="grid-row" v-for="(row,i) of rows">
<br> <span class="label">{{ i + 1 }}</span>
@ -28,6 +29,8 @@ const template = `
v-for="(cell,j) of row"
v-bind:render="cell.render"
@click="on_cell_click(i,j)"
@hover="on_cell_hover(i,j)"
v-bind:has_ghost_ship="is_ghost_cell(i,j)"
></app-game-cell>
</div>
<div class="column_labels">
@ -39,7 +42,7 @@ const template = `
export default class GameBoardComponent extends Component {
static get selector() { return 'app-game-board' }
static get template() { return template }
static get props() { return ['rows'] }
static get props() { return ['rows', 'is_placement_mode', 'ships_to_place'] }
/**
* If true, the grid is ready to be rendered. If false,
@ -49,24 +52,168 @@ export default class GameBoardComponent extends Component {
ready = false
/**
* Array of grid rows. Each element in this array is itself
* an array of grid cell values.
* @type {Array<Array<*>>}
* The various column labels to display.
* @type {string[]}
*/
// rows = []
column_labels = ["A", "B", "C", "D", "E", "F", "G", "H", "I"]
<<<<<<< Updated upstream
=======
>>>>>>> Stashed changes
/**
* Array of coordinates as [row_index, column_index] of cells which should
* show a ghost ship overlay.
* @type {[number, number][]}
*/
ship_ghost_cells = []
/**
* The ship currently being placed.
* @type {string}
*/
current_placement = ShipType.x3
/**
* Set to true when the shift key is pressed.
* @type {boolean}
*/
shift_pressed = false
/**
* Array of functions bound to event listeners. Used to
* remove event listeners on destroy.
* @type {function[]}
*/
bound_fns = []
async vue_on_create() {
this.ready = true
// We need to listen for keyup/keydown so we can tell when the user has
// pressed/released the shift key.
const keyup_fn = this.on_keyup.bind(this)
const keydown_fn = this.on_keydown.bind(this)
this.bound_fns.push(keyup_fn, keydown_fn)
window.addEventListener('keyup', keyup_fn)
window.addEventListener('keydown', keydown_fn)
}
async vue_on_destroy() {
// Remove the event listeners for the shift key
const [keyup_fn, keydown_fn] = this.bound_fns
window.removeEventListener('keyup', keyup_fn)
window.removeEventListener('keydown', keydown_fn)
}
<<<<<<< Updated upstream
on_cell_click(row_i, cell_i) {
alert(`${row_i} : ${cell_i}`)
if ( this.is_placement_mode && this.ships_to_place[0] ) {
// We should try to place a ship here
if ( this.ship_ghost_cells.length > 0 ) {
// We have some valid ship placement coordinates
const coord_one = this.ship_ghost_cells[0]
const coord_two = this.ship_ghost_cells.slice(-1)[0]
game_service.place_ship(this.ships_to_place[0], coord_one, coord_two)
this.$emit('shipplaced')
}
}
}
/**
* Called when the user hovers over a cell.
* When in placement mode, this updates the cells that show the ghost ship.
* @param {number} row_i
* @param {number} cell_i
*/
on_cell_hover(row_i, cell_i) {
if ( this.is_placement_mode ) {
// If we're in placement mode, determine if the cell the user is hovering
// over is a valid place to place the ship.
const ghost_cells = [[row_i, cell_i]]
const is_horizontal = this.shift_pressed
let is_valid_hover = true
if ( !is_horizontal ) {
const num_cells = game_service.get_ship_length(this.ships_to_place[0])
for ( let i = row_i + 1; i < row_i + num_cells; i += 1 ) {
ghost_cells.push([i, cell_i])
if ( i > 8 ) is_valid_hover = false
}
} else {
const num_cells = game_service.get_ship_length(this.ships_to_place[0])
for ( let i = cell_i + 1; i < cell_i + num_cells; i += 1 ) {
ghost_cells.push([row_i, i])
if ( i > 8 ) is_valid_hover = false
}
}
// Don't allow placing on existing ships
is_valid_hover = is_valid_hover && !ghost_cells.some(([row_i, col_i]) => this.is_ship_cell(row_i, col_i))
if ( is_valid_hover ) {
this.ship_ghost_cells = ghost_cells
} else {
this.ship_ghost_cells = []
}
} else {
this.ship_ghost_cells = []
}
}
/**
* Returns true if the cell at [row_index, column_index] is a ship.
* @param {number} row_i
* @param {number} col_i
* @return {boolean}
*/
is_ship_cell(row_i, col_i) {
return this.rows[row_i] && this.rows[row_i][col_i] && isShipCell(this.rows[row_i][col_i].render)
}
/**
* Hide the ghost ship when the mouse leaves the grid.
*/
on_mouse_leave() {
this.ship_ghost_cells = []
}
/**
* Returns a truthy value if the given cell is a ghost ship.
* @param {number} row_i
* @param {number} col_i
* @return {boolean}
*/
is_ghost_cell(row_i, col_i) {
return !!this.ship_ghost_cells.find(([cell_row_i, cell_col_i]) => cell_row_i === row_i && cell_col_i === col_i)
}
/**
* When keydown, check if shift was pressed. If so, update the placement.
* @param event
*/
on_keydown(event) {
if ( event.key === 'Shift' ) {
this.shift_pressed = true
if ( this.ship_ghost_cells.length > 0 ) {
this.on_cell_hover(this.ship_ghost_cells[0][0], this.ship_ghost_cells[0][1])
}
}
}
/**
* When keyup, check if shift was released. If so, update the placement.
* @param event
*/
on_keyup(event) {
if ( event.key === 'Shift' ) {
this.shift_pressed = false
if ( this.ship_ghost_cells.length > 0 ) {
this.on_cell_hover(this.ship_ghost_cells[0][0], this.ship_ghost_cells[0][1])
}
}
}
=======

@ -5,9 +5,11 @@ const template = `
<div
class="game-board-cell-component"
@click="on_click"
@mouseover="on_hover($event)"
@mouseleave="on_mouse_leave"
v-bind:class="{ disabled: render === GridCellState.Disabled, available: render === GridCellState.Available,
ship: render == GridCellState.Ship, damaged: render == GridCellState.Damaged, sunk: render == GridCellState.Sunk,
missed: render == GridCellState.Missed }"
missed: render == GridCellState.Missed, ghost: has_ghost_ship }"
>
</div>
@ -20,6 +22,7 @@ export default class GridCellComponent extends Component {
static get props() {
return [
'render',
'has_ghost_ship',
]
}
@ -29,4 +32,12 @@ export default class GridCellComponent extends Component {
on_click() {
this.$emit('click')
}
on_hover($event) {
this.$emit('hover', $event)
}
on_mouse_leave() {
this.$emit('hoverchange')
}
}

@ -13,15 +13,23 @@ export default class ScoreBoardComponent extends Component {
static get props() { return [] }
player_one_score = 0
player_two_score = 0
player_one_progress = 0
player_two_progress = 0
async vue_on_create() {
game_service.on_state_change(() => {
this.update()
})
this.update()
}
update() {
// here is where you should fetch the data from the game service and update variables on the class
this.player_one_score = game_service.get_player_score(Player.One)
this.player_two_score = game_service.get_player_score(Player.Two)
this.player_one_progress = game_service.get_progress(Player.One)
this.player_two_progress = game_service.get_progress(Player.Two)
}
}

@ -1,5 +1,5 @@
import {Component} from '../../lib/vues6.js'
import {GameState} from '../module/util.js'
import {GameState, ShipType} from '../module/util.js'
import game_service from '../services/GameState.service.js'
const template = `
@ -40,7 +40,12 @@ const template = `
<!-- Player's board -->
<div class="game-board">
<app-game-board v-bind:rows="player_rows"></app-game-board>
<app-game-board
v-bind:rows="player_rows"
v-bind:is_placement_mode="player_is_placing_ships"
v-bind:ships_to_place="ships_to_place"
@shipplaced="on_ship_placed"
></app-game-board>
</div>
</div>
</div>
@ -66,26 +71,73 @@ export default class TopLevelComponent extends Component {
*/
current_state = undefined
/**
* The opponent's grid data.
* @type {object[][]}
*/
opponent_rows = []
/**
* The player's grid data.
* @type {object[][]}
*/
player_rows = []
/**
* The current instructions to be shown to the user.
* @type {string}
*/
instructions = ''
/**
* True if the player should be able to place their ships.
* @type {boolean}
*/
player_is_placing_ships = false
/**
* If in placement mode, the ships that are yet to be placed.
* @type {ShipType[]}
*/
ships_to_place = []
async vue_on_create() {
console.log('game service', game_service)
this.current_state = game_service.get_game_state()
game_service.on_state_change((next_state) => {
// Called every time the game state is updated
game_service.on_state_change((next_state, was_refresh) => {
this.current_state = next_state
this.opponent_rows = game_service.get_current_opponent_state()
this.player_rows = game_service.get_current_player_state()
// add code for instructions
this.player_is_placing_ships = next_state === GameState.PlayerSetup
if ( !was_refresh && this.player_is_placing_ships ) {
// TODO replace with call to game state service
this.ships_to_place = [ShipType.x1, ShipType.x2, ShipType.x3]
}
// TODO add code for instructions
})
}
/**
* Set the number of boats.
* @param {number} n
*/
ship(n) {
game_service.set_n_boats(n)
game_service.advance_game_state()
}
/**
* Called when the current user has placed a ship.
*/
on_ship_placed() {
this.ships_to_place.shift()
if ( this.ships_to_place.length < 1 ) {
// We've placed all the ships. Let's move on.
game_service.advance_game_state()
}
}
}

@ -331,7 +331,7 @@ export class GameStateService {
}
this.current_turn_had_missile_attempt = false
this.game_state_change_listeners.forEach(fn => fn(this.current_state))
this.game_state_change_listeners.forEach(fn => fn(this.current_state, false))
}
/**
@ -439,6 +439,9 @@ export class GameStateService {
this.get_covered_cells(coords_one, coords_two).some(([row_i, col_i]) => {
this._set_cell_state(this.current_player, row_i, col_i, GridCellState.Ship)
})
// refresh the view
this._trigger_view_update()
}
/**
@ -644,6 +647,14 @@ export class GameStateService {
_get_cell_state(player, row_i, col_i) {
return this.player_x_game_board[player][row_i][col_i]
}
/**
* Force a view update without changing the current state.
* @private
*/
_trigger_view_update() {
this.game_state_change_listeners.forEach(fn => fn(this.current_state, true))
}
}
// Export a single instance, so it can be shared by all files

@ -67,6 +67,10 @@
background: #ffbbbb;
}
.game-board-cell-component.ghost {
background: #507090;
}
.column_labels {
display: flex;
margin-top: 5px;

Loading…
Cancel
Save