diff --git a/README.md b/README.md index c90f179..890d5ce 100644 --- a/README.md +++ b/README.md @@ -20,6 +20,17 @@ The easiest way to run this project is by creating a basic static web server usi This will start a web server on port 8000. You can then run the game by navigating to http://localhost:8000/ from a web browser. +## Documentation +You can [preview it here](https://htmlpreview.github.io/?https://raw.githubusercontent.com/EECS-448-Battleship/project-1/master/documentation/generated/index.html). Otherwise, it is generated by JSDoc in the `documentation/generated` directory. + +### Re-generating the documentation +To regenerate the docs, you need Node.js and the Yarn package manager installed. Then, just: + +```shell script +cd documentation +./generate.sh +``` + ## Contributors - Lucas Brakenridge - Javier Barea Lara diff --git a/documentation/.gitignore b/documentation/.gitignore new file mode 100644 index 0000000..3c3629e --- /dev/null +++ b/documentation/.gitignore @@ -0,0 +1 @@ +node_modules diff --git a/documentation/README.md b/documentation/README.md new file mode 100644 index 0000000..d90f392 --- /dev/null +++ b/documentation/README.md @@ -0,0 +1,51 @@ +# Battleship +## EECS 448 - Project 1 + +This is a basic battleship game created as our submission for project 1 for EECS 448 at the University of Kansas. + +## Structure Info +This project has been wired up to use Vue.js to help organize components of the game. + +These components are defined in files that end in the `.component.js` extension, and are located in the `src/components/` directory. + +The entry point for the project is the `index.html`. This file contains the basic logic for loading Vue, and adding the game board to the page. + +Obviously, we'll flesh out the look-and-feel as we go along. This is just a basic starter for now. + +## How to Run +The easiest way to run this project is by creating a basic static web server using Python. This is super simple: + +1. Open a terminal or command prompt to the root of this project (i.e. the directory this file is in). +2. Start the server: `python -m http.server` + +This will start a web server on port 8000. You can then run the game by navigating to http://localhost:8000/ from a web browser. + +## Documentation +You can [preview it here](https://htmlpreview.github.io/?https://raw.githubusercontent.com/EECS-448-Battleship/project-1/master/documentation/generated/index.html). Otherwise, it is generated by JSDoc in the `documentation/generated` directory. + +### Re-generating the documentation +To regenerate the docs, you need Node.js and the Yarn package manager installed. Then, just: + +```shell script +cd documentation +./generate.sh +``` + +## Third-Party Libraries +The files in the `lib/` are external libraries used in this project. + +- Vue.js + - A front-end framework. Used under the terms of the MIT license. + - https://github.com/vuejs/vue +- VuES6.js + - A kind-of crappy loader for defining Vue components using ES6 classes. + - Also used under the terms of the MIT license. + - https://code.garrettmills.dev/garrettmills/vues6 +- Sound effects obtained from https://www.zapsplat.com and used with permission. + +## Contributors +- Lucas Brakenridge +- Javier Barea Lara +- Garrett Mills +- Evan Powell +- Alec Horlick-Mills diff --git a/documentation/generate.sh b/documentation/generate.sh new file mode 100755 index 0000000..8b99aab --- /dev/null +++ b/documentation/generate.sh @@ -0,0 +1,3 @@ +#!/bin/sh +yarn install +./node_modules/.bin/jsdoc --destination ./generated --readme ./README.md --recurse ../src diff --git a/documentation/generated/GameBoardComponent.html b/documentation/generated/GameBoardComponent.html new file mode 100644 index 0000000..3817627 --- /dev/null +++ b/documentation/generated/GameBoardComponent.html @@ -0,0 +1,1866 @@ + + + + + JSDoc: Class: GameBoardComponent + + + + + + + + + + +
+ +

Class: GameBoardComponent

+ + + + + + +
+ +
+ +

GameBoardComponent()

+ +
A component which represents a single, programmable game board.
+ + +
+ +
+
+ + + + +

Constructor

+ + + +

new GameBoardComponent()

+ + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + +
+ + +

Extends

+ + + + +
    +
  • Component
  • +
+ + + + + + + + + + + + + + + +

Members

+ + + +

bound_fns :Array.<function()>

+ + + + +
+ Array of functions bound to event listeners. Used to +remove event listeners on destroy. +
+ + + +
Type:
+
    +
  • + +Array.<function()> + + +
  • +
+ + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + +

column_labels :Array.<string>

+ + + + +
+ The various column labels to display. +
+ + + +
Type:
+
    +
  • + +Array.<string> + + +
  • +
+ + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + +

current_placement :string

+ + + + +
+ The ship currently being placed. +
+ + + +
Type:
+
    +
  • + +string + + +
  • +
+ + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + +

ready :boolean

+ + + + +
+ If true, the grid is ready to be rendered. If false, +the grid will be hidden. +
+ + + +
Type:
+
    +
  • + +boolean + + +
  • +
+ + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + +

shift_pressed :boolean

+ + + + +
+ Set to true when the shift key is pressed. +
+ + + +
Type:
+
    +
  • + +boolean + + +
  • +
+ + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + +

ship_ghost_cells :Array.<number>

+ + + + +
+ Array of coordinates as [row_index, column_index] of cells which should +show a ghost ship overlay. +
+ + + +
Type:
+
    +
  • + +Array.<number> + + +
  • +
+ + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + +

Methods

+ + + + + + + +

is_ghost_cell(row_i, col_i) → {boolean}

+ + + + + + +
+ Returns a truthy value if the given cell is a ghost ship. +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
row_i + + +number + + + +
col_i + + +number + + + +
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + + + +
+
+ Type +
+
+ +boolean + + +
+
+ + + + + + + + + + + + + +

is_ship_cell(row_i, col_i) → {boolean}

+ + + + + + +
+ Returns true if the cell at [row_index, column_index] is a ship. +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
row_i + + +number + + + +
col_i + + +number + + + +
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + + + +
+
+ Type +
+
+ +boolean + + +
+
+ + + + + + + + + + + + + +

on_cell_click(row_i, cell_i)

+ + + + + + +
+ Called when a user clicks a cell. If in placement mode, will attempt to place +a ship. If in missile mode, will attempt to fire a missile. +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
row_i + + +number + + + + the index of the row
cell_i + + +number + + + + the index of the cell
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

on_cell_hover(row_i, cell_i)

+ + + + + + +
+ Called when the user hovers over a cell. +When in placement mode, this updates the cells that show the ghost ship. +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
row_i + + +number + + + +
cell_i + + +number + + + +
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

on_keydown(event)

+ + + + + + +
+ When keydown, check if shift was pressed. If so, update the placement. +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
event + +
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

on_keyup(event)

+ + + + + + +
+ When keyup, check if shift was released. If so, update the placement. +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
event + +
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

on_mouse_leave()

+ + + + + + +
+ Hide the ghost ship when the mouse leaves the grid. +
+ + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) vue_on_create() → {Promise.<void>}

+ + + + + + +
+ Called when the component is initialized. +
+ + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + + + +
+
+ Type +
+
+ +Promise.<void> + + +
+
+ + + + + + + + + + + + + +

(async) vue_on_destroy() → {Promise.<void>}

+ + + + + + +
+ Called when the component is destroyed. +
+ + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + + + +
+
+ Type +
+
+ +Promise.<void> + + +
+
+ + + + + + + + + + + + + +
+ +
+ + + + +
+ + + +
+ + + + + + + \ No newline at end of file diff --git a/documentation/generated/GameStateService.html b/documentation/generated/GameStateService.html new file mode 100644 index 0000000..0ce2857 --- /dev/null +++ b/documentation/generated/GameStateService.html @@ -0,0 +1,3111 @@ + + + + + JSDoc: Class: GameStateService + + + + + + + + + + +
+ +

Class: GameStateService

+ + + + + + +
+ +
+ +

GameStateService()

+ +
Singleton service for managing the state of the game.
+ + +
+ +
+
+ + + + +

Constructor

+ + + +

new GameStateService()

+ + + + + + +
+ Construct a new game service. Initialize any internal states. +
+ + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + +
+ + + + + + +

Classes

+ +
+
GameStateService
+
+
+ + + + + + + + + +

Members

+ + + +

current_turn_had_missile_attempt :boolean

+ + + + +
+ True if, during the current turn, the user has tried to fire a missile. +
+ + + +
Type:
+
    +
  • + +boolean + + +
  • +
+ + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + +

game_state_change_listeners :Array.<function()>

+ + + + +
+ Array of functions that are called when the game state changes. +
+ + + +
Type:
+
    +
  • + +Array.<function()> + + +
  • +
+ + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + +

post_player_change_state :undefined|string

+ + + + +
+ If the current state is the PromptPlayerChange, then this is +the state that we should move to next. +
+ + + +
Type:
+
    +
  • + +undefined +| + +string + + +
  • +
+ + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + +

Methods

+ + + + + + + +

advance_game_state()

+ + + + + + +
+ responsible for advancing the game state +will be consisting of +
+ + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

attempt_missile_fire(coords) → {boolean}

+ + + + + + +
+ Attempt to fire a missile at the current opponent at the given coordinates. +The coordinates should be an array of [row_index, column_index] where the missile should fire. +Returns true if the missile hit an undamaged cell of a ship. +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
coords + + +Array.<number> + + + +
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + + + +
+
+ Type +
+
+ +boolean + + +
+
+ + + + + + +
Example
+ +
If I want to fire a missile at row 5 column 7, then:
+game_service.attempt_missile_fire([5, 7])
+ + + + + + + + + +

get_covered_cells(coords_one, coords_two) → {Array.<Array.<number>>}

+ + + + + + +
+ Get an array of cell coordinates that are covered by a ship that spans +the given coordinates. +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
coords_one + + +Array.<number> + + + +
coords_two + + +Array.<number> + + + +
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + + + +
+
+ Type +
+
+ +Array.<Array.<number>> + + +
+
+ + + + + + +
Example
+ +
If a ship goes from row 1 column 1 to row 4 column 1, then I can get
+the coordinates of all cells covered by that ship using:
+game_service.get_covered_cells([1,1], [4,1])
+Which would return [[1,1], [2,1], [3,1], [4,1]].
+ + + + + + + + + +

get_current_opponent() → {string}

+ + + + + + +
+ Get the player who is NOT the focus of the current game state. +
+ + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + + + +
+
+ Type +
+
+ +string + + +
+
+ + + + + + + + + + + + + +

get_current_opponent_state() → {Array.<Array.<object>>}

+ + + + + + +
+ Get the state of the current opponent's board, as it should appear to the +current player. Note that the current player cannot see "ship" spaces, only +available, damaged, missed, or sunk. +
+ + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + + + +
+
+ Type +
+
+ +Array.<Array.<object>> + + +
+
+ + + + + + + + + + + + + +

get_current_player() → {string}

+ + + + + + +
+ Get the player who is the focus of the current game state. +
+ + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + + + +
+
+ Type +
+
+ +string + + +
+
+ + + + + + + + + + + + + +

get_current_player_state() → {Array.<Array.<object>>}

+ + + + + + +
+ Get the state of the current player's board, as it should appear to them. +
+ + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + + + +
+
+ Type +
+
+ +Array.<Array.<object>> + + +
+
+ + + + + + + + + + + + + +

get_dimensions() → {Array.<number>}

+ + + + + + +
+ Get the dimensions of the board as [rows, cols]. +
+ + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + + + +
+
+ Type +
+
+ +Array.<number> + + +
+
+ + + + + + +
Example
+ +
const [n_rows, n_cols] = game_service.get_dimensions()
+ + + + + + + + + +

get_game_state() → {string}

+ + + + + + +
+ Get the current game state. +
+ + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + + + +
+
+ Type +
+
+ +string + + +
+
+ + + + + + + + + + + + + +

get_other_player(player) → {string}

+ + + + + + +
+ Returns the other player. +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
player + + +string + + + +
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + + + +
+
+ Type +
+
+ +string + + +
+
+ + + + + + + + + + + + + +

get_player_display(player) → {string}

+ + + + + + +
+ Given a Player type, return the display value of that player. +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
player + + +string + + + +
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + + + +
+
+ Type +
+
+ +string + + +
+
+ + + + + + + + + + + + + +

get_player_victory_state() → {Array.<Array.<Array.<object>>>}

+ + + + + + +
+ Get the states that should be shown on the victory screen. +First element is the winner's state, second element is the loser's state. +
+ + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + + + +
+
+ Type +
+
+ +Array.<Array.<Array.<object>>> + + +
+
+ + + + + + + + + + + + + +

get_possible_boats() → {Array.<string>}

+ + + + + + +
+ Given the number of boats set by the player (n_boats), return an array +of possible ShipTypes. +
+ + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + + + +
+
+ Type +
+
+ +Array.<string> + + +
+
+ + + + + + + + + + + + + +

get_ship_cells(player) → {Array.<number>}

+ + + + + + +
+ Get the coordinates of all cells that have ships in them, for the given player. +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
player + + +string + + + +
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + + + +
+
+ Type +
+
+ +Array.<number> + + +
+
+ + + + + + + + + + + + + +

get_ship_entities(player) → {Array.<object>}

+ + + + + + +
+ Get an array of ship entities for the given player. +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
player + + +string + + + +
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + + + +
+
+ Type +
+
+ +Array.<object> + + +
+
+ + + + + + + + + + + + + +

get_ship_length(ship_type) → {number}

+ + + + + + +
+ Get the number of cells the given ship type should occupy. +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
ship_type + + +string + + + +
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + + + +
+
+ Type +
+
+ +number + + +
+
+ + + + + + + + + + + + + +

get_winner() → {string|undefined}

+ + + + + + +
+ If there is a winner, this will return the Player that won. +If no winner has been decided yet, will return undefined. +
+ + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + + + +
+
+ Type +
+
+ +string +| + +undefined + + +
+
+ + + + + + + + + + + + + +

on_state_change(handler)

+ + + + + + +
+ Register a handler to be called when the game state changes. +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
handler + + +function + + + +
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

place_ship(ship_type, coords_one, coords_two)

+ + + + + + +
+ Attempt to place a ship of the given type at the given coordinates. +Throws an InvalidShipPlacementError if the coordinates are invalid. +Coordinates should be [row_index, column_index] of either end of the ship. +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
ship_type + + +string + + + +
coords_one + + +Array.<number> + + + +
coords_two + + +Array.<number> + + + +
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + +
Example
+ +
If I am placing a 1x3 ship and I want it to be in row 3 column 2 horizontal
+to row 3 column 4, then I would call:
+game_service.place_ship(ShipType.x3, [3,2], [3,4])
+ + + + + + + + + +

validate_coordinates(ship_type, coords_one, coords_two)

+ + + + + + +
+ Validate the given coordinates for the given ship type. +Throws an InvalidShipPlacementError if the coordinates are invalid. +Coordinates should be [row_index, column_index] of either end of the ship. +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
ship_type + + +string + + + +
coords_one + + +Array.<number> + + + +
coords_two + + +Array.<number> + + + +
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + +
Example
+ +
If I am placing a 1x3 ship and I want it to be in row 3 column 2 horizontal
+to row 3 column 4, then I would call:
+game_service.validate_coordinates(ShipType.x3, [3,2], [3,4])
+ + + + + + + + + +
+ +
+ + + + +
+ + + +
+ + + + + + + \ No newline at end of file diff --git a/documentation/generated/GridCellComponent.html b/documentation/generated/GridCellComponent.html new file mode 100644 index 0000000..d15d757 --- /dev/null +++ b/documentation/generated/GridCellComponent.html @@ -0,0 +1,621 @@ + + + + + JSDoc: Class: GridCellComponent + + + + + + + + + + +
+ +

Class: GridCellComponent

+ + + + + + +
+ +
+ +

GridCellComponent()

+ +
A component which represents a single, programmable grid cell.
+ + +
+ +
+
+ + + + +

Constructor

+ + + +

new GridCellComponent()

+ + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + +
+ + +

Extends

+ + + + +
    +
  • Component
  • +
+ + + + + + + + + + + + + + + +

Members

+ + + +

(static) props

+ + + + +
+ Properties that can be passed into this component. +
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + +

GridCellState

+ + + + +
+ Make the "GridCellState" enum available in the template. +
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + +

Methods

+ + + + + + + +

on_click()

+ + + + + + +
+ Fire a click event. +
+ + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

on_hover($event)

+ + + + + + +
+ Fire a hover event. +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
$event + +
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

on_mouse_leave()

+ + + + + + +
+ Fire a "hoverchange" event. +
+ + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + +
+ + + +
+ + + + + + + \ No newline at end of file diff --git a/documentation/generated/ScoreBoardComponent.html b/documentation/generated/ScoreBoardComponent.html new file mode 100644 index 0000000..3eda487 --- /dev/null +++ b/documentation/generated/ScoreBoardComponent.html @@ -0,0 +1,821 @@ + + + + + JSDoc: Class: ScoreBoardComponent + + + + + + + + + + +
+ +

Class: ScoreBoardComponent

+ + + + + + +
+ +
+ +

ScoreBoardComponent()

+ +
A component which represents the programmable scoreboard.
+ + +
+ +
+
+ + + + +

Constructor

+ + + +

new ScoreBoardComponent()

+ + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + +
+ + +

Extends

+ + + + +
    +
  • Component
  • +
+ + + + + + + + + + + + + + + +

Members

+ + + +

current_player :string|undefined

+ + + + +
+ The current player. +
+ + + +
Type:
+
    +
  • + +string +| + +undefined + + +
  • +
+ + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + +

player_one_progress :number

+ + + + +
+ The progress of player one, as a decimal. +
+ + + +
Type:
+
    +
  • + +number + + +
  • +
+ + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + +

player_one_score :number

+ + + + +
+ The score of player one. +
+ + + +
Type:
+
    +
  • + +number + + +
  • +
+ + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + +

player_two_progress :number

+ + + + +
+ The progress of player two, as a decimal. +
+ + + +
Type:
+
    +
  • + +number + + +
  • +
+ + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + +

player_two_score :number

+ + + + +
+ The score of player two. +
+ + + +
Type:
+
    +
  • + +number + + +
  • +
+ + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + +

winning_player :string|undefined

+ + + + +
+ The winning player. +
+ + + +
Type:
+
    +
  • + +string +| + +undefined + + +
  • +
+ + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + +

Methods

+ + + + + + + +

update()

+ + + + + + +
+ Fetch new data from the game service. +
+ + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) vue_on_create() → {Promise.<void>}

+ + + + + + +
+ Called when the component is initialized. +
+ + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + + + +
+
+ Type +
+
+ +Promise.<void> + + +
+
+ + + + + + + + + + + + + +
+ +
+ + + + +
+ + + +
+ + + + + + + \ No newline at end of file diff --git a/documentation/generated/TopLevelComponent.html b/documentation/generated/TopLevelComponent.html new file mode 100644 index 0000000..87b2539 --- /dev/null +++ b/documentation/generated/TopLevelComponent.html @@ -0,0 +1,1491 @@ + + + + + JSDoc: Class: TopLevelComponent + + + + + + + + + + +
+ +

Class: TopLevelComponent

+ + + + + + +
+ +
+ +

TopLevelComponent()

+ +
Top-level component which manages the display of the entire game.
+ + +
+ +
+
+ + + + +

Constructor

+ + + +

new TopLevelComponent()

+ + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + +
+ + +

Extends

+ + + + +
    +
  • Component
  • +
+ + + + + + + + + + + + + + + +

Members

+ + + +

current_opponent_display :string

+ + + + +
+ The display name of the current opponent. +
+ + + +
Type:
+
    +
  • + +string + + +
  • +
+ + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + +

current_player_display :string

+ + + + +
+ The display name of the current player. +
+ + + +
Type:
+
    +
  • + +string + + +
  • +
+ + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + +

current_state :GameState|undefined

+ + + + +
+ The current game state. +
+ + + +
Type:
+
    +
  • + +GameState +| + +undefined + + +
  • +
+ + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + +

GameState :object

+ + + + +
+ Make the game state accessible w/in the template. +
+ + + +
Type:
+
    +
  • + +object + + +
  • +
+ + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + +

instructions :string

+ + + + +
+ The current instructions to be shown to the user. +
+ + + +
Type:
+
    +
  • + +string + + +
  • +
+ + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + +

opponent_rows :Array.<Array.<object>>

+ + + + +
+ The opponent's grid data. +
+ + + +
Type:
+
    +
  • + +Array.<Array.<object>> + + +
  • +
+ + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + +

player_is_firing_missiles :boolean

+ + + + +
+ True if the player should be able to fire missiles at their opponent. +
+ + + +
Type:
+
    +
  • + +boolean + + +
  • +
+ + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + +

player_is_placing_ships :boolean

+ + + + +
+ True if the player should be able to place their ships. +
+ + + +
Type:
+
    +
  • + +boolean + + +
  • +
+ + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + +

player_rows :Array.<Array.<object>>

+ + + + +
+ The player's grid data. +
+ + + +
Type:
+
    +
  • + +Array.<Array.<object>> + + +
  • +
+ + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + +

ships_to_place :Array.<ShipType>

+ + + + +
+ If in placement mode, the ships that are yet to be placed. +
+ + + +
Type:
+
    +
  • + +Array.<ShipType> + + +
  • +
+ + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + +

Methods

+ + + + + + + +

confirm_player_change()

+ + + + + + +
+ Called when the player has confirmed the player change. +
+ + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) on_missile_fired(row_index, column_index)

+ + + + + + +
+ Called when the player attempts to fire a missile. +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
row_index + + +number + + + +
column_index + + +number + + + +
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

on_ship_placed()

+ + + + + + +
+ Called when the current user has placed a ship. +
+ + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

ship(n)

+ + + + + + +
+ Set the number of boats. +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
n + + +number + + + +
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) vue_on_create() → {Promise.<void>}

+ + + + + + +
+ Called when the component is initialized. +
+ + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + + + +
+
+ Type +
+
+ +Promise.<void> + + +
+
+ + + + + + + + + + + + + +
+ +
+ + + + +
+ + + +
+ + + + + + + \ No newline at end of file diff --git a/documentation/generated/components_GameBoard.component.js.html b/documentation/generated/components_GameBoard.component.js.html new file mode 100644 index 0000000..019a478 --- /dev/null +++ b/documentation/generated/components_GameBoard.component.js.html @@ -0,0 +1,287 @@ + + + + + JSDoc: Source: components/GameBoard.component.js + + + + + + + + + + +
+ +

Source: components/GameBoard.component.js

+ + + + + + +
+
+
import {Component} from '../../lib/vues6.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.
+ * The "template" variable at the top defines the HTML for this component. It can contain references
+ * to methods and properties on the "GameBoardComponent" class shown below.
+ *
+ * For example, the "greeting" property is referenced in the template as "{{ greeting }}". When
+ * the page loads, this will be replaced by the value of the "greeting" property.
+ *
+ * The class below manages the logic referenced by the template. Then, we can use the component
+ * in the application by creating an HTML tag with the value of the "selector()" getter.
+ *
+ * In this case, that's the <app-game-board></app-game-board> tag in index.html.
+ *
+ * We can also use components w/in components, to keep code clean. For example, we could have
+ * a battleship component that we reference inside this game board component.
+ *
+ * Battleship grid is 14x14.
+ */
+const template  = `
+<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>
+            <app-game-cell
+                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">
+             <div class="label" v-for="(label,i) of column_labels">{{ label }}</div>
+         </div>
+    </div>
+</div>
+`
+
+/**
+ * A component which represents a single, programmable game board.
+ * @extends Component
+ */
+class GameBoardComponent extends Component {
+    static get selector() { return 'app-game-board' }
+    static get template() { return template }
+    static get props() { return ['rows', 'is_placement_mode', 'ships_to_place', 'is_missile_mode'] }
+
+    /**
+     * If true, the grid is ready to be rendered. If false,
+     * the grid will be hidden.
+     * @type {boolean}
+     */
+    ready = false
+
+    /**
+     * The various column labels to display.
+     * @type {string[]}
+     */
+    column_labels = ["A", "B", "C", "D", "E", "F", "G", "H", "I"]
+
+    /**
+     * Array of coordinates as [row_index, column_index] of cells which should
+     * show a ghost ship overlay.
+     * @type {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 = []
+
+    /**
+     * Called when the component is initialized.
+     * @return {Promise<void>}
+     */
+    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)
+    }
+
+    /**
+     * Called when the component is destroyed.
+     * @return {Promise<void>}
+     */
+    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)
+    }
+
+    /**
+     * Called when a user clicks a cell. If in placement mode, will attempt to place
+     * a ship. If in missile mode, will attempt to fire a missile.
+     * @param {number} row_i - the index of the row
+     * @param {number} cell_i - the index of the cell
+     */
+    on_cell_click(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')
+            }
+        } else if ( this.is_missile_mode ) {
+            this.$emit('missilefired', [row_i, cell_i])
+        }
+    }
+
+    /**
+     * 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])
+            }
+        }
+    }
+}
+
+export default GameBoardComponent
+
+
+
+ + + + +
+ + + +
+ + + + + + + diff --git a/documentation/generated/components_GridCell.component.js.html b/documentation/generated/components_GridCell.component.js.html new file mode 100644 index 0000000..bd7a1fe --- /dev/null +++ b/documentation/generated/components_GridCell.component.js.html @@ -0,0 +1,111 @@ + + + + + JSDoc: Source: components/GridCell.component.js + + + + + + + + + + +
+ +

Source: components/GridCell.component.js

+ + + + + + +
+
+
import {Component} from '../../lib/vues6.js'
+import {GridCellState} from '../module/util.js'
+
+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, ghost: has_ghost_ship }"
+>
+
+</div>
+`
+
+/**
+ * A component which represents a single, programmable grid cell.
+ * @extends Component
+ */
+class GridCellComponent extends Component {
+    static get selector() { return 'app-game-cell' }
+    static get template() { return template }
+
+    /** Properties that can be passed into this component. */
+    static get props() {
+        return [
+            'render',
+            'has_ghost_ship',
+        ]
+    }
+
+    /** Make the "GridCellState" enum available in the template. */
+    GridCellState = GridCellState
+
+    /**
+     * Fire a click event.
+     */
+    on_click() {
+        this.$emit('click')
+    }
+
+    /**
+     * Fire a hover event.
+     * @param $event
+     */
+    on_hover($event) {
+        this.$emit('hover', $event)
+    }
+
+    /**
+     * Fire a "hoverchange" event.
+     */
+    on_mouse_leave() {
+        this.$emit('hoverchange')
+    }
+}
+
+export default GridCellComponent
+
+
+
+ + + + +
+ + + +
+ + + + + + + diff --git a/documentation/generated/components_ScoreBoard.component.js.html b/documentation/generated/components_ScoreBoard.component.js.html new file mode 100644 index 0000000..402a259 --- /dev/null +++ b/documentation/generated/components_ScoreBoard.component.js.html @@ -0,0 +1,160 @@ + + + + + JSDoc: Source: components/ScoreBoard.component.js + + + + + + + + + + +
+ +

Source: components/ScoreBoard.component.js

+ + + + + + +
+
+
import {Component} from '../../lib/vues6.js'
+import game_service from '../services/GameState.service.js'
+import {Player, GameState} from '../module/util.js'
+
+const template = `
+<div class="app-scoreboard-component">
+    <table class="scoreboard_table" style="width:50%">
+        <tr class="scoreboard_rows">
+            <th class="scoreboard_table_empty"></th>
+            <th class="scoreboard_table_header" colspan="3">scoreboard</th>
+        </tr>
+        <tr class="scoreboard_header_scoreProgress">
+            <th class="scoreboard_table_empty"></th>
+            <td class="scoreboard_data">score</td>
+            <td class="scoreboard_data">progress</td>
+        </tr>
+        <tr class="scoreboard_rows_score&progress">
+            <td class="scoreboard_player">{{ current_player === Player.One ? '➜ ' : '' }}Player 1{{ winning_player === Player.One ? ' ★' : '' }}</td>
+            <td class="scoreboard_data">{{player_one_score}}</td>
+            <td class="scoreboard_data">{{player_one_progress * 100}}%</td>
+        </tr>
+        <tr class="scoreboard_lastRow">
+            <td class="scoreboard_player">{{ current_player === Player.Two ? '➜ ' : '' }}Player 2{{ winning_player === Player.Two ? ' ★' : '' }}</td>
+            <td class="scoreboard_data">{{player_two_score}}</td>
+            <td class="scoreboard_data">{{player_two_progress * 100}}%</td>
+        </tr>
+    </table>
+</div>
+`
+
+/**
+ * A component which represents the programmable scoreboard.
+ * @extends Component
+ */
+class ScoreBoardComponent extends Component {
+    static get selector() { return 'app-scoreboard' }
+    static get template() { return template }
+    static get props() { return [] }
+
+    /**
+     * The score of player one.
+     * @type {number}
+     */
+    player_one_score = 0
+
+    /**
+     * The score of player two.
+     * @type {number}
+     */
+    player_two_score = 0
+
+    /**
+     * The progress of player one, as a decimal.
+     * @type {number}
+     */
+    player_one_progress = 0
+
+    /**
+     * The progress of player two, as a decimal.
+     * @type {number}
+     */
+    player_two_progress = 0
+
+    /**
+     * The current player.
+     * @type {string|undefined}
+     */
+    current_player = undefined
+
+    /**
+     * The winning player.
+     * @type {string|undefined}
+     */
+    winning_player = undefined
+
+    Player = Player
+
+    /**
+     * Called when the component is initialized.
+     * @return {Promise<void>}
+     */
+    async vue_on_create() {
+        game_service.on_state_change(() => {
+            this.update()
+        })
+
+        this.update()
+    }
+
+    /**
+     * Fetch new data from the game service.
+     */
+    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)
+
+        if ( game_service.get_game_state() !== GameState.PlayerVictory )
+            this.current_player = game_service.get_current_player()
+        else {
+            this.current_player = undefined
+            this.winning_player = game_service.get_current_player()
+        }
+    }
+}
+
+export default ScoreBoardComponent
+
+
+
+ + + + +
+ + + +
+ + + + + + + diff --git a/documentation/generated/components_TopLevel.component.js.html b/documentation/generated/components_TopLevel.component.js.html new file mode 100644 index 0000000..65dbefd --- /dev/null +++ b/documentation/generated/components_TopLevel.component.js.html @@ -0,0 +1,283 @@ + + + + + JSDoc: Source: components/TopLevel.component.js + + + + + + + + + + +
+ +

Source: components/TopLevel.component.js

+ + + + + + +
+
+
import {Component} from '../../lib/vues6.js'
+import {GameState, ShipType} from '../module/util.js'
+import {instructions} from '../module/lang.js'
+import game_service from '../services/GameState.service.js'
+import {GameSounds} from '../module/sounds.js'
+
+const template = `
+<div class="top-level-container">
+    <div class="top-level-component">
+        <div v-if="current_state === GameState.ChoosingNumberOfShips" class="game-choose-ships-container">
+            <span v-if="instructions">{{ instructions }}</span>
+            <div style="margin-top: 30px;">
+                <button @click="ship(1)" class="shipBtn">1 ship</button>
+                <button @click="ship(2)" class="shipBtn">2 ships</button>
+                <button @click="ship(3)" class="shipBtn">3 ships</button>
+                <button @click="ship(4)" class="shipBtn">4 ships</button>
+                <button @click="ship(5)" class="shipBtn">5 ships</button>
+            </div>
+        </div>
+        <div v-if="current_state === GameState.PromptPlayerChange" class="game-player-change-container">
+            It is now {{ current_player_display }}'s turn!
+            <button @click="confirm_player_change" class="playerBtn">Continue</button>
+        </div>
+        <div
+            v-if="current_state !== GameState.ChoosingNumberOfShips && current_state !== GameState.PromptPlayerChange && instructions"
+            class="instructions"
+        >
+            {{ instructions.replace('{player}', current_player_display) }}
+        </div>
+        <div
+            v-if="current_state !== GameState.ChoosingNumberOfShips
+                    && current_state !== GameState.PromptPlayerChange
+                    && current_state !== GameState.PlayerVictory"
+            class="game-boards-container"
+        >
+            <!-- Opponent's board -->
+            <div class="game-board">
+                <app-game-board
+                    v-bind:rows="opponent_rows"
+                    v-bind:is_missile_mode="player_is_firing_missiles"
+                    @missilefired="on_missile_fired"
+                ></app-game-board>
+                <div class="fleet-label">Opposing fleet</div>
+            </div>
+    
+            <!-- Player's board -->
+            <div class="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 class="fleet-label">Your fleet</div>
+            </div>
+        </div>
+        <div
+            v-if="current_state === GameState.PlayerVictory"
+            class="game-boards-container"
+        >
+            <!-- Winner's board -->
+            <div class="game-board">
+                <app-game-board
+                    v-bind:rows="player_rows"
+                ></app-game-board>
+                <div class="fleet-label">{{ current_player_display }}'s fleet (winner)</div>
+            </div>
+    
+            <!-- Loser's board -->
+            <div class="game-board">
+                <app-game-board
+                    v-bind:rows="opponent_rows"
+                ></app-game-board>
+                <div class="fleet-label">{{ current_opponent_display }}'s fleet</div>
+            </div>
+        </div>
+    </div>
+    <div class="scoreboard-container">
+        <app-scoreboard></app-scoreboard>
+    </div>
+</div>
+`
+
+/**
+ * Top-level component which manages the display of the entire game.
+ * @extends Component
+ */
+class TopLevelComponent extends Component {
+    static get selector() { return 'app-top-level' }
+    static get template() { return template }
+    static get props() { return [] }
+
+    /**
+     * Make the game state accessible w/in the template.
+     * @type {object}
+     */
+    GameState = GameState
+
+    /**
+     * The current game state.
+     * @type {GameState|undefined}
+     */
+    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 = instructions[GameState.ChoosingNumberOfShips]
+
+    /**
+     * True if the player should be able to place their ships.
+     * @type {boolean}
+     */
+    player_is_placing_ships = false
+
+    /**
+     * True if the player should be able to fire missiles at their opponent.
+     * @type {boolean}
+     */
+    player_is_firing_missiles = false
+
+    /**
+     * If in placement mode, the ships that are yet to be placed.
+     * @type {ShipType[]}
+     */
+    ships_to_place = []
+
+    /**
+     * The display name of the current player.
+     * @type {string}
+     */
+    current_player_display = ''
+
+    /**
+     * The display name of the current opponent.
+     * @type {string}
+     */
+    current_opponent_display = ''
+
+    /**
+     * Called when the component is initialized.
+     * @return {Promise<void>}
+     */
+    async vue_on_create() {
+        this.current_state = game_service.get_game_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()
+            this.current_player_display = game_service.get_player_display(game_service.get_current_player())
+            this.current_opponent_display = game_service.get_player_display(game_service.get_current_opponent())
+
+            this.player_is_placing_ships = next_state === GameState.PlayerSetup
+            this.player_is_firing_missiles = next_state === GameState.PlayerTurn
+            if ( !was_refresh && this.player_is_placing_ships ) {
+                this.ships_to_place = game_service.get_possible_boats()
+            }
+
+            if ( next_state === GameState.PlayerVictory ) {
+                const [victor_state, loser_state] = game_service.get_player_victory_state()
+                this.player_rows = victor_state
+                this.opponent_rows = loser_state
+            }
+
+            this.instructions = instructions[this.current_state]
+        })
+    }
+
+    /**
+     * 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()
+        }
+    }
+
+    /**
+     * Called when the player attempts to fire a missile.
+     * @param {number} row_index
+     * @param {number} column_index
+     */
+    async on_missile_fired([row_index, column_index]) {
+        if ( this.player_is_firing_missiles ) {
+            await GameSounds.Fire.play()
+            const success = game_service.attempt_missile_fire([row_index, column_index])
+
+            if ( success ) await GameSounds.Hit.play()
+            else await GameSounds.Miss.play()
+
+            // Give the user time to see whether they hit or not
+            setTimeout(() => {
+                game_service.advance_game_state()
+            }, 2000)
+        }
+    }
+
+    /**
+     * Called when the player has confirmed the player change.
+     */
+    confirm_player_change() {
+        game_service.advance_game_state()
+    }
+}
+
+export default TopLevelComponent
+
+
+
+ + + + +
+ + + +
+ + + + + + + diff --git a/documentation/generated/fonts/OpenSans-Bold-webfont.eot b/documentation/generated/fonts/OpenSans-Bold-webfont.eot new file mode 100644 index 0000000..5d20d91 Binary files /dev/null and b/documentation/generated/fonts/OpenSans-Bold-webfont.eot differ diff --git a/documentation/generated/fonts/OpenSans-Bold-webfont.svg b/documentation/generated/fonts/OpenSans-Bold-webfont.svg new file mode 100644 index 0000000..3ed7be4 --- /dev/null +++ b/documentation/generated/fonts/OpenSans-Bold-webfont.svg @@ -0,0 +1,1830 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/documentation/generated/fonts/OpenSans-Bold-webfont.woff b/documentation/generated/fonts/OpenSans-Bold-webfont.woff new file mode 100644 index 0000000..1205787 Binary files /dev/null and b/documentation/generated/fonts/OpenSans-Bold-webfont.woff differ diff --git a/documentation/generated/fonts/OpenSans-BoldItalic-webfont.eot b/documentation/generated/fonts/OpenSans-BoldItalic-webfont.eot new file mode 100644 index 0000000..1f639a1 Binary files /dev/null and b/documentation/generated/fonts/OpenSans-BoldItalic-webfont.eot differ diff --git a/documentation/generated/fonts/OpenSans-BoldItalic-webfont.svg b/documentation/generated/fonts/OpenSans-BoldItalic-webfont.svg new file mode 100644 index 0000000..6a2607b --- /dev/null +++ b/documentation/generated/fonts/OpenSans-BoldItalic-webfont.svg @@ -0,0 +1,1830 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/documentation/generated/fonts/OpenSans-BoldItalic-webfont.woff b/documentation/generated/fonts/OpenSans-BoldItalic-webfont.woff new file mode 100644 index 0000000..ed760c0 Binary files /dev/null and b/documentation/generated/fonts/OpenSans-BoldItalic-webfont.woff differ diff --git a/documentation/generated/fonts/OpenSans-Italic-webfont.eot b/documentation/generated/fonts/OpenSans-Italic-webfont.eot new file mode 100644 index 0000000..0c8a0ae Binary files /dev/null and b/documentation/generated/fonts/OpenSans-Italic-webfont.eot differ diff --git a/documentation/generated/fonts/OpenSans-Italic-webfont.svg b/documentation/generated/fonts/OpenSans-Italic-webfont.svg new file mode 100644 index 0000000..e1075dc --- /dev/null +++ b/documentation/generated/fonts/OpenSans-Italic-webfont.svg @@ -0,0 +1,1830 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/documentation/generated/fonts/OpenSans-Italic-webfont.woff b/documentation/generated/fonts/OpenSans-Italic-webfont.woff new file mode 100644 index 0000000..ff652e6 Binary files /dev/null and b/documentation/generated/fonts/OpenSans-Italic-webfont.woff differ diff --git a/documentation/generated/fonts/OpenSans-Light-webfont.eot b/documentation/generated/fonts/OpenSans-Light-webfont.eot new file mode 100644 index 0000000..1486840 Binary files /dev/null and b/documentation/generated/fonts/OpenSans-Light-webfont.eot differ diff --git a/documentation/generated/fonts/OpenSans-Light-webfont.svg b/documentation/generated/fonts/OpenSans-Light-webfont.svg new file mode 100644 index 0000000..11a472c --- /dev/null +++ b/documentation/generated/fonts/OpenSans-Light-webfont.svg @@ -0,0 +1,1831 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/documentation/generated/fonts/OpenSans-Light-webfont.woff b/documentation/generated/fonts/OpenSans-Light-webfont.woff new file mode 100644 index 0000000..e786074 Binary files /dev/null and b/documentation/generated/fonts/OpenSans-Light-webfont.woff differ diff --git a/documentation/generated/fonts/OpenSans-LightItalic-webfont.eot b/documentation/generated/fonts/OpenSans-LightItalic-webfont.eot new file mode 100644 index 0000000..8f44592 Binary files /dev/null and b/documentation/generated/fonts/OpenSans-LightItalic-webfont.eot differ diff --git a/documentation/generated/fonts/OpenSans-LightItalic-webfont.svg b/documentation/generated/fonts/OpenSans-LightItalic-webfont.svg new file mode 100644 index 0000000..431d7e3 --- /dev/null +++ b/documentation/generated/fonts/OpenSans-LightItalic-webfont.svg @@ -0,0 +1,1835 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/documentation/generated/fonts/OpenSans-LightItalic-webfont.woff b/documentation/generated/fonts/OpenSans-LightItalic-webfont.woff new file mode 100644 index 0000000..43e8b9e Binary files /dev/null and b/documentation/generated/fonts/OpenSans-LightItalic-webfont.woff differ diff --git a/documentation/generated/fonts/OpenSans-Regular-webfont.eot b/documentation/generated/fonts/OpenSans-Regular-webfont.eot new file mode 100644 index 0000000..6bbc3cf Binary files /dev/null and b/documentation/generated/fonts/OpenSans-Regular-webfont.eot differ diff --git a/documentation/generated/fonts/OpenSans-Regular-webfont.svg b/documentation/generated/fonts/OpenSans-Regular-webfont.svg new file mode 100644 index 0000000..25a3952 --- /dev/null +++ b/documentation/generated/fonts/OpenSans-Regular-webfont.svg @@ -0,0 +1,1831 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/documentation/generated/fonts/OpenSans-Regular-webfont.woff b/documentation/generated/fonts/OpenSans-Regular-webfont.woff new file mode 100644 index 0000000..e231183 Binary files /dev/null and b/documentation/generated/fonts/OpenSans-Regular-webfont.woff differ diff --git a/documentation/generated/index.html b/documentation/generated/index.html new file mode 100644 index 0000000..8c145fd --- /dev/null +++ b/documentation/generated/index.html @@ -0,0 +1,116 @@ + + + + + JSDoc: Home + + + + + + + + + + +
+ +

Home

+ + + + + + + + +

+ + + + + + + + + + + + + + + +
+

Battleship

+

EECS 448 - Project 1

+

This is a basic battleship game created as our submission for project 1 for EECS 448 at the University of Kansas.

+

Structure Info

+

This project has been wired up to use Vue.js to help organize components of the game.

+

These components are defined in files that end in the .component.js extension, and are located in the src/components/ directory.

+

The entry point for the project is the index.html. This file contains the basic logic for loading Vue, and adding the game board to the page.

+

Obviously, we'll flesh out the look-and-feel as we go along. This is just a basic starter for now.

+

How to Run

+

The easiest way to run this project is by creating a basic static web server using Python. This is super simple:

+
    +
  1. Open a terminal or command prompt to the root of this project (i.e. the directory this file is in).
  2. +
  3. Start the server: python -m http.server
  4. +
+

This will start a web server on port 8000. You can then run the game by navigating to http://localhost:8000/ from a web browser.

+

Documentation

+

You can preview it here. Otherwise, it is generated by JSDoc in the documentation/generated directory.

+

Re-generating the documentation

+

To regenerate the docs, you need Node.js and the Yarn package manager installed. Then, just:

+
cd documentation
+./generate.sh
+
+

Third-Party Libraries

+

The files in the lib/ are external libraries used in this project.

+
    +
  • Vue.js +
      +
    • A front-end framework. Used under the terms of the MIT license.
    • +
    • https://github.com/vuejs/vue
    • +
    +
  • +
  • VuES6.js +
      +
    • A kind-of crappy loader for defining Vue components using ES6 classes.
    • +
    • Also used under the terms of the MIT license.
    • +
    • https://code.garrettmills.dev/garrettmills/vues6
    • +
    +
  • +
  • Sound effects obtained from https://www.zapsplat.com and used with permission.
  • +
+

Contributors

+
    +
  • Lucas Brakenridge
  • +
  • Javier Barea Lara
  • +
  • Garrett Mills
  • +
  • Evan Powell
  • +
  • Alec Horlick-Mills
  • +
+
+ + + + + + +
+ + + +
+ + + + + + + \ No newline at end of file diff --git a/documentation/generated/module-errors.InvalidAdvanceStateError.html b/documentation/generated/module-errors.InvalidAdvanceStateError.html new file mode 100644 index 0000000..bd5713a --- /dev/null +++ b/documentation/generated/module-errors.InvalidAdvanceStateError.html @@ -0,0 +1,183 @@ + + + + + JSDoc: Class: InvalidAdvanceStateError + + + + + + + + + + +
+ +

Class: InvalidAdvanceStateError

+ + + + + + +
+ +
+ +

+ errors.InvalidAdvanceStateError()

+ +
Error thrown when the program tries to advance the state, but it is +invalid.
+ + +
+ +
+
+ + + + +

Constructor

+ + + +

new InvalidAdvanceStateError()

+ + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + +
+ + +

Extends

+ + + + +
    +
  • Error
  • +
+ + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + +
+ + + +
+ + + + + + + \ No newline at end of file diff --git a/documentation/generated/module-errors.InvalidMissileFireAttemptError.html b/documentation/generated/module-errors.InvalidMissileFireAttemptError.html new file mode 100644 index 0000000..0c580b6 --- /dev/null +++ b/documentation/generated/module-errors.InvalidMissileFireAttemptError.html @@ -0,0 +1,182 @@ + + + + + JSDoc: Class: InvalidMissileFireAttemptError + + + + + + + + + + +
+ +

Class: InvalidMissileFireAttemptError

+ + + + + + +
+ +
+ +

+ errors.InvalidMissileFireAttemptError()

+ +
Error thrown when a missile is fired at an invalid cell.
+ + +
+ +
+
+ + + + +

Constructor

+ + + +

new InvalidMissileFireAttemptError()

+ + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + +
+ + +

Extends

+ + + + +
    +
  • Error
  • +
+ + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + +
+ + + +
+ + + + + + + \ No newline at end of file diff --git a/documentation/generated/module-errors.InvalidShipPlacementError.html b/documentation/generated/module-errors.InvalidShipPlacementError.html new file mode 100644 index 0000000..e77fa8b --- /dev/null +++ b/documentation/generated/module-errors.InvalidShipPlacementError.html @@ -0,0 +1,183 @@ + + + + + JSDoc: Class: InvalidShipPlacementError + + + + + + + + + + +
+ +

Class: InvalidShipPlacementError

+ + + + + + +
+ +
+ +

+ errors.InvalidShipPlacementError()

+ +
Placeholder class for an error that is thrown when a ship is placed +in an invalid position.
+ + +
+ +
+
+ + + + +

Constructor

+ + + +

new InvalidShipPlacementError()

+ + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + +
+ + +

Extends

+ + + + +
    +
  • Error
  • +
+ + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + +
+ + + +
+ + + + + + + \ No newline at end of file diff --git a/documentation/generated/module-errors.html b/documentation/generated/module-errors.html new file mode 100644 index 0000000..110f5a9 --- /dev/null +++ b/documentation/generated/module-errors.html @@ -0,0 +1,98 @@ + + + + + JSDoc: Module: errors + + + + + + + + + + +
+ +

Module: errors

+ + + + + + +
+ +
+ + + +
+ + + +
+ + + + +
+ + + +
+ + + + + + + \ No newline at end of file diff --git a/documentation/generated/module-lang.html b/documentation/generated/module-lang.html new file mode 100644 index 0000000..aa78a80 --- /dev/null +++ b/documentation/generated/module-lang.html @@ -0,0 +1,161 @@ + + + + + JSDoc: Module: lang + + + + + + + + + + +
+ +

Module: lang

+ + + + + + +
+ +
+ + + +
+ +
+
+ + + + + +
+ + + + + + + + + + + + + + +

Members

+ + + +

(inner, constant) instructions :object

+ + + + +
+ Enum of all possible instructions. +
+ + + +
Type:
+
    +
  • + +object + + +
  • +
+ + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + +
+ +
+ + + + +
+ + + +
+ + + + + + + \ No newline at end of file diff --git a/documentation/generated/module-sounds-Sound.html b/documentation/generated/module-sounds-Sound.html new file mode 100644 index 0000000..dba0c95 --- /dev/null +++ b/documentation/generated/module-sounds-Sound.html @@ -0,0 +1,480 @@ + + + + + JSDoc: Class: Sound + + + + + + + + + + +
+ +

Class: Sound

+ + + + + + +
+ +
+ +

+ sounds~Sound(src)

+ +
A thin wrapper for sound effects.
+ + +
+ +
+
+ + + + +

Constructor

+ + + +

new Sound(src)

+ + + + + + +
+ Construct the sound. +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
src + + +string + + + + URL of the file
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + +

Members

+ + + +

sound :HTMLAudioElement

+ + + + +
+ The sound element. +
+ + + +
Type:
+
    +
  • + +HTMLAudioElement + + +
  • +
+ + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + +

Methods

+ + + + + + + +

(async) play()

+ + + + + + +
+ Start playing the sound. +
+ + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

stop()

+ + + + + + +
+ Pause the sound. +
+ + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + +
+ + + +
+ + + + + + + \ No newline at end of file diff --git a/documentation/generated/module-sounds.html b/documentation/generated/module-sounds.html new file mode 100644 index 0000000..2588964 --- /dev/null +++ b/documentation/generated/module-sounds.html @@ -0,0 +1,168 @@ + + + + + JSDoc: Module: sounds + + + + + + + + + + +
+ +

Module: sounds

+ + + + + + +
+ +
+ + + +
+ +
+
+ + + + + +
+ + + + + + +

Classes

+ +
+
Sound
+
+
+ + + + + + + + + +

Members

+ + + +

(inner, constant) GameSounds :object

+ + + + +
+ Enum of the various sound effects available in the game. +
+ + + +
Type:
+
    +
  • + +object + + +
  • +
+ + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + +
+ +
+ + + + +
+ + + +
+ + + + + + + \ No newline at end of file diff --git a/documentation/generated/module-util.html b/documentation/generated/module-util.html new file mode 100644 index 0000000..1f02918 --- /dev/null +++ b/documentation/generated/module-util.html @@ -0,0 +1,1001 @@ + + + + + JSDoc: Module: util + + + + + + + + + + +
+ +

Module: util

+ + + + + + +
+ +
+ + + +
+ +
+
+ + + + + +
+ + + + + + + + + + + + + + +

Members

+ + + +

(static, constant) GameState :object

+ + + + +
+ Enum of all possible game states. These are player-agnostic. +
+ + + +
Type:
+
    +
  • + +object + + +
  • +
+ + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + +

(static, constant) GridCellState :object

+ + + + +
+ Enum of all possible states of a grid cell. +
+ + + +
Type:
+
    +
  • + +object + + +
  • +
+ + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + +

(static, constant) Player :object

+ + + + +
+ Enum of all possible players. +
+ + + +
Type:
+
    +
  • + +object + + +
  • +
+ + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + +

(static, constant) ShipType :object

+ + + + +
+ The various supported ship types, by dimension. +
+ + + +
Type:
+
    +
  • + +object + + +
  • +
+ + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + +

Methods

+ + + + + + + +

(static) appUrl(path) → {string}

+ + + + + + +
+ Generate an absolute URL to a file w/in the project directory. +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
path + + +string + + + +
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + + + +
+
+ Type +
+
+ +string + + +
+
+ + + + + + + + + + + + + +

(static) clone(obj) → {*}

+ + + + + + +
+ Makes a deep copy of the value passed in. +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
obj + + +* + + + +
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + + + +
+
+ Type +
+
+ +* + + +
+
+ + + + + + + + + + + + + +

(static) isShipCell(grid_cell_state) → {boolean}

+ + + + + + +
+ Returns true if the given grid cell state represents a ship in some way. +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
grid_cell_state + + +GridCellState + + + +
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + + + +
+
+ Type +
+
+ +boolean + + +
+
+ + + + + + + + + + + + + +

(static) isValidTargetCell(grid_cell_state) → {boolean}

+ + + + + + +
+ Returns true if the given grid cell state can be fired upon. +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
grid_cell_state + + +GridCellState + + + +
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + + + +
+
+ Type +
+
+ +boolean + + +
+
+ + + + + + + + + + + + + +
+ +
+ + + + +
+ + + +
+ + + + + + + \ No newline at end of file diff --git a/documentation/generated/module_errors.js.html b/documentation/generated/module_errors.js.html new file mode 100644 index 0000000..06df610 --- /dev/null +++ b/documentation/generated/module_errors.js.html @@ -0,0 +1,72 @@ + + + + + JSDoc: Source: module/errors.js + + + + + + + + + + +
+ +

Source: module/errors.js

+ + + + + + +
+
+
/** @module errors */
+
+/**
+ * Placeholder class for an error that is thrown when a ship is placed
+ * in an invalid position.
+ * @extends Error
+ */
+export class InvalidShipPlacementError extends Error {}
+
+/**
+ * Error thrown when the program tries to advance the state, but it is
+ * invalid.
+ * @extends Error
+ */
+export class InvalidAdvanceStateError extends Error {}
+
+/**
+ * Error thrown when a missile is fired at an invalid cell.
+ * @extends Error
+ */
+export class InvalidMissileFireAttemptError extends Error {}
+
+
+
+ + + + +
+ + + +
+ + + + + + + diff --git a/documentation/generated/module_lang.js.html b/documentation/generated/module_lang.js.html new file mode 100644 index 0000000..574eeff --- /dev/null +++ b/documentation/generated/module_lang.js.html @@ -0,0 +1,67 @@ + + + + + JSDoc: Source: module/lang.js + + + + + + + + + + +
+ +

Source: module/lang.js

+ + + + + + +
+
+
/** @module lang **/
+
+import { GameState } from './util.js'
+
+/**
+ * Enum of all possible instructions.
+ * @type {object}
+ */
+const instructions = {
+  [GameState.ChoosingNumberOfShips]: 'Select the number of ships both players will play with.',
+  [GameState.PlayerSetup]: 'Place your ships on your fleet\'s grid. You can hold the shift key to change the orientation.',
+  [GameState.PlayerTurn]: 'Select a cell on the opposing fleet\'s grid to fire a missile.',
+  [GameState.PlayerVictory]: '{player} won!'
+}
+
+export { instructions }
+
+
+
+ + + + +
+ + + +
+ + + + + + + diff --git a/documentation/generated/module_sounds.js.html b/documentation/generated/module_sounds.js.html new file mode 100644 index 0000000..d09c007 --- /dev/null +++ b/documentation/generated/module_sounds.js.html @@ -0,0 +1,109 @@ + + + + + JSDoc: Source: module/sounds.js + + + + + + + + + + +
+ +

Source: module/sounds.js

+ + + + + + +
+
+
/** @module sounds */
+
+import { appUrl } from './util.js'
+
+/**
+ * A thin wrapper for sound effects.
+ */
+class Sound {
+    /**
+     * Construct the sound.
+     * @param {string} src - URL of the file
+     */
+    constructor(src) {
+        /**
+         * The sound element.
+         * @type {HTMLAudioElement}
+         */
+        this.sound = document.createElement('audio')
+        this.sound.src = src
+        this.sound.setAttribute('preload', 'auto')
+        this.sound.setAttribute('controls', 'none')
+        this.sound.style.display = 'none'
+
+        document.body.appendChild(this.sound)
+    }
+
+    /**
+     * Start playing the sound.
+     */
+    async play() {
+        const duration = this.sound.duration
+
+        await this.sound.play()
+        await new Promise(res => {
+            setTimeout(res, duration * 1000)
+        })
+    }
+
+    /**
+     * Pause the sound.
+     */
+    stop() {
+        this.sound.pause()
+    }
+}
+
+/**
+ * Enum of the various sound effects available in the game.
+ * @type {object}
+ */
+const GameSounds = {
+    Victory: new Sound(appUrl('/lib/sounds/cartoon_success_fanfair.mp3')),
+    Fire: new Sound(appUrl('/lib/sounds/zapsplat_warfare_mortar_projectile_launch_002_25232.mp3')),
+    Hit: new Sound(appUrl('/lib/sounds/zapsplat_warfare_bomb_whizz_in_hit_close_by_explosion_med_003_48060.mp3')),
+    Miss: new Sound(appUrl('/lib/sounds/zapsplat_nature_water_pour_medium_amount_deep_sudden_fast_002_52765.mp3')),
+}
+
+export { GameSounds }
+
+
+
+ + + + +
+ + + +
+ + + + + + + diff --git a/documentation/generated/module_util.js.html b/documentation/generated/module_util.js.html new file mode 100644 index 0000000..8a6f324 --- /dev/null +++ b/documentation/generated/module_util.js.html @@ -0,0 +1,177 @@ + + + + + JSDoc: Source: module/util.js + + + + + + + + + + +
+ +

Source: module/util.js

+ + + + + + +
+
+
/** @module util */
+
+/**
+ * Enum of all possible states of a grid cell.
+ * @type {object}
+ */
+export const GridCellState = {
+    // Empty cell, default state
+    Available: 'available',
+
+    // Disabled. Ship cannot be placed here.
+    Disabled: 'disabled',
+
+    // There is a ship in this cell.
+    Ship: 'ship',
+
+    // This cell contains part of a ship which was damaged but not sunk
+    Damaged: 'damaged',
+
+    // This cell contains part of a ship which was sunk
+    Sunk: 'sunk',
+
+    // This cell was targeted, but nothing was hit
+    Missed: 'missed',
+}
+
+/**
+ * Returns true if the given grid cell state represents a ship in some way.
+ * @param {GridCellState} grid_cell_state
+ * @return {boolean}
+ */
+export function isShipCell(grid_cell_state) {
+    return [
+        GridCellState.Ship,
+        GridCellState.Damaged,
+        GridCellState.Sunk,
+    ].includes(grid_cell_state)
+}
+
+/**
+ * Returns true if the given grid cell state can be fired upon.
+ * @param {GridCellState} grid_cell_state
+ * @return {boolean}
+ */
+export function isValidTargetCell(grid_cell_state) {
+    return [
+        GridCellState.Ship,
+        GridCellState.Available,
+    ].includes(grid_cell_state)
+}
+
+/**
+ * Enum of all possible players.
+ * @type {object}
+ */
+export const Player = {
+    One: 'player_one',
+    Two: 'player_two',
+}
+
+/**
+ * Enum of all possible game states. These are player-agnostic.
+ * @type {object}
+ */
+export const GameState = {
+    // Both players are choosing the number of ships to play with (1-5)
+    ChoosingNumberOfShips: 'choosing_number_of_ships',
+
+    // A player is placing their ships
+    PlayerSetup: 'player_setup',
+
+    // We are prompting to change to the other player
+    PromptPlayerChange: 'prompt_player_change',
+
+    // It is the player's turn to fire a missle at their opponent
+    PlayerTurn: 'player_turn',
+
+    // A player has won
+    PlayerVictory: 'player_victory',
+}
+
+/**
+ * The various supported ship types, by dimension.
+ * @type {object}
+ */
+export const ShipType = {
+    x1: '1x1',
+    x2: '1x2',
+    x3: '1x3',
+    x4: '1x4',
+    x5: '1x5',
+}
+
+export function isShipType(type) {
+    return ['1x1', '1x2', '1x3', '1x4', '1x5'].includes(type)
+}
+
+/**
+ * Makes a deep copy of the value passed in.
+ * @param {*} obj
+ * @return {*}
+ */
+export function clone(obj) {
+    // If it's just a value, return it.
+    if ( typeof obj !== 'object' || obj === null ) return obj
+
+    // If it's an array, copy its values.
+    if ( Array.isArray(obj) ) return obj.map(x => clone(x))
+
+    // If it's an object, copy its properties.
+    const copy = {}
+    for ( const prop in obj ) {
+        copy[prop] = clone(obj[prop])
+    }
+    return copy
+}
+
+/**
+ * Generate an absolute URL to a file w/in the project directory.
+ * @param {string} path
+ * @return {string}
+ */
+export function appUrl(path) {
+    if ( path.startsWith('/') ) path = path.slice(1)
+    return `${APP_BASE_PATH}${path}`
+}
+
+
+
+ + + + +
+ + + +
+ + + + + + + diff --git a/documentation/generated/scripts/linenumber.js b/documentation/generated/scripts/linenumber.js new file mode 100644 index 0000000..4354785 --- /dev/null +++ b/documentation/generated/scripts/linenumber.js @@ -0,0 +1,25 @@ +/*global document */ +(() => { + const source = document.getElementsByClassName('prettyprint source linenums'); + let i = 0; + let lineNumber = 0; + let lineId; + let lines; + let totalLines; + let anchorHash; + + if (source && source[0]) { + anchorHash = document.location.hash.substring(1); + lines = source[0].getElementsByTagName('li'); + totalLines = lines.length; + + for (; i < totalLines; i++) { + lineNumber++; + lineId = `line${lineNumber}`; + lines[i].id = lineId; + if (lineId === anchorHash) { + lines[i].className += ' selected'; + } + } + } +})(); diff --git a/documentation/generated/scripts/prettify/Apache-License-2.0.txt b/documentation/generated/scripts/prettify/Apache-License-2.0.txt new file mode 100644 index 0000000..d645695 --- /dev/null +++ b/documentation/generated/scripts/prettify/Apache-License-2.0.txt @@ -0,0 +1,202 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/documentation/generated/scripts/prettify/lang-css.js b/documentation/generated/scripts/prettify/lang-css.js new file mode 100644 index 0000000..041e1f5 --- /dev/null +++ b/documentation/generated/scripts/prettify/lang-css.js @@ -0,0 +1,2 @@ +PR.registerLangHandler(PR.createSimpleLexer([["pln",/^[\t\n\f\r ]+/,null," \t\r\n "]],[["str",/^"(?:[^\n\f\r"\\]|\\(?:\r\n?|\n|\f)|\\[\S\s])*"/,null],["str",/^'(?:[^\n\f\r'\\]|\\(?:\r\n?|\n|\f)|\\[\S\s])*'/,null],["lang-css-str",/^url\(([^"')]*)\)/i],["kwd",/^(?:url|rgb|!important|@import|@page|@media|@charset|inherit)(?=[^\w-]|$)/i,null],["lang-css-kw",/^(-?(?:[_a-z]|\\[\da-f]+ ?)(?:[\w-]|\\\\[\da-f]+ ?)*)\s*:/i],["com",/^\/\*[^*]*\*+(?:[^*/][^*]*\*+)*\//],["com", +/^(?:<\!--|--\>)/],["lit",/^(?:\d+|\d*\.\d+)(?:%|[a-z]+)?/i],["lit",/^#[\da-f]{3,6}/i],["pln",/^-?(?:[_a-z]|\\[\da-f]+ ?)(?:[\w-]|\\\\[\da-f]+ ?)*/i],["pun",/^[^\s\w"']+/]]),["css"]);PR.registerLangHandler(PR.createSimpleLexer([],[["kwd",/^-?(?:[_a-z]|\\[\da-f]+ ?)(?:[\w-]|\\\\[\da-f]+ ?)*/i]]),["css-kw"]);PR.registerLangHandler(PR.createSimpleLexer([],[["str",/^[^"')]+/]]),["css-str"]); diff --git a/documentation/generated/scripts/prettify/prettify.js b/documentation/generated/scripts/prettify/prettify.js new file mode 100644 index 0000000..eef5ad7 --- /dev/null +++ b/documentation/generated/scripts/prettify/prettify.js @@ -0,0 +1,28 @@ +var q=null;window.PR_SHOULD_USE_CONTINUATION=!0; +(function(){function L(a){function m(a){var f=a.charCodeAt(0);if(f!==92)return f;var b=a.charAt(1);return(f=r[b])?f:"0"<=b&&b<="7"?parseInt(a.substring(1),8):b==="u"||b==="x"?parseInt(a.substring(2),16):a.charCodeAt(1)}function e(a){if(a<32)return(a<16?"\\x0":"\\x")+a.toString(16);a=String.fromCharCode(a);if(a==="\\"||a==="-"||a==="["||a==="]")a="\\"+a;return a}function h(a){for(var f=a.substring(1,a.length-1).match(/\\u[\dA-Fa-f]{4}|\\x[\dA-Fa-f]{2}|\\[0-3][0-7]{0,2}|\\[0-7]{1,2}|\\[\S\s]|[^\\]/g),a= +[],b=[],o=f[0]==="^",c=o?1:0,i=f.length;c122||(d<65||j>90||b.push([Math.max(65,j)|32,Math.min(d,90)|32]),d<97||j>122||b.push([Math.max(97,j)&-33,Math.min(d,122)&-33]))}}b.sort(function(a,f){return a[0]-f[0]||f[1]-a[1]});f=[];j=[NaN,NaN];for(c=0;ci[0]&&(i[1]+1>i[0]&&b.push("-"),b.push(e(i[1])));b.push("]");return b.join("")}function y(a){for(var f=a.source.match(/\[(?:[^\\\]]|\\[\S\s])*]|\\u[\dA-Fa-f]{4}|\\x[\dA-Fa-f]{2}|\\\d+|\\[^\dux]|\(\?[!:=]|[()^]|[^()[\\^]+/g),b=f.length,d=[],c=0,i=0;c=2&&a==="["?f[c]=h(j):a!=="\\"&&(f[c]=j.replace(/[A-Za-z]/g,function(a){a=a.charCodeAt(0);return"["+String.fromCharCode(a&-33,a|32)+"]"}));return f.join("")}for(var t=0,s=!1,l=!1,p=0,d=a.length;p=5&&"lang-"===b.substring(0,5))&&!(o&&typeof o[1]==="string"))c=!1,b="src";c||(r[f]=b)}i=d;d+=f.length;if(c){c=o[1];var j=f.indexOf(c),k=j+c.length;o[2]&&(k=f.length-o[2].length,j=k-c.length);b=b.substring(5);B(l+i,f.substring(0,j),e,p);B(l+i+j,c,C(b,c),p);B(l+i+k,f.substring(k),e,p)}else p.push(l+i,b)}a.e=p}var h={},y;(function(){for(var e=a.concat(m), +l=[],p={},d=0,g=e.length;d=0;)h[n.charAt(k)]=r;r=r[1];n=""+r;p.hasOwnProperty(n)||(l.push(r),p[n]=q)}l.push(/[\S\s]/);y=L(l)})();var t=m.length;return e}function u(a){var m=[],e=[];a.tripleQuotedStrings?m.push(["str",/^(?:'''(?:[^'\\]|\\[\S\s]|''?(?=[^']))*(?:'''|$)|"""(?:[^"\\]|\\[\S\s]|""?(?=[^"]))*(?:"""|$)|'(?:[^'\\]|\\[\S\s])*(?:'|$)|"(?:[^"\\]|\\[\S\s])*(?:"|$))/,q,"'\""]):a.multiLineStrings?m.push(["str",/^(?:'(?:[^'\\]|\\[\S\s])*(?:'|$)|"(?:[^"\\]|\\[\S\s])*(?:"|$)|`(?:[^\\`]|\\[\S\s])*(?:`|$))/, +q,"'\"`"]):m.push(["str",/^(?:'(?:[^\n\r'\\]|\\.)*(?:'|$)|"(?:[^\n\r"\\]|\\.)*(?:"|$))/,q,"\"'"]);a.verbatimStrings&&e.push(["str",/^@"(?:[^"]|"")*(?:"|$)/,q]);var h=a.hashComments;h&&(a.cStyleComments?(h>1?m.push(["com",/^#(?:##(?:[^#]|#(?!##))*(?:###|$)|.*)/,q,"#"]):m.push(["com",/^#(?:(?:define|elif|else|endif|error|ifdef|include|ifndef|line|pragma|undef|warning)\b|[^\n\r]*)/,q,"#"]),e.push(["str",/^<(?:(?:(?:\.\.\/)*|\/?)(?:[\w-]+(?:\/[\w-]+)+)?[\w-]+\.h|[a-z]\w*)>/,q])):m.push(["com",/^#[^\n\r]*/, +q,"#"]));a.cStyleComments&&(e.push(["com",/^\/\/[^\n\r]*/,q]),e.push(["com",/^\/\*[\S\s]*?(?:\*\/|$)/,q]));a.regexLiterals&&e.push(["lang-regex",/^(?:^^\.?|[!+-]|!=|!==|#|%|%=|&|&&|&&=|&=|\(|\*|\*=|\+=|,|-=|->|\/|\/=|:|::|;|<|<<|<<=|<=|=|==|===|>|>=|>>|>>=|>>>|>>>=|[?@[^]|\^=|\^\^|\^\^=|{|\||\|=|\|\||\|\|=|~|break|case|continue|delete|do|else|finally|instanceof|return|throw|try|typeof)\s*(\/(?=[^*/])(?:[^/[\\]|\\[\S\s]|\[(?:[^\\\]]|\\[\S\s])*(?:]|$))+\/)/]);(h=a.types)&&e.push(["typ",h]);a=(""+a.keywords).replace(/^ | $/g, +"");a.length&&e.push(["kwd",RegExp("^(?:"+a.replace(/[\s,]+/g,"|")+")\\b"),q]);m.push(["pln",/^\s+/,q," \r\n\t\xa0"]);e.push(["lit",/^@[$_a-z][\w$@]*/i,q],["typ",/^(?:[@_]?[A-Z]+[a-z][\w$@]*|\w+_t\b)/,q],["pln",/^[$_a-z][\w$@]*/i,q],["lit",/^(?:0x[\da-f]+|(?:\d(?:_\d+)*\d*(?:\.\d*)?|\.\d\+)(?:e[+-]?\d+)?)[a-z]*/i,q,"0123456789"],["pln",/^\\[\S\s]?/,q],["pun",/^.[^\s\w"-$'./@\\`]*/,q]);return x(m,e)}function D(a,m){function e(a){switch(a.nodeType){case 1:if(k.test(a.className))break;if("BR"===a.nodeName)h(a), +a.parentNode&&a.parentNode.removeChild(a);else for(a=a.firstChild;a;a=a.nextSibling)e(a);break;case 3:case 4:if(p){var b=a.nodeValue,d=b.match(t);if(d){var c=b.substring(0,d.index);a.nodeValue=c;(b=b.substring(d.index+d[0].length))&&a.parentNode.insertBefore(s.createTextNode(b),a.nextSibling);h(a);c||a.parentNode.removeChild(a)}}}}function h(a){function b(a,d){var e=d?a.cloneNode(!1):a,f=a.parentNode;if(f){var f=b(f,1),g=a.nextSibling;f.appendChild(e);for(var h=g;h;h=g)g=h.nextSibling,f.appendChild(h)}return e} +for(;!a.nextSibling;)if(a=a.parentNode,!a)return;for(var a=b(a.nextSibling,0),e;(e=a.parentNode)&&e.nodeType===1;)a=e;d.push(a)}var k=/(?:^|\s)nocode(?:\s|$)/,t=/\r\n?|\n/,s=a.ownerDocument,l;a.currentStyle?l=a.currentStyle.whiteSpace:window.getComputedStyle&&(l=s.defaultView.getComputedStyle(a,q).getPropertyValue("white-space"));var p=l&&"pre"===l.substring(0,3);for(l=s.createElement("LI");a.firstChild;)l.appendChild(a.firstChild);for(var d=[l],g=0;g=0;){var h=m[e];A.hasOwnProperty(h)?window.console&&console.warn("cannot override language handler %s",h):A[h]=a}}function C(a,m){if(!a||!A.hasOwnProperty(a))a=/^\s*=o&&(h+=2);e>=c&&(a+=2)}}catch(w){"console"in window&&console.log(w&&w.stack?w.stack:w)}}var v=["break,continue,do,else,for,if,return,while"],w=[[v,"auto,case,char,const,default,double,enum,extern,float,goto,int,long,register,short,signed,sizeof,static,struct,switch,typedef,union,unsigned,void,volatile"], +"catch,class,delete,false,import,new,operator,private,protected,public,this,throw,true,try,typeof"],F=[w,"alignof,align_union,asm,axiom,bool,concept,concept_map,const_cast,constexpr,decltype,dynamic_cast,explicit,export,friend,inline,late_check,mutable,namespace,nullptr,reinterpret_cast,static_assert,static_cast,template,typeid,typename,using,virtual,where"],G=[w,"abstract,boolean,byte,extends,final,finally,implements,import,instanceof,null,native,package,strictfp,super,synchronized,throws,transient"], +H=[G,"as,base,by,checked,decimal,delegate,descending,dynamic,event,fixed,foreach,from,group,implicit,in,interface,internal,into,is,lock,object,out,override,orderby,params,partial,readonly,ref,sbyte,sealed,stackalloc,string,select,uint,ulong,unchecked,unsafe,ushort,var"],w=[w,"debugger,eval,export,function,get,null,set,undefined,var,with,Infinity,NaN"],I=[v,"and,as,assert,class,def,del,elif,except,exec,finally,from,global,import,in,is,lambda,nonlocal,not,or,pass,print,raise,try,with,yield,False,True,None"], +J=[v,"alias,and,begin,case,class,def,defined,elsif,end,ensure,false,in,module,next,nil,not,or,redo,rescue,retry,self,super,then,true,undef,unless,until,when,yield,BEGIN,END"],v=[v,"case,done,elif,esac,eval,fi,function,in,local,set,then,until"],K=/^(DIR|FILE|vector|(de|priority_)?queue|list|stack|(const_)?iterator|(multi)?(set|map)|bitset|u?(int|float)\d*)/,N=/\S/,O=u({keywords:[F,H,w,"caller,delete,die,do,dump,elsif,eval,exit,foreach,for,goto,if,import,last,local,my,next,no,our,print,package,redo,require,sub,undef,unless,until,use,wantarray,while,BEGIN,END"+ +I,J,v],hashComments:!0,cStyleComments:!0,multiLineStrings:!0,regexLiterals:!0}),A={};k(O,["default-code"]);k(x([],[["pln",/^[^]*(?:>|$)/],["com",/^<\!--[\S\s]*?(?:--\>|$)/],["lang-",/^<\?([\S\s]+?)(?:\?>|$)/],["lang-",/^<%([\S\s]+?)(?:%>|$)/],["pun",/^(?:<[%?]|[%?]>)/],["lang-",/^]*>([\S\s]+?)<\/xmp\b[^>]*>/i],["lang-js",/^]*>([\S\s]*?)(<\/script\b[^>]*>)/i],["lang-css",/^]*>([\S\s]*?)(<\/style\b[^>]*>)/i],["lang-in.tag",/^(<\/?[a-z][^<>]*>)/i]]), +["default-markup","htm","html","mxml","xhtml","xml","xsl"]);k(x([["pln",/^\s+/,q," \t\r\n"],["atv",/^(?:"[^"]*"?|'[^']*'?)/,q,"\"'"]],[["tag",/^^<\/?[a-z](?:[\w-.:]*\w)?|\/?>$/i],["atn",/^(?!style[\s=]|on)[a-z](?:[\w:-]*\w)?/i],["lang-uq.val",/^=\s*([^\s"'>]*(?:[^\s"'/>]|\/(?=\s)))/],["pun",/^[/<->]+/],["lang-js",/^on\w+\s*=\s*"([^"]+)"/i],["lang-js",/^on\w+\s*=\s*'([^']+)'/i],["lang-js",/^on\w+\s*=\s*([^\s"'>]+)/i],["lang-css",/^style\s*=\s*"([^"]+)"/i],["lang-css",/^style\s*=\s*'([^']+)'/i],["lang-css", +/^style\s*=\s*([^\s"'>]+)/i]]),["in.tag"]);k(x([],[["atv",/^[\S\s]+/]]),["uq.val"]);k(u({keywords:F,hashComments:!0,cStyleComments:!0,types:K}),["c","cc","cpp","cxx","cyc","m"]);k(u({keywords:"null,true,false"}),["json"]);k(u({keywords:H,hashComments:!0,cStyleComments:!0,verbatimStrings:!0,types:K}),["cs"]);k(u({keywords:G,cStyleComments:!0}),["java"]);k(u({keywords:v,hashComments:!0,multiLineStrings:!0}),["bsh","csh","sh"]);k(u({keywords:I,hashComments:!0,multiLineStrings:!0,tripleQuotedStrings:!0}), +["cv","py"]);k(u({keywords:"caller,delete,die,do,dump,elsif,eval,exit,foreach,for,goto,if,import,last,local,my,next,no,our,print,package,redo,require,sub,undef,unless,until,use,wantarray,while,BEGIN,END",hashComments:!0,multiLineStrings:!0,regexLiterals:!0}),["perl","pl","pm"]);k(u({keywords:J,hashComments:!0,multiLineStrings:!0,regexLiterals:!0}),["rb"]);k(u({keywords:w,cStyleComments:!0,regexLiterals:!0}),["js"]);k(u({keywords:"all,and,by,catch,class,else,extends,false,finally,for,if,in,is,isnt,loop,new,no,not,null,of,off,on,or,return,super,then,true,try,unless,until,when,while,yes", +hashComments:3,cStyleComments:!0,multilineStrings:!0,tripleQuotedStrings:!0,regexLiterals:!0}),["coffee"]);k(x([],[["str",/^[\S\s]+/]]),["regex"]);window.prettyPrintOne=function(a,m,e){var h=document.createElement("PRE");h.innerHTML=a;e&&D(h,e);E({g:m,i:e,h:h});return h.innerHTML};window.prettyPrint=function(a){function m(){for(var e=window.PR_SHOULD_USE_CONTINUATION?l.now()+250:Infinity;p=0){var k=k.match(g),f,b;if(b= +!k){b=n;for(var o=void 0,c=b.firstChild;c;c=c.nextSibling)var i=c.nodeType,o=i===1?o?b:c:i===3?N.test(c.nodeValue)?b:o:o;b=(f=o===b?void 0:o)&&"CODE"===f.tagName}b&&(k=f.className.match(g));k&&(k=k[1]);b=!1;for(o=n.parentNode;o;o=o.parentNode)if((o.tagName==="pre"||o.tagName==="code"||o.tagName==="xmp")&&o.className&&o.className.indexOf("prettyprint")>=0){b=!0;break}b||((b=(b=n.className.match(/\blinenums\b(?::(\d+))?/))?b[1]&&b[1].length?+b[1]:!0:!1)&&D(n,b),d={g:k,h:n,i:b},E(d))}}p + + + + JSDoc: Source: services/GameState.service.js + + + + + + + + + + +
+ +

Source: services/GameState.service.js

+ + + + + + +
+
+
import { Player, GridCellState, GameState, clone, ShipType, isShipType, isShipCell, isValidTargetCell } from '../module/util.js'
+import { InvalidShipPlacementError, InvalidAdvanceStateError, InvalidMissileFireAttemptError } from '../module/errors.js'
+
+/**
+ * Singleton service for managing the state of the game.
+ */
+export class GameStateService {
+    /**
+     * A mapping of player => game board state.
+     * @private
+     * @type {object}
+     */
+    player_x_game_board = {}
+
+    /**
+     * A mapping of player => ship definitions.
+     * @private
+     * @type {object}
+     */
+    player_x_ships = {}
+
+    /**
+     * An array of all players. This is mostly for internal purposes.
+     * @private
+     * @type {string[]}
+     */
+    players = [Player.One, Player.Two]
+
+    /**
+     * Number of rows in the grid.
+     * @private
+     * @type {number}
+     */
+    n_rows = 9
+
+    /**
+     * Number of cols in the grid.
+     * @private
+     * @type {number}
+     */
+    n_cols = 9
+
+    /**
+     * Number boats placed on the board.
+     * @private
+     * @type {number}
+     */
+    n_boats = 1
+
+    /**
+     * gets the number of boats placed on the board
+     * @private
+     * @return {number}
+     */
+    get_n_boats(){
+        return (this.n_boats);
+    }
+
+    /**
+     * sets the number of boats to a valid number
+     * @private
+     * @return none
+     */
+    set_n_boats(number){
+        if(number >= 1 && number <= 5 )
+        {
+            this.n_boats = number;
+        }
+    }
+
+    /**
+     * Given the number of boats set by the player (n_boats), return an array
+     * of possible ShipTypes.
+     * @return {string[]}
+     */
+    get_possible_boats(){
+        if (this.get_n_boats() === 1) {
+            return [ShipType.x1]
+        }
+        else if (this.get_n_boats() === 2) {
+            return [ShipType.x1, ShipType.x2]
+        }
+        else if (this.get_n_boats() === 3) {
+            return [ShipType.x1, ShipType.x2, ShipType.x3]
+        }
+        else if (this.get_n_boats() === 4) {
+            return [ShipType.x1, ShipType.x2, ShipType.x3, ShipType.x4]
+        }
+        else if (this.get_n_boats() === 5) {
+            return [ShipType.x1, ShipType.x2, ShipType.x3, ShipType.x4, ShipType.x5]
+        }
+    }
+
+    /**
+     * The current state of the game.
+     * @private
+     * @type {string}
+     */
+    current_state = GameState.ChoosingNumberOfShips
+
+    /**
+     * The current player.
+     * @private
+     * @type {string}
+     */
+    current_player = Player.One
+
+    /**
+     * The current opponent.
+     * @private
+     * @type {string}
+     */
+    current_opponent = Player.Two
+
+    /**
+     * If the current state is the PromptPlayerChange, then this is
+     * the state that we should move to next.
+     * @type {undefined|string}
+     */
+    post_player_change_state = undefined
+
+    /**
+     * True if, during the current turn, the user has tried to fire a missile.
+     * @type {boolean}
+     */
+    current_turn_had_missile_attempt = false
+
+    /**
+     * Array of functions that are called when the game state changes.
+     * @type {function[]}
+     */
+    game_state_change_listeners = []
+
+    /**
+     * Construct a new game service. Initialize any internal states.
+     */
+    constructor() {
+        // Generate empty boards for each player
+        for ( const player of this.players ) {
+            this.player_x_game_board[player] = this._build_empty_board()
+            this.player_x_ships[player] = []
+        }
+    }
+
+    /**
+     * Get the dimensions of the board as [rows, cols].
+     * @example const [n_rows, n_cols] = game_service.get_dimensions()
+     * @return {number[]}
+     */
+    get_dimensions() {
+        return [this.n_rows, this.n_cols]
+    }
+
+    /**
+     * Get the player who is the focus of the current game state.
+     * @return {string}
+     */
+    get_current_player() {
+        return this.current_player
+    }
+
+    /**
+     * Get the player who is NOT the focus of the current game state.
+     * @return {string}
+     */
+    get_current_opponent() {
+        return this.current_opponent
+    }
+
+    /**
+     * Get the state of the current player's board, as it should appear to them.
+     * @return {object[][]}
+     */
+    get_current_player_state() {
+        // The player can see everything about their own board, so just return it.
+        // Return a deep-copy, so internal state can't be modified.
+        return clone(this.player_x_game_board[this.current_player])
+    }
+
+    /**
+     * Get the state of the current opponent's board, as it should appear to the
+     * current player. Note that the current player cannot see "ship" spaces, only
+     * available, damaged, missed, or sunk.
+     * @return {object[][]}
+     */
+    get_current_opponent_state() {
+        // Return a deep-copy, so internal state can't be modified.
+        const state = clone(this.player_x_game_board[this.current_opponent])
+        const hidden_states = [
+            GridCellState.Disabled,
+            GridCellState.Ship,
+        ]
+
+        return state.map(row => {
+            return row.map(cell => {
+                if ( hidden_states.includes(cell.render) ) {
+                    // This is a hidden state, so hide it
+                    cell.render = GridCellState.Available
+                }
+
+                return cell
+            })
+        })
+    }
+
+    /**
+     * Get the states that should be shown on the victory screen.
+     * First element is the winner's state, second element is the loser's state.
+     * @return {object[][][]}
+     */
+    get_player_victory_state(){
+      return [clone(this.player_x_game_board[this.current_player]), clone(this.player_x_game_board[this.current_opponent])]
+    }
+
+    /**
+     * get the "score" (the number of hits) that the
+     * current player has (counting sunk ships)
+     * @return {number}
+     * @private
+     */
+    get_player_score(player) {
+        let score = 0
+        this.player_x_game_board[player].some(row => {
+            row.some(cell => {
+                if ( cell.render === GridCellState.Damaged || cell.render === GridCellState.Sunk ) {
+                    score += 1
+                }
+            })
+        })
+
+        return score
+    }
+
+    /**
+     * gets the number of the boats (sunken, damaged or not) that the opponent has
+     * used to help keep get progress method looking clean
+     * @return {number}
+     * @private
+     */
+    get_boat_count(player){
+        let boat_count = 0
+        this.player_x_game_board[player].some(row => {
+            row.some(cell => {
+                if ( isShipCell(cell.render) ) {
+                    boat_count += 1
+                }
+            })
+        })
+
+        return boat_count
+    }
+
+    /**
+     * gets the progress (hits/total boats) that the player has
+     * @return {number}
+     * @private
+     */
+    get_progress(player){
+        const boat_count = this.get_boat_count(player)
+        if ( boat_count !== 0 ) {
+            return (this.get_player_score(player) / boat_count).toFixed(2)
+        } else {
+            return 0
+        }
+    }
+
+    /**
+     * Get the current game state.
+     * @return {string}
+     */
+    get_game_state() {
+        return clone(this.current_state)
+    }
+
+    /**
+     * responsible for advancing the game state
+     * will be consisting of
+     */
+    advance_game_state() {
+        /** functions to be made that validate:
+         * 1) number of ships
+         * 2) player one placement
+         * 3) player two placement
+         * 4) player one turn
+         * 5) advance to player 2
+         * 6) player 2 turn
+         * 7) advance to player one
+         * 8) player win
+         */
+        if (this.current_state === GameState.ChoosingNumberOfShips) {
+            if (this.n_boats >= 1 && this.n_boats <= 5) {
+                this.current_state = GameState.PromptPlayerChange;
+                this.post_player_change_state = GameState.PlayerSetup;
+                this.current_player = Player.One;
+                this.current_opponent = Player.Two;
+            } else {
+                throw new InvalidAdvanceStateError("Invalid Number of Boats");
+            }
+        }
+        else if (this.current_state === GameState.PlayerSetup) {
+            if (this.current_player === Player.One) {
+                // because the place_ship handles all the validation
+                // all you need to do is make sure they have placed all the appropriate ships
+                if ( this.get_ship_entities(this.current_player).length === this.n_boats ) {
+                    this.current_state = GameState.PromptPlayerChange;
+                    this.post_player_change_state = GameState.PlayerSetup;
+                    this.current_player = Player.Two;
+                    this.current_opponent = Player.One;
+                }
+                else{
+                    throw new InvalidAdvanceStateError("Player One has a problem with the number of boats selected");
+                }
+            }
+            else if (this.current_player === Player.Two) {
+                if ( this.get_ship_entities(this.current_player).length === this.n_boats ) {
+                    this.current_state = GameState.PromptPlayerChange;
+                    this.post_player_change_state = GameState.PlayerTurn;
+                    this.current_player = Player.One;
+                    this.current_opponent = Player.Two;
+                }
+                else{
+                    throw new InvalidAdvanceStateError("Player Two has a problem with the number of boats selected");
+                }
+            }
+        }
+        else if (this.current_state === GameState.PlayerTurn && this.current_player === Player.One) {
+            if (this.current_turn_had_missile_attempt === true) {
+                this.current_state = GameState.PromptPlayerChange;
+                this.post_player_change_state = GameState.PlayerTurn;
+                this.current_player = Player.Two;
+                this.current_opponent = Player.One;
+            }
+            else {
+                throw new InvalidAdvanceStateError("the player has not fired a missle");
+            }
+        }
+        else if (this.current_state === GameState.PlayerTurn && this.current_player === Player.Two) {
+            if (this.current_turn_had_missile_attempt === true) {
+                this.current_state = GameState.PromptPlayerChange;
+                this.post_player_change_state = GameState.PlayerTurn;
+                this.current_player = Player.One;
+                this.current_opponent = Player.Two;
+            }
+            else {
+                throw new InvalidAdvanceStateError("the player has not fired a missle");
+            }
+        }
+        else if ( this.current_state === GameState.PromptPlayerChange ) {
+            if ( !this.post_player_change_state ) {
+                throw new InvalidAdvanceStateError('No state to advance to after player change!')
+            }
+
+            this.current_state = this.post_player_change_state
+            this.post_player_change_state = undefined
+        }
+
+        let winner = this.get_winner();
+        if(winner) {
+            this.current_state = GameState.PlayerVictory;
+            this.current_player = winner;
+            this.current_opponent = this.get_other_player(winner);
+        }
+
+        this.current_turn_had_missile_attempt = false
+        this.game_state_change_listeners.forEach(fn => fn(this.current_state, false))
+    }
+
+    /**
+     * Register a handler to be called when the game state changes.
+     * @param {function} handler
+     */
+    on_state_change(handler) {
+        this.game_state_change_listeners.push(handler)
+    }
+
+    /**
+     * Attempt to fire a missile at the current opponent at the given coordinates.
+     * The coordinates should be an array of [row_index, column_index] where the missile should fire.
+     * Returns true if the missile hit an undamaged cell of a ship.
+     *
+     * @example
+     * If I want to fire a missile at row 5 column 7, then:
+     * game_service.attempt_missile_fire([5, 7])
+     *
+     * @param {number[]} coords
+     * @return {boolean}
+     */
+    attempt_missile_fire([target_row_i, target_col_i]) {
+        if ( this.current_turn_had_missile_attempt ) {
+            throw new InvalidMissileFireAttemptError('Cannot fire more than once per turn.')
+        } else {
+            this.current_turn_had_missile_attempt = true
+        }
+
+        const target_cell = this._get_cell_state(this.current_opponent, target_row_i, target_col_i)
+        if ( !isValidTargetCell(target_cell.render) ) {
+            this.current_turn_had_missile_attempt = false
+            throw new InvalidMissileFireAttemptError('Cannot fire on cell with state: ' + target_cell.render)
+        }
+
+        if ( target_cell.render === GridCellState.Ship ) {
+            // We hit an un-hit ship cell!
+            this._set_cell_state(this.current_opponent, target_row_i, target_col_i, GridCellState.Damaged)
+
+            // set ships to sunk where appropriate
+            this._sink_damaged_ships(this.current_opponent)
+            this._trigger_view_update()
+            return true
+        } else if ( target_cell.render === GridCellState.Available ) {
+            // We missed...
+            this._set_cell_state(this.current_opponent, target_row_i, target_col_i, GridCellState.Missed)
+        }
+
+        this._trigger_view_update()
+        return false
+    }
+
+    /**
+     * Checks the player's ships. If any are fully damaged, it flags that ship's cells
+     * as "sunk" rather than damaged.
+     * @param {string} player
+     * @private
+     */
+    _sink_damaged_ships(player) {
+        this.get_ship_entities(player).some(ship => {
+            const covered_cells = this.get_covered_cells(ship.coords_one, ship.coords_two)
+            const all_damaged = covered_cells.every(([cell_row, cell_col]) => {
+                return this._get_cell_state(player, cell_row, cell_col).render === GridCellState.Damaged
+            })
+
+            if ( all_damaged ) {
+                // The entire boat was damaged, so sink it
+                covered_cells.some(([cell_row, cell_col]) => {
+                    this._set_cell_state(player, cell_row, cell_col, GridCellState.Sunk)
+                })
+            }
+        })
+    }
+
+    /**
+     * Attempt to place a ship of the given type at the given coordinates.
+     * Throws an InvalidShipPlacementError if the coordinates are invalid.
+     * Coordinates should be [row_index, column_index] of either end of the ship.
+     *
+     * @example
+     * If I am placing a 1x3 ship and I want it to be in row 3 column 2 horizontal
+     * to row 3 column 4, then I would call:
+     * game_service.place_ship(ShipType.x3, [3,2], [3,4])
+     *
+     * @param {string} ship_type
+     * @param {number[]} coords_one
+     * @param {number[]} coords_two
+     */
+    place_ship(ship_type, coords_one, coords_two) {
+        // make sure the coordinates are valid for the given ship type
+        this.validate_coordinates(ship_type, coords_one, coords_two)
+
+        // get the ships for the current player
+        const player_ships = this.get_ship_entities(this.current_player)
+
+        // make sure they don't already have this ship type
+        const have_ship_type = player_ships.some(ship => ship.ship_type === ship_type)
+        if ( have_ship_type )
+            throw new InvalidShipPlacementError('A ship with this type has already been placed.')
+
+        // make sure they don't already have too many
+        if ( player_ships.length >= this.n_boats )
+            throw new InvalidShipPlacementError('This player cannot place any more ships.')
+
+        // place the ship
+        this.player_x_ships[this.current_player].push({ ship_type, coords_one, coords_two })
+
+        // mark the cells as having a ship in them
+        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()
+    }
+
+    /**
+     * Get an array of cell coordinates that are covered by a ship that spans
+     * the given coordinates.
+     *
+     * @example
+     * If a ship goes from row 1 column 1 to row 4 column 1, then I can get
+     * the coordinates of all cells covered by that ship using:
+     * game_service.get_covered_cells([1,1], [4,1])
+     * Which would return [[1,1], [2,1], [3,1], [4,1]].
+     *
+     * @param {number[]} coords_one
+     * @param {number[]} coords_two
+     * @return {number[][]}
+     */
+    get_covered_cells(coords_one, coords_two) {
+        const [row_one, col_one] = coords_one
+        const [row_two, col_two] = coords_two
+        const [left_col, right_col] = [Math.min(col_one, col_two), Math.max(col_one, col_two)]
+        const [top_row, bottom_row] = [Math.min(row_one, row_two), Math.max(row_one, row_two)]
+        const is_horizontal = top_row === bottom_row
+
+        if ( is_horizontal ) {
+            return Array((right_col - left_col) + 1).fill('').map((_, i) => {
+                return [top_row, i + left_col]
+            })
+        } else {
+            return Array((bottom_row - top_row) + 1).fill('').map((_, i) => {
+                return [i + top_row, left_col]
+            })
+        }
+    }
+
+    /**
+     * Validate the given coordinates for the given ship type.
+     * Throws an InvalidShipPlacementError if the coordinates are invalid.
+     * Coordinates should be [row_index, column_index] of either end of the ship.
+     *
+     * @example
+     * If I am placing a 1x3 ship and I want it to be in row 3 column 2 horizontal
+     * to row 3 column 4, then I would call:
+     * game_service.validate_coordinates(ShipType.x3, [3,2], [3,4])
+     *
+     * @param {string} ship_type
+     * @param {number[]} coords_one
+     * @param {number[]} coords_two
+     */
+    validate_coordinates(ship_type, coords_one, coords_two) {
+        if ( !isShipType(ship_type) ) throw new InvalidShipPlacementError('Invalid ship type: '+ship_type)
+
+        const ship_length = this.get_ship_length(ship_type)
+        const [row_one, col_one] = coords_one
+        const [row_two, col_two] = coords_two
+        const [left_col, right_col] = [Math.min(col_one, col_two), Math.max(col_one, col_two)]
+        const [top_row, bottom_row] = [Math.min(row_one, row_two), Math.max(row_one, row_two)]
+
+        const is_horizontal = top_row === bottom_row
+        const ship_cells = this.get_ship_cells(this.current_player)
+        const placement_cells = []
+
+        if ( is_horizontal ) {
+            // Make sure the input length matches the given ship type
+            if ( (right_col - left_col) !== (ship_length - 1) )
+                throw new InvalidShipPlacementError('Invalid coordinates: ship length is invalid')
+
+            Array(ship_length).fill('').map((_, i) => {
+                placement_cells.push([top_row, i + left_col])
+            })
+        } else {
+            // Make sure the input length matches the given ship type
+            if ( (bottom_row - top_row) !== (ship_length - 1) )
+                throw new InvalidShipPlacementError('Invalid coordinates: ship length is invalid')
+
+            Array(ship_length).fill('').map((_, i) => {
+                placement_cells.push([i + top_row, left_col])
+            })
+        }
+
+        // Make sure none of the placement cells overlap with existing ships
+        const has_overlap = ship_cells.some(([ship_row, ship_col]) => {
+            return placement_cells.some(([placement_row, placement_col]) => {
+                return ship_row === placement_row && ship_col === placement_col
+            })
+        })
+
+        if ( has_overlap )
+            throw new InvalidShipPlacementError('Invalid coordinates: ship overlaps with others')
+    }
+
+    /**
+     * Get the number of cells the given ship type should occupy.
+     * @param {string} ship_type
+     * @return {number}
+     */
+    get_ship_length(ship_type) {
+        if ( ship_type === ShipType.x1 ) return 1
+        if ( ship_type === ShipType.x2 ) return 2
+        if ( ship_type === ShipType.x3 ) return 3
+        if ( ship_type === ShipType.x4 ) return 4
+        if ( ship_type === ShipType.x5 ) return 5
+    }
+
+    /**
+     * Get the coordinates of all cells that have ships in them, for the given player.
+     * @param {string} player
+     * @return {number[]}
+     */
+    get_ship_cells(player) {
+        const cells = []
+        this.player_x_game_board[player].some((row, row_i) => {
+            row.some((col, col_i) => {
+                if ( isShipCell(col.render) ) {
+                    cells.push([row_i, col_i])
+                }
+            })
+        })
+        return cells
+    }
+
+    /**
+     * If there is a winner, this will return the Player that won.
+     * If no winner has been decided yet, will return undefined.
+     * @return {string|undefined}
+     */
+    get_winner() {
+        const [player_1, player_2] = this.players
+
+        // Make sure to sink any fully-damaged ships
+        this._sink_damaged_ships(player_1)
+        const player_1_ship_cells = this.get_ship_cells(player_1)
+        const player_1_loses = (
+            (player_1_ship_cells.length > 0)
+            && player_1_ship_cells.every(cell => this._get_cell_state(player_1, cell[0], cell[1]).render === GridCellState.Sunk)
+        )
+        if ( player_1_loses ) return player_2
+
+        // Make sure to sink any fully-damaged ships
+        this._sink_damaged_ships(player_2)
+        const player_2_ship_cells = this.get_ship_cells(player_2)
+        const player_2_loses = (
+            (player_2_ship_cells.length > 0)
+            && player_2_ship_cells.every(cell => this._get_cell_state(player_2, cell[0], cell[1]).render === GridCellState.Sunk)
+        )
+        if ( player_2_loses ) return player_2
+    }
+
+    /**
+     * Returns the other player.
+     * @param {string} player
+     * @return {string}
+     */
+    get_other_player(player) {
+        if ( player === Player.One ) return Player.Two
+        else if ( player === Player.Two ) return Player.One
+    }
+
+    /**
+     * Given a Player type, return the display value of that player.
+     * @param {string} player
+     * @return {string}
+     */
+    get_player_display(player) {
+        if ( player === Player.One ) return 'Player 1'
+        else if ( player === Player.Two ) return 'Player 2'
+    }
+
+    /**
+     * Get an array of ship entities for the given player.
+     * @param {string} player
+     * @return {object[]}
+     */
+    get_ship_entities(player) {
+        return clone(this.player_x_ships[player])
+    }
+
+    /**
+     * Build an empty structure of grid cells.
+     * @return {object[][]}
+     * @private
+     */
+    _build_empty_board() {
+        return Array(this.n_rows).fill('').map(_ => {
+            return Array(this.n_cols).fill('').map(_ => {
+                return {
+                    render: GridCellState.Available,
+                }
+            })
+        })
+    }
+
+    /**
+     * Set the state of the cell at the given coordinates on the player's board
+     * to the specified state.
+     * @param {string} player
+     * @param {number} row_i
+     * @param {number} col_i
+     * @param {string} state
+     * @private
+     */
+    _set_cell_state(player, row_i, col_i, state) {
+        this.player_x_game_board[player][row_i][col_i].render = state
+    }
+
+    /**
+     * Get the state of the cell at the given coordinates on the player's board.
+     * @param {string} player
+     * @param {number} row_i
+     * @param {number} col_i
+     * @return {object}
+     * @private
+     */
+    _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
+// To use the game state service, you should do:
+// import game_service from './services/GameState.service.js'
+const game_service = new GameStateService()
+export default game_service
+
+
+
+ + + + +
+ + + +
+ +
+ Documentation generated by JSDoc 3.6.5 on Sat Sep 12 2020 16:40:09 GMT-0500 (Central Daylight Time) +
+ + + + + diff --git a/documentation/generated/styles/jsdoc-default.css b/documentation/generated/styles/jsdoc-default.css new file mode 100644 index 0000000..7d1729d --- /dev/null +++ b/documentation/generated/styles/jsdoc-default.css @@ -0,0 +1,358 @@ +@font-face { + font-family: 'Open Sans'; + font-weight: normal; + font-style: normal; + src: url('../fonts/OpenSans-Regular-webfont.eot'); + src: + local('Open Sans'), + local('OpenSans'), + url('../fonts/OpenSans-Regular-webfont.eot?#iefix') format('embedded-opentype'), + url('../fonts/OpenSans-Regular-webfont.woff') format('woff'), + url('../fonts/OpenSans-Regular-webfont.svg#open_sansregular') format('svg'); +} + +@font-face { + font-family: 'Open Sans Light'; + font-weight: normal; + font-style: normal; + src: url('../fonts/OpenSans-Light-webfont.eot'); + src: + local('Open Sans Light'), + local('OpenSans Light'), + url('../fonts/OpenSans-Light-webfont.eot?#iefix') format('embedded-opentype'), + url('../fonts/OpenSans-Light-webfont.woff') format('woff'), + url('../fonts/OpenSans-Light-webfont.svg#open_sanslight') format('svg'); +} + +html +{ + overflow: auto; + background-color: #fff; + font-size: 14px; +} + +body +{ + font-family: 'Open Sans', sans-serif; + line-height: 1.5; + color: #4d4e53; + background-color: white; +} + +a, a:visited, a:active { + color: #0095dd; + text-decoration: none; +} + +a:hover { + text-decoration: underline; +} + +header +{ + display: block; + padding: 0px 4px; +} + +tt, code, kbd, samp { + font-family: Consolas, Monaco, 'Andale Mono', monospace; +} + +.class-description { + font-size: 130%; + line-height: 140%; + margin-bottom: 1em; + margin-top: 1em; +} + +.class-description:empty { + margin: 0; +} + +#main { + float: left; + width: 70%; +} + +article dl { + margin-bottom: 40px; +} + +article img { + max-width: 100%; +} + +section +{ + display: block; + background-color: #fff; + padding: 12px 24px; + border-bottom: 1px solid #ccc; + margin-right: 30px; +} + +.variation { + display: none; +} + +.signature-attributes { + font-size: 60%; + color: #aaa; + font-style: italic; + font-weight: lighter; +} + +nav +{ + display: block; + float: right; + margin-top: 28px; + width: 30%; + box-sizing: border-box; + border-left: 1px solid #ccc; + padding-left: 16px; +} + +nav ul { + font-family: 'Lucida Grande', 'Lucida Sans Unicode', arial, sans-serif; + font-size: 100%; + line-height: 17px; + padding: 0; + margin: 0; + list-style-type: none; +} + +nav ul a, nav ul a:visited, nav ul a:active { + font-family: Consolas, Monaco, 'Andale Mono', monospace; + line-height: 18px; + color: #4D4E53; +} + +nav h3 { + margin-top: 12px; +} + +nav li { + margin-top: 6px; +} + +footer { + display: block; + padding: 6px; + margin-top: 12px; + font-style: italic; + font-size: 90%; +} + +h1, h2, h3, h4 { + font-weight: 200; + margin: 0; +} + +h1 +{ + font-family: 'Open Sans Light', sans-serif; + font-size: 48px; + letter-spacing: -2px; + margin: 12px 24px 20px; +} + +h2, h3.subsection-title +{ + font-size: 30px; + font-weight: 700; + letter-spacing: -1px; + margin-bottom: 12px; +} + +h3 +{ + font-size: 24px; + letter-spacing: -0.5px; + margin-bottom: 12px; +} + +h4 +{ + font-size: 18px; + letter-spacing: -0.33px; + margin-bottom: 12px; + color: #4d4e53; +} + +h5, .container-overview .subsection-title +{ + font-size: 120%; + font-weight: bold; + letter-spacing: -0.01em; + margin: 8px 0 3px 0; +} + +h6 +{ + font-size: 100%; + letter-spacing: -0.01em; + margin: 6px 0 3px 0; + font-style: italic; +} + +table +{ + border-spacing: 0; + border: 0; + border-collapse: collapse; +} + +td, th +{ + border: 1px solid #ddd; + margin: 0px; + text-align: left; + vertical-align: top; + padding: 4px 6px; + display: table-cell; +} + +thead tr +{ + background-color: #ddd; + font-weight: bold; +} + +th { border-right: 1px solid #aaa; } +tr > th:last-child { border-right: 1px solid #ddd; } + +.ancestors, .attribs { color: #999; } +.ancestors a, .attribs a +{ + color: #999 !important; + text-decoration: none; +} + +.clear +{ + clear: both; +} + +.important +{ + font-weight: bold; + color: #950B02; +} + +.yes-def { + text-indent: -1000px; +} + +.type-signature { + color: #aaa; +} + +.name, .signature { + font-family: Consolas, Monaco, 'Andale Mono', monospace; +} + +.details { margin-top: 14px; border-left: 2px solid #DDD; } +.details dt { width: 120px; float: left; padding-left: 10px; padding-top: 6px; } +.details dd { margin-left: 70px; } +.details ul { margin: 0; } +.details ul { list-style-type: none; } +.details li { margin-left: 30px; padding-top: 6px; } +.details pre.prettyprint { margin: 0 } +.details .object-value { padding-top: 0; } + +.description { + margin-bottom: 1em; + margin-top: 1em; +} + +.code-caption +{ + font-style: italic; + font-size: 107%; + margin: 0; +} + +.source +{ + border: 1px solid #ddd; + width: 80%; + overflow: auto; +} + +.prettyprint.source { + width: inherit; +} + +.source code +{ + font-size: 100%; + line-height: 18px; + display: block; + padding: 4px 12px; + margin: 0; + background-color: #fff; + color: #4D4E53; +} + +.prettyprint code span.line +{ + display: inline-block; +} + +.prettyprint.linenums +{ + padding-left: 70px; + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; +} + +.prettyprint.linenums ol +{ + padding-left: 0; +} + +.prettyprint.linenums li +{ + border-left: 3px #ddd solid; +} + +.prettyprint.linenums li.selected, +.prettyprint.linenums li.selected * +{ + background-color: lightyellow; +} + +.prettyprint.linenums li * +{ + -webkit-user-select: text; + -moz-user-select: text; + -ms-user-select: text; + user-select: text; +} + +.params .name, .props .name, .name code { + color: #4D4E53; + font-family: Consolas, Monaco, 'Andale Mono', monospace; + font-size: 100%; +} + +.params td.description > p:first-child, +.props td.description > p:first-child +{ + margin-top: 0; + padding-top: 0; +} + +.params td.description > p:last-child, +.props td.description > p:last-child +{ + margin-bottom: 0; + padding-bottom: 0; +} + +.disabled { + color: #454545; +} diff --git a/documentation/generated/styles/prettify-jsdoc.css b/documentation/generated/styles/prettify-jsdoc.css new file mode 100644 index 0000000..5a2526e --- /dev/null +++ b/documentation/generated/styles/prettify-jsdoc.css @@ -0,0 +1,111 @@ +/* JSDoc prettify.js theme */ + +/* plain text */ +.pln { + color: #000000; + font-weight: normal; + font-style: normal; +} + +/* string content */ +.str { + color: #006400; + font-weight: normal; + font-style: normal; +} + +/* a keyword */ +.kwd { + color: #000000; + font-weight: bold; + font-style: normal; +} + +/* a comment */ +.com { + font-weight: normal; + font-style: italic; +} + +/* a type name */ +.typ { + color: #000000; + font-weight: normal; + font-style: normal; +} + +/* a literal value */ +.lit { + color: #006400; + font-weight: normal; + font-style: normal; +} + +/* punctuation */ +.pun { + color: #000000; + font-weight: bold; + font-style: normal; +} + +/* lisp open bracket */ +.opn { + color: #000000; + font-weight: bold; + font-style: normal; +} + +/* lisp close bracket */ +.clo { + color: #000000; + font-weight: bold; + font-style: normal; +} + +/* a markup tag name */ +.tag { + color: #006400; + font-weight: normal; + font-style: normal; +} + +/* a markup attribute name */ +.atn { + color: #006400; + font-weight: normal; + font-style: normal; +} + +/* a markup attribute value */ +.atv { + color: #006400; + font-weight: normal; + font-style: normal; +} + +/* a declaration */ +.dec { + color: #000000; + font-weight: bold; + font-style: normal; +} + +/* a variable name */ +.var { + color: #000000; + font-weight: normal; + font-style: normal; +} + +/* a function name */ +.fun { + color: #000000; + font-weight: bold; + font-style: normal; +} + +/* Specify class=linenums on a pre to get line numbering */ +ol.linenums { + margin-top: 0; + margin-bottom: 0; +} diff --git a/documentation/generated/styles/prettify-tomorrow.css b/documentation/generated/styles/prettify-tomorrow.css new file mode 100644 index 0000000..b6f92a7 --- /dev/null +++ b/documentation/generated/styles/prettify-tomorrow.css @@ -0,0 +1,132 @@ +/* Tomorrow Theme */ +/* Original theme - https://github.com/chriskempson/tomorrow-theme */ +/* Pretty printing styles. Used with prettify.js. */ +/* SPAN elements with the classes below are added by prettyprint. */ +/* plain text */ +.pln { + color: #4d4d4c; } + +@media screen { + /* string content */ + .str { + color: #718c00; } + + /* a keyword */ + .kwd { + color: #8959a8; } + + /* a comment */ + .com { + color: #8e908c; } + + /* a type name */ + .typ { + color: #4271ae; } + + /* a literal value */ + .lit { + color: #f5871f; } + + /* punctuation */ + .pun { + color: #4d4d4c; } + + /* lisp open bracket */ + .opn { + color: #4d4d4c; } + + /* lisp close bracket */ + .clo { + color: #4d4d4c; } + + /* a markup tag name */ + .tag { + color: #c82829; } + + /* a markup attribute name */ + .atn { + color: #f5871f; } + + /* a markup attribute value */ + .atv { + color: #3e999f; } + + /* a declaration */ + .dec { + color: #f5871f; } + + /* a variable name */ + .var { + color: #c82829; } + + /* a function name */ + .fun { + color: #4271ae; } } +/* Use higher contrast and text-weight for printable form. */ +@media print, projection { + .str { + color: #060; } + + .kwd { + color: #006; + font-weight: bold; } + + .com { + color: #600; + font-style: italic; } + + .typ { + color: #404; + font-weight: bold; } + + .lit { + color: #044; } + + .pun, .opn, .clo { + color: #440; } + + .tag { + color: #006; + font-weight: bold; } + + .atn { + color: #404; } + + .atv { + color: #060; } } +/* Style */ +/* +pre.prettyprint { + background: white; + font-family: Consolas, Monaco, 'Andale Mono', monospace; + font-size: 12px; + line-height: 1.5; + border: 1px solid #ccc; + padding: 10px; } +*/ + +/* Specify class=linenums on a pre to get line numbering */ +ol.linenums { + margin-top: 0; + margin-bottom: 0; } + +/* IE indents via margin-left */ +li.L0, +li.L1, +li.L2, +li.L3, +li.L4, +li.L5, +li.L6, +li.L7, +li.L8, +li.L9 { + /* */ } + +/* Alternate shading for lines */ +li.L1, +li.L3, +li.L5, +li.L7, +li.L9 { + /* */ } diff --git a/documentation/package.json b/documentation/package.json new file mode 100644 index 0000000..3c87a6b --- /dev/null +++ b/documentation/package.json @@ -0,0 +1,9 @@ +{ + "name": "eecs448-project-1", + "version": "0.1.0", + "main": "index.js", + "license": "MIT", + "dependencies": { + "jsdoc": "^3.6.5" + } +} diff --git a/documentation/yarn.lock b/documentation/yarn.lock new file mode 100644 index 0000000..9419e2c --- /dev/null +++ b/documentation/yarn.lock @@ -0,0 +1,156 @@ +# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. +# yarn lockfile v1 + + +"@babel/parser@^7.9.4": + version "7.11.5" + resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.11.5.tgz#c7ff6303df71080ec7a4f5b8c003c58f1cf51037" + integrity sha512-X9rD8qqm695vgmeaQ4fvz/o3+Wk4ZzQvSHkDBgpYKxpD4qTAUm88ZKtHkVqIOsYFFbIQ6wQYhC6q7pjqVK0E0Q== + +argparse@^1.0.7: + version "1.0.10" + resolved "https://registry.yarnpkg.com/argparse/-/argparse-1.0.10.tgz#bcd6791ea5ae09725e17e5ad988134cd40b3d911" + integrity sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg== + dependencies: + sprintf-js "~1.0.2" + +bluebird@^3.7.2: + version "3.7.2" + resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-3.7.2.tgz#9f229c15be272454ffa973ace0dbee79a1b0c36f" + integrity sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg== + +catharsis@^0.8.11: + version "0.8.11" + resolved "https://registry.yarnpkg.com/catharsis/-/catharsis-0.8.11.tgz#d0eb3d2b82b7da7a3ce2efb1a7b00becc6643468" + integrity sha512-a+xUyMV7hD1BrDQA/3iPV7oc+6W26BgVJO05PGEoatMyIuPScQKsde6i3YorWX1qs+AZjnJ18NqdKoCtKiNh1g== + dependencies: + lodash "^4.17.14" + +entities@~2.0.0: + version "2.0.3" + resolved "https://registry.yarnpkg.com/entities/-/entities-2.0.3.tgz#5c487e5742ab93c15abb5da22759b8590ec03b7f" + integrity sha512-MyoZ0jgnLvB2X3Lg5HqpFmn1kybDiIfEQmKzTb5apr51Rb+T3KdmMiqa70T+bhGnyv7bQ6WMj2QMHpGMmlrUYQ== + +escape-string-regexp@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz#a30304e99daa32e23b2fd20f51babd07cffca344" + integrity sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w== + +graceful-fs@^4.1.9: + version "4.2.4" + resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.4.tgz#2256bde14d3632958c465ebc96dc467ca07a29fb" + integrity sha512-WjKPNJF79dtJAVniUlGGWHYGz2jWxT6VhN/4m1NdkbZ2nOsEF+cI1Edgql5zCRhs/VsQYRvrXctxktVXZUkixw== + +js2xmlparser@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/js2xmlparser/-/js2xmlparser-4.0.1.tgz#670ef71bc5661f089cc90481b99a05a1227ae3bd" + integrity sha512-KrPTolcw6RocpYjdC7pL7v62e55q7qOMHvLX1UCLc5AAS8qeJ6nukarEJAF2KL2PZxlbGueEbINqZR2bDe/gUw== + dependencies: + xmlcreate "^2.0.3" + +jsdoc@^3.6.5: + version "3.6.5" + resolved "https://registry.yarnpkg.com/jsdoc/-/jsdoc-3.6.5.tgz#e004372ca6f2dcdf19b3d2ebcd7c725528485502" + integrity sha512-SbY+i9ONuxSK35cgVHaI8O9senTE4CDYAmGSDJ5l3+sfe62Ff4gy96osy6OW84t4K4A8iGnMrlRrsSItSNp3RQ== + dependencies: + "@babel/parser" "^7.9.4" + bluebird "^3.7.2" + catharsis "^0.8.11" + escape-string-regexp "^2.0.0" + js2xmlparser "^4.0.1" + klaw "^3.0.0" + markdown-it "^10.0.0" + markdown-it-anchor "^5.2.7" + marked "^0.8.2" + mkdirp "^1.0.4" + requizzle "^0.2.3" + strip-json-comments "^3.1.0" + taffydb "2.6.2" + underscore "~1.10.2" + +klaw@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/klaw/-/klaw-3.0.0.tgz#b11bec9cf2492f06756d6e809ab73a2910259146" + integrity sha512-0Fo5oir+O9jnXu5EefYbVK+mHMBeEVEy2cmctR1O1NECcCkPRreJKrS6Qt/j3KC2C148Dfo9i3pCmCMsdqGr0g== + dependencies: + graceful-fs "^4.1.9" + +linkify-it@^2.0.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/linkify-it/-/linkify-it-2.2.0.tgz#e3b54697e78bf915c70a38acd78fd09e0058b1cf" + integrity sha512-GnAl/knGn+i1U/wjBz3akz2stz+HrHLsxMwHQGofCDfPvlf+gDKN58UtfmUquTY4/MXeE2x7k19KQmeoZi94Iw== + dependencies: + uc.micro "^1.0.1" + +lodash@^4.17.14: + version "4.17.20" + resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.20.tgz#b44a9b6297bcb698f1c51a3545a2b3b368d59c52" + integrity sha512-PlhdFcillOINfeV7Ni6oF1TAEayyZBoZ8bcshTHqOYJYlrqzRK5hagpagky5o4HfCzzd1TRkXPMFq6cKk9rGmA== + +markdown-it-anchor@^5.2.7: + version "5.3.0" + resolved "https://registry.yarnpkg.com/markdown-it-anchor/-/markdown-it-anchor-5.3.0.tgz#d549acd64856a8ecd1bea58365ef385effbac744" + integrity sha512-/V1MnLL/rgJ3jkMWo84UR+K+jF1cxNG1a+KwqeXqTIJ+jtA8aWSHuigx8lTzauiIjBDbwF3NcWQMotd0Dm39jA== + +markdown-it@^10.0.0: + version "10.0.0" + resolved "https://registry.yarnpkg.com/markdown-it/-/markdown-it-10.0.0.tgz#abfc64f141b1722d663402044e43927f1f50a8dc" + integrity sha512-YWOP1j7UbDNz+TumYP1kpwnP0aEa711cJjrAQrzd0UXlbJfc5aAq0F/PZHjiioqDC1NKgvIMX+o+9Bk7yuM2dg== + dependencies: + argparse "^1.0.7" + entities "~2.0.0" + linkify-it "^2.0.0" + mdurl "^1.0.1" + uc.micro "^1.0.5" + +marked@^0.8.2: + version "0.8.2" + resolved "https://registry.yarnpkg.com/marked/-/marked-0.8.2.tgz#4faad28d26ede351a7a1aaa5fec67915c869e355" + integrity sha512-EGwzEeCcLniFX51DhTpmTom+dSA/MG/OBUDjnWtHbEnjAH180VzUeAw+oE4+Zv+CoYBWyRlYOTR0N8SO9R1PVw== + +mdurl@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/mdurl/-/mdurl-1.0.1.tgz#fe85b2ec75a59037f2adfec100fd6c601761152e" + integrity sha1-/oWy7HWlkDfyrf7BAP1sYBdhFS4= + +mkdirp@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-1.0.4.tgz#3eb5ed62622756d79a5f0e2a221dfebad75c2f7e" + integrity sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw== + +requizzle@^0.2.3: + version "0.2.3" + resolved "https://registry.yarnpkg.com/requizzle/-/requizzle-0.2.3.tgz#4675c90aacafb2c036bd39ba2daa4a1cb777fded" + integrity sha512-YanoyJjykPxGHii0fZP0uUPEXpvqfBDxWV7s6GKAiiOsiqhX6vHNyW3Qzdmqp/iq/ExbhaGbVrjB4ruEVSM4GQ== + dependencies: + lodash "^4.17.14" + +sprintf-js@~1.0.2: + version "1.0.3" + resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c" + integrity sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw= + +strip-json-comments@^3.1.0: + version "3.1.1" + resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-3.1.1.tgz#31f1281b3832630434831c310c01cccda8cbe006" + integrity sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig== + +taffydb@2.6.2: + version "2.6.2" + resolved "https://registry.yarnpkg.com/taffydb/-/taffydb-2.6.2.tgz#7cbcb64b5a141b6a2efc2c5d2c67b4e150b2a268" + integrity sha1-fLy2S1oUG2ou/CxdLGe04VCyomg= + +uc.micro@^1.0.1, uc.micro@^1.0.5: + version "1.0.6" + resolved "https://registry.yarnpkg.com/uc.micro/-/uc.micro-1.0.6.tgz#9c411a802a409a91fc6cf74081baba34b24499ac" + integrity sha512-8Y75pvTYkLJW2hWQHXxoqRgV7qb9B+9vFEtidML+7koHUFapnVJAZ6cKs+Qjz5Aw3aZWHMC6u0wJE3At+nSGwA== + +underscore@~1.10.2: + version "1.10.2" + resolved "https://registry.yarnpkg.com/underscore/-/underscore-1.10.2.tgz#73d6aa3668f3188e4adb0f1943bd12cfd7efaaaf" + integrity sha512-N4P+Q/BuyuEKFJ43B9gYuOj4TQUHXX+j2FqguVOpjkssLUUrnJofCcBccJSCoeturDoZU6GorDTHSvUDlSQbTg== + +xmlcreate@^2.0.3: + version "2.0.3" + resolved "https://registry.yarnpkg.com/xmlcreate/-/xmlcreate-2.0.3.tgz#df9ecd518fd3890ab3548e1b811d040614993497" + integrity sha512-HgS+X6zAztGa9zIK3Y3LXuJes33Lz9x+YyTxgrkIdabu2vqcGOWwdfCpf1hWLRrd553wd4QCDf6BBO6FfdsRiQ== diff --git a/lib/README.md b/lib/README.md index 6dad6e9..f2e29d8 100644 --- a/lib/README.md +++ b/lib/README.md @@ -7,5 +7,4 @@ The files in this directory are external libraries used in this project. - A kind-of crappy loader for defining Vue components using ES6 classes. - Also used under the terms of the MIT license. - https://code.garrettmills.dev/garrettmills/vues6 - -Sound effects obtained from https://www.zapsplat.com \ No newline at end of file +- Sound effects obtained from https://www.zapsplat.com \ No newline at end of file diff --git a/src/components/GameBoard.component.js b/src/components/GameBoard.component.js index ec91552..5a67734 100644 --- a/src/components/GameBoard.component.js +++ b/src/components/GameBoard.component.js @@ -39,7 +39,12 @@ const template = ` ` -export default class GameBoardComponent extends Component { + +/** + * A component which represents a single, programmable game board. + * @extends Component + */ +class GameBoardComponent extends Component { static get selector() { return 'app-game-board' } static get template() { return template } static get props() { return ['rows', 'is_placement_mode', 'ships_to_place', 'is_missile_mode'] } @@ -60,7 +65,7 @@ export default class GameBoardComponent extends Component { /** * Array of coordinates as [row_index, column_index] of cells which should * show a ghost ship overlay. - * @type {[number, number][]} + * @type {number[]} */ ship_ghost_cells = [] @@ -83,6 +88,10 @@ export default class GameBoardComponent extends Component { */ bound_fns = [] + /** + * Called when the component is initialized. + * @return {Promise} + */ async vue_on_create() { this.ready = true @@ -96,6 +105,10 @@ export default class GameBoardComponent extends Component { window.addEventListener('keydown', keydown_fn) } + /** + * Called when the component is destroyed. + * @return {Promise} + */ async vue_on_destroy() { // Remove the event listeners for the shift key const [keyup_fn, keydown_fn] = this.bound_fns @@ -103,6 +116,12 @@ export default class GameBoardComponent extends Component { window.removeEventListener('keydown', keydown_fn) } + /** + * Called when a user clicks a cell. If in placement mode, will attempt to place + * a ship. If in missile mode, will attempt to fire a missile. + * @param {number} row_i - the index of the row + * @param {number} cell_i - the index of the cell + */ on_cell_click(row_i, cell_i) { if ( this.is_placement_mode && this.ships_to_place[0] ) { // We should try to place a ship here @@ -213,3 +232,5 @@ export default class GameBoardComponent extends Component { } } } + +export default GameBoardComponent diff --git a/src/components/GridCell.component.js b/src/components/GridCell.component.js index 74f6d35..f2e5bd3 100644 --- a/src/components/GridCell.component.js +++ b/src/components/GridCell.component.js @@ -14,7 +14,12 @@ const template = ` ` -export default class GridCellComponent extends Component { + +/** + * A component which represents a single, programmable grid cell. + * @extends Component + */ +class GridCellComponent extends Component { static get selector() { return 'app-game-cell' } static get template() { return template } @@ -29,15 +34,27 @@ export default class GridCellComponent extends Component { /** Make the "GridCellState" enum available in the template. */ GridCellState = GridCellState + /** + * Fire a click event. + */ on_click() { this.$emit('click') } + /** + * Fire a hover event. + * @param $event + */ on_hover($event) { this.$emit('hover', $event) } + /** + * Fire a "hoverchange" event. + */ on_mouse_leave() { this.$emit('hoverchange') } } + +export default GridCellComponent diff --git a/src/components/ScoreBoard.component.js b/src/components/ScoreBoard.component.js index 811733c..04deee7 100644 --- a/src/components/ScoreBoard.component.js +++ b/src/components/ScoreBoard.component.js @@ -27,20 +27,58 @@ const template = ` ` -export default class ScoreBoardComponent extends Component { + +/** + * A component which represents the programmable scoreboard. + * @extends Component + */ +class ScoreBoardComponent extends Component { static get selector() { return 'app-scoreboard' } static get template() { return template } static get props() { return [] } + /** + * The score of player one. + * @type {number} + */ player_one_score = 0 + + /** + * The score of player two. + * @type {number} + */ player_two_score = 0 + + /** + * The progress of player one, as a decimal. + * @type {number} + */ player_one_progress = 0 + + /** + * The progress of player two, as a decimal. + * @type {number} + */ player_two_progress = 0 + + /** + * The current player. + * @type {string|undefined} + */ current_player = undefined + + /** + * The winning player. + * @type {string|undefined} + */ winning_player = undefined Player = Player + /** + * Called when the component is initialized. + * @return {Promise} + */ async vue_on_create() { game_service.on_state_change(() => { this.update() @@ -49,6 +87,9 @@ export default class ScoreBoardComponent extends Component { this.update() } + /** + * Fetch new data from the game service. + */ 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) @@ -64,3 +105,5 @@ export default class ScoreBoardComponent extends Component { } } } + +export default ScoreBoardComponent diff --git a/src/components/TopLevel.component.js b/src/components/TopLevel.component.js index 7b450ea..bcc16a6 100644 --- a/src/components/TopLevel.component.js +++ b/src/components/TopLevel.component.js @@ -80,7 +80,12 @@ const template = ` ` -export default class TopLevelComponent extends Component { + +/** + * Top-level component which manages the display of the entire game. + * @extends Component + */ +class TopLevelComponent extends Component { static get selector() { return 'app-top-level' } static get template() { return template } static get props() { return [] } @@ -145,8 +150,11 @@ export default class TopLevelComponent extends Component { */ current_opponent_display = '' + /** + * Called when the component is initialized. + * @return {Promise} + */ async vue_on_create() { - console.log('game service', game_service) this.current_state = game_service.get_game_state() // Called every time the game state is updated @@ -221,3 +229,5 @@ export default class TopLevelComponent extends Component { game_service.advance_game_state() } } + +export default TopLevelComponent diff --git a/src/module/errors.js b/src/module/errors.js index 3db0685..b52e7fa 100644 --- a/src/module/errors.js +++ b/src/module/errors.js @@ -1,3 +1,5 @@ +/** @module errors */ + /** * Placeholder class for an error that is thrown when a ship is placed * in an invalid position. diff --git a/src/module/lang.js b/src/module/lang.js index 08ab92b..d743fd2 100644 --- a/src/module/lang.js +++ b/src/module/lang.js @@ -1,3 +1,5 @@ +/** @module lang **/ + import { GameState } from './util.js' /** diff --git a/src/module/sounds.js b/src/module/sounds.js index a094de7..a4cff3a 100644 --- a/src/module/sounds.js +++ b/src/module/sounds.js @@ -1,3 +1,5 @@ +/** @module sounds */ + import { appUrl } from './util.js' /** @@ -42,6 +44,10 @@ class Sound { } } +/** + * Enum of the various sound effects available in the game. + * @type {object} + */ const GameSounds = { Victory: new Sound(appUrl('/lib/sounds/cartoon_success_fanfair.mp3')), Fire: new Sound(appUrl('/lib/sounds/zapsplat_warfare_mortar_projectile_launch_002_25232.mp3')), @@ -49,6 +55,4 @@ const GameSounds = { Miss: new Sound(appUrl('/lib/sounds/zapsplat_nature_water_pour_medium_amount_deep_sudden_fast_002_52765.mp3')), } -console.log(GameSounds) - export { GameSounds } diff --git a/src/module/util.js b/src/module/util.js index bd6ffe5..06e28a5 100644 --- a/src/module/util.js +++ b/src/module/util.js @@ -1,3 +1,5 @@ +/** @module util */ + /** * Enum of all possible states of a grid cell. * @type {object} diff --git a/src/services/GameState.service.js b/src/services/GameState.service.js index 0c47adb..e045cd1 100644 --- a/src/services/GameState.service.js +++ b/src/services/GameState.service.js @@ -22,7 +22,7 @@ export class GameStateService { /** * An array of all players. This is mostly for internal purposes. * @private - * @type {(string)[]} + * @type {string[]} */ players = [Player.One, Player.Two] @@ -71,7 +71,7 @@ export class GameStateService { /** * Given the number of boats set by the player (n_boats), return an array * of possible ShipTypes. - * @return {ShipType[]} + * @return {string[]} */ get_possible_boats(){ if (this.get_n_boats() === 1) { @@ -115,7 +115,7 @@ export class GameStateService { /** * If the current state is the PromptPlayerChange, then this is * the state that we should move to next. - * @type {undefined|GameState} + * @type {undefined|string} */ post_player_change_state = undefined @@ -145,7 +145,7 @@ export class GameStateService { /** * Get the dimensions of the board as [rows, cols]. * @example const [n_rows, n_cols] = game_service.get_dimensions() - * @return {[number, number]} + * @return {number[]} */ get_dimensions() { return [this.n_rows, this.n_cols] @@ -220,7 +220,7 @@ export class GameStateService { */ get_player_score(player) { let score = 0 - this.player_x_game_board[player].some(row => { + this.player_x_game_board[this.get_other_player(player)].some(row => { row.some(cell => { if ( cell.render === GridCellState.Damaged || cell.render === GridCellState.Sunk ) { score += 1 @@ -239,7 +239,7 @@ export class GameStateService { */ get_boat_count(player){ let boat_count = 0 - this.player_x_game_board[player].some(row => { + this.player_x_game_board[this.get_other_player(player)].some(row => { row.some(cell => { if ( isShipCell(cell.render) ) { boat_count += 1 @@ -266,7 +266,7 @@ export class GameStateService { /** * Get the current game state. - * @return {GameState} + * @return {string} */ get_game_state() { return clone(this.current_state) @@ -275,7 +275,6 @@ export class GameStateService { /** * responsible for advancing the game state * will be consisting of - * @return */ advance_game_state() { /** functions to be made that validate: @@ -383,7 +382,7 @@ export class GameStateService { * If I want to fire a missile at row 5 column 7, then: * game_service.attempt_missile_fire([5, 7]) * - * @param {[number, number]} coords + * @param {number[]} coords * @return {boolean} */ attempt_missile_fire([target_row_i, target_col_i]) { @@ -419,7 +418,7 @@ export class GameStateService { /** * Checks the player's ships. If any are fully damaged, it flags that ship's cells * as "sunk" rather than damaged. - * @param {Player} player + * @param {string} player * @private */ _sink_damaged_ships(player) { @@ -448,9 +447,9 @@ export class GameStateService { * to row 3 column 4, then I would call: * game_service.place_ship(ShipType.x3, [3,2], [3,4]) * - * @param {ShipType} ship_type - * @param {[number, number]} coords_one - * @param {[number, number]} coords_two + * @param {string} ship_type + * @param {number[]} coords_one + * @param {number[]} coords_two */ place_ship(ship_type, coords_one, coords_two) { // make sure the coordinates are valid for the given ship type @@ -490,9 +489,9 @@ export class GameStateService { * game_service.get_covered_cells([1,1], [4,1]) * Which would return [[1,1], [2,1], [3,1], [4,1]]. * - * @param {[number, number]} coords_one - * @param {[number, number]} coords_two - * @return {[number, number][]} + * @param {number[]} coords_one + * @param {number[]} coords_two + * @return {number[][]} */ get_covered_cells(coords_one, coords_two) { const [row_one, col_one] = coords_one @@ -522,9 +521,9 @@ export class GameStateService { * to row 3 column 4, then I would call: * game_service.validate_coordinates(ShipType.x3, [3,2], [3,4]) * - * @param {ShipType} ship_type - * @param {[number, number]} coords_one - * @param {[number, number]} coords_two + * @param {string} ship_type + * @param {number[]} coords_one + * @param {number[]} coords_two */ validate_coordinates(ship_type, coords_one, coords_two) { if ( !isShipType(ship_type) ) throw new InvalidShipPlacementError('Invalid ship type: '+ship_type) @@ -570,7 +569,7 @@ export class GameStateService { /** * Get the number of cells the given ship type should occupy. - * @param {ShipType} ship_type + * @param {string} ship_type * @return {number} */ get_ship_length(ship_type) { @@ -583,8 +582,8 @@ export class GameStateService { /** * Get the coordinates of all cells that have ships in them, for the given player. - * @param {Player} player - * @return {[number, number]} + * @param {string} player + * @return {number[]} */ get_ship_cells(player) { const cells = [] @@ -601,7 +600,7 @@ export class GameStateService { /** * If there is a winner, this will return the Player that won. * If no winner has been decided yet, will return undefined. - * @return {Player|undefined} + * @return {string|undefined} */ get_winner() { const [player_1, player_2] = this.players @@ -622,13 +621,13 @@ export class GameStateService { (player_2_ship_cells.length > 0) && player_2_ship_cells.every(cell => this._get_cell_state(player_2, cell[0], cell[1]).render === GridCellState.Sunk) ) - if ( player_2_loses ) return player_2 + if ( player_2_loses ) return player_1 } /** * Returns the other player. - * @param {Player} player - * @return {Player} + * @param {string} player + * @return {string} */ get_other_player(player) { if ( player === Player.One ) return Player.Two @@ -637,7 +636,7 @@ export class GameStateService { /** * Given a Player type, return the display value of that player. - * @param {Player} player + * @param {string} player * @return {string} */ get_player_display(player) { @@ -647,7 +646,7 @@ export class GameStateService { /** * Get an array of ship entities for the given player. - * @param {Player} player + * @param {string} player * @return {object[]} */ get_ship_entities(player) { @@ -672,10 +671,10 @@ export class GameStateService { /** * Set the state of the cell at the given coordinates on the player's board * to the specified state. - * @param {Player} player + * @param {string} player * @param {number} row_i * @param {number} col_i - * @param {GridCellState} state + * @param {string} state * @private */ _set_cell_state(player, row_i, col_i, state) { @@ -684,7 +683,7 @@ export class GameStateService { /** * Get the state of the cell at the given coordinates on the player's board. - * @param {Player} player + * @param {string} player * @param {number} row_i * @param {number} col_i * @return {object}