Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- // Import the game logic script from the root file
- importScripts('gamelogic.js');
- /**
- * On a message event as running via web worker.
- * @param {Object} event The event details
- * @param {Array} event.data The array of data sent with the request
- * @param {String} event.data[0] The event command
- * @param {String} event.data[1] The game board
- * @param {Object} event.data[2] The Human users ships
- * @param {Double} event.data[3] The AI Skill level
- * @param {Boolean} event.data[4] Whether it is the first game or not
- */
- onmessage = function(event) {
- // Extract the command and parameters
- let command = event.data[0];
- let board = event.data[1], ships = event.data[2], skillLevel = event.data[3], firstGame = event.data[4];
- // Switch the command that was sent
- switch(command) {
- // Move command requested
- case 'move':
- // Get and post the move back to the main thread
- //setTimeout(function() {
- postMessage({move: aiMove(board, ships, skillLevel, firstGame)});
- //}, 350);
- break;
- // If a ship placement is requested
- case 'getBoard':
- // Post the ships back to the user
- postMessage({ships: getAIShipPlacement()});
- break;
- // Chat command requested
- case 'chat':
- // Get a chat message
- let message = aiChat(board, skillLevel, firstGame);
- // If a chat message was returned, post it
- if(message != undefined && message != '') {
- postMessage({message: message});
- }
- break;
- }
- }
- //skillLevel is the sliding scale, number between 1 and 10
- //board is the current board
- function aiMove(board, ships, skillLevel, firstGame) {
- let difficulty = skillLevel*10;
- let availableMoves;
- let move;
- let pick;
- let random;
- let huntAbility = false;
- let advancedHuntMode = false;
- let advancedSearchMode = false;
- let cheatMode = false;
- let probablity;
- switch (difficulty){
- case 0:
- //All features are false.
- break;
- case 1:
- huntAbility = true;
- probablity = 0.6;
- break;
- case 2:
- huntAbility = true;
- probablity = 0.4;
- break;
- case 3:
- huntAbility = true;
- probablity = 0.2;
- break;
- case 4:
- huntAbility = true;
- advancedSearchMode = true;
- probablity = 0.6;
- break;
- case 5:
- huntAbility = true;
- advancedSearchMode = true;
- probablity = 0.4;
- break;
- case 6:
- huntAbility = true;
- advancedSearchMode = true;
- probablity = 0.2;
- break;
- case 7:
- huntAbility = true;
- advancedSearchMode = true;
- advancedHuntMode = true;
- probablity = 0.6;
- break;
- case 8:
- huntAbility = true;
- advancedSearchMode = true;
- advancedHuntMode = true;
- probablity = 0.4;
- break;
- case 9:
- huntAbility = true;
- advancedSearchMode = true;
- advancedHuntMode = true;
- probablity = 0.2;
- break;
- case 10:
- huntAbility = true;
- advancedSearchMode = true;
- advancedHuntMode = true;
- cheatMode = true;
- probablity = 0.1
- }
- //Generate a random number between 0 and 1
- random = Math.random();
- //Determine whether to use huntAbility for levels 1 - 3.
- if(difficulty > 0 && difficulty < 4){
- if(random <= probablity){
- huntAbility = false;
- }
- }
- //Determine whether to use advanced search mode for levels 4 - 6
- if(difficulty > 3 && difficulty < 7){
- if(random <= probablity){
- advancedSearchMode = false;
- }
- }
- //Determine whether to use advanced hunt mode for levels 7 - 9
- if(difficulty > 6 && difficulty < 10){
- if(random <= probablity){
- advancedHuntMode = false;
- }
- }
- //Determine whether to use the cheat mode for level 10.
- if(cheatMode == true && random <= probablity){
- cheatMode = true;
- }
- else{
- cheatMode = false;
- }
- console.log("Difficulty: " + difficulty + " Hunt Ability: " + huntAbility + " Advanced Search Mode: " + advancedSearchMode + " Advanced Hunt Mode: " + advancedHuntMode + " Cheat Mode: " + cheatMode);
- //Determine whether there are any hits on the board, hence returning true for huntmode.
- huntMode = checkHits(board);
- //Hunt modes.
- //If the there is a hit and the AI has hunt ability activated. Begin a hunt for the ship.
- if(huntMode == true && huntAbility == true){
- //If the AI has advanced hunt mode activated, use the advanced find hit method.
- if(advancedHuntMode == true){
- move = advancedFindHits(board);
- return{row: move.row, col: move.col};
- }
- else{
- //Otherwise use the standard find hit method to return moves to randomly choose from.
- availableMoves = findHits(board);
- }
- }
- //Search modes.
- else{
- //If cheatMode is activated get an array of cheat moves.
- if(cheatMode == true){
- availableMoves = getCheatMoves(board);
- }
- //If advanced search mode is activated use the advanced get moves method.
- else if(advancedSearchMode == true){
- availableMoves = advancedGetAvailableMoves(board);
- }
- //Otherwise use the standard get moves method.
- else{
- availableMoves = getAvailableMoves(board);
- }
- }
- //Randomly pick a move from the available moves.
- pick = Math.floor(Math.random()* availableMoves.length);
- move = availableMoves[pick];
- //Return the move coordinates.
- return {row: move.row , col: move.col};
- }
- /*--------------- Search Methods ---------------*/
- //Methods to return moves for the AI to take.
- //Standard method to return an array of all the potential moves the AI can make.
- function getAvailableMoves(board){
- //Array to store move objects.
- let availableMoves = [];
- //Traverse the board to access each cell.
- for(let i = 0; i < 10; i++){
- for(let j = 0; j < 10; j++){
- //If the board position is available for a placement, push it to the moves array.
- if(board[i][j].value == 's' || board[i][j].value == ''){
- availableMoves.push({row: i, col: j});
- }
- }
- }
- return availableMoves;
- }
- //Advanced version of getAvailableMoves method.
- //This method returns availableMoves where the parity of the row and column index is the same.
- //Meaning a cross patern will be used to search the board, hence making it more likely to get a hit.
- function advancedGetAvailableMoves(board){
- //Array to store move objects.
- let availableMoves = [];
- //Traverse the board to access each cell.
- for(let i = 0; i < 10; i++){
- for(let j = 0; j < 10; j++){
- //If the row and column indexes are both even.
- if(i%2 == 0 && j%2 == 0){
- //If the board position is available for a placement, push it to the moves array.
- if(board[i][j].value == 's' || board[i][j].value == ''){
- availableMoves.push({row: i, col: j});
- }
- }
- //If the row and column indexes are both odd.
- else if(i%2 != 0 && j%2 != 0){
- //If the board position is available for a placement, push it to the moves array.
- if(board[i][j].value == 's' || board[i][j].value == ''){
- availableMoves.push({row: i, col: j});
- }
- }
- }
- }
- //Array of moves is returned.
- return availableMoves;
- }
- //Cheat Mode.
- //This method is for the top difficulty.
- //Returns all the positions with ship locations.
- function getCheatMoves(board){
- //Array to store move objects.
- let availableMoves = [];
- //Traverse the board to access each cell.
- for(let i = 0; i < 10; i++){
- for(let j = 0; j < 10; j++){
- //If there is a ship in the position, push it to the moves array.
- if(board[i][j].value == 's'){
- availableMoves.push({row: i, col: j});
- }
- }
- }
- //Array of moves is returned.
- return availableMoves;
- }
- /*--------------- Hunting Methods ---------------*/
- //Methods to determine if there is a hit, and use that information to destroy the entire ship.
- //Method to return whether it is necessary to enter hunt mode.
- function checkHits(board){
- //Traverse the board to access each cell.
- for(let i = 0; i < 10; i++){
- for(let j = 0; j < 10; j++){
- //IF there is a hit return true to begin hunt mode.
- if(board[i][j].value == 'h'){
- return true;
- }
- }
- }
- //Otherwise return false to continue search mode.
- return false;
- }
- //Method to search the cells around a hit.
- function findHits(board){
- //Array to store move objects.
- let availableMoves = [];
- //Traverse the board to access each cell.
- for(let i = 0; i < 10; i++){
- for(let j = 0; j < 10; j++){
- //If there is a hit cell, search its surounding cells.
- if(board[i][j].value == 'h'){
- //If the current row is not the top row.
- if(i != 0){
- //Check if the position above the cell is available for a move.
- if(board[i-1][j].value == '' || board[i-1][j].value == 's'){
- //Push move to array.
- availableMoves.push({row: i - 1, col: j});
- }
- }
- //If the current the row is not the bottom row.
- if(i != 9){
- //Check if the position below the cell is available for a move.
- if(board[i+1][j].value == '' || board[i+1][j].value == 's'){
- //Push move to array.
- availableMoves.push({row: i + 1, col: j});
- }
- }
- //If the current column is not the far left column.
- if(j != 0){
- //Check if the position left of the cell is available for a move.
- if(board[i][j-1].value == '' || board[i][j-1].value == 's'){
- //Push move to array.
- availableMoves.push({row: i, col: j - 1});
- }
- }
- //If the current column is not the far right column.
- if(j != 9){
- //Check if the position right of the cell is available for a move.
- if(board[i][j+1].value == '' || board[i][j+1].value == 's'){
- //Push move to array.
- availableMoves.push({row: i, col: j + 1});
- }
- }
- }
- }
- }
- //Return the array of moves.
- return availableMoves;
- }
- //Advanced find hit mode for higher difficulties - sinks ships faster than normal version.
- function advancedFindHits(board){
- let informedMoves = [];
- let vertical = false;
- let horizontal = false;
- for(let i = 0; i < 10; i++){
- for(let j = 0; j < 10; j++){
- if(board[i][j].value == 'h'){
- if(i != 0){
- if(board[i-1][j].value == 'h'){
- vertical = true;
- }
- }
- if(i != 9){
- if(board[i+1][j].value == 'h'){
- vertical = true;
- }
- }
- if(j != 0){
- if(board[i][j-1].value == 'h'){
- horizontal = true;
- }
- }
- if(j != 9){
- if(board[i][j+1].value == 'h'){
- horizontal = true;
- }
- }
- //Select a surounding cell.
- //Above.
- if(horizontal == false){
- if(i != 0){
- if(board[i-1][j].value == '' || board[i-1][j].value == 's'){
- return {row: i - 1, col: j};
- }
- if(board[i-1][j].value == 'h'){
- if(i - 1 != 0){
- if(board[i-1][j].value == '' || board[i-1][j].value == 's'){
- return {row: i - 2, col: j};
- }
- }
- }
- }
- if(i != 9){
- if(board[i+1][j].value == '' || board[i+1][j].value == 's'){
- return {row: i + 1, col: j};
- }
- if(board[i+1][j].value == 'h'){
- if(i + 1 != 9){
- if(board[i+1][j].value == '' || board[i+1][j].value == 's'){
- return {row: i + 2, col: j};
- }
- }
- }
- }
- }
- if(vertical == false){
- if(j != 0){
- if(board[i][j - 1].value == '' || board[i][j-1].value == 's'){
- return {row: i, col: j - 1};
- }
- if(board[i][j-1].value == 'h'){
- if(j - 1 != 0){
- if(board[i][j - 1].value == '' || board[i][j-1].value == 's'){
- return {row: i, col: j - 2};
- }
- }
- }
- }
- if(j != 9){
- if(board[i][j + 1].value == '' || board[i][j + 1].value == 's'){
- return {row: i, col: j + 1};
- }
- if(board[i][j+1].value == 'h'){
- if(j + 1 != 9){
- if(board[i][j + 1].value == '' || board[i][j + 1].value == 's'){
- return {row: i, col: j + 2};
- }
- }
- }
- }
- }
- }
- }
- }
- //If at this point, moves MUST BE left or right. Loop again and make these moves.
- for(let i = 0; i < 10; i++){
- for(let j = 0; j < 10; j++){
- if(board[i][j].value == 'h'){
- if(j != 0){
- if(board[i][j - 1].value == '' || board[i][j-1].value == 's'){
- return {row: i, col: j - 1};
- }
- if(board[i][j-1].value == 'h'){
- if(j - 1 != 0){
- if(board[i][j - 1].value == '' || board[i][j-1].value == 's'){
- return {row: i, col: j - 2};
- }
- }
- }
- }
- if(j != 9){
- if(board[i][j + 1].value == '' || board[i][j + 1].value == 's'){
- return {row: i, col: j + 1};
- }
- if(board[i][j+1].value == 'h'){
- if(j + 1 != 9){
- if(board[i][j + 1].value == '' || board[i][j + 1].value == 's'){
- return {row: i, col: j + 2};
- }
- }
- }
- }
- }
- }
- }
- //Should never reach this point, but return 0, 0 if is the case.
- return ({row: 0, col: 0});
- }
- // returns a board
- function getAIShipPlacement() {
- let pick;
- let directions;
- let xP;
- let yP;
- let shipLength;
- let directionLimit = 0;
- let ships = [];
- let tempBoard = [];
- for(let i=0; i<10; i++) {
- tempBoard.push([]);
- for(let j=0; j<10; j++) {
- // Push a value of the tile
- tempBoard[i].push({value: '', prevMove: '', x: i, y: j});
- }
- }
- for(let i = 0; i < 5; i++){
- switch (i){
- case 0:
- shipLength = 5;
- break;
- case 1:
- shipLength = 4;
- break;
- case 2:
- shipLength = 3;
- break;
- case 3:
- shipLength = 3;
- break;
- case 4:
- shipLength = 2;
- }
- //PICK H OR V.
- pick = Math.random();
- if(pick >= 0.5){
- console.log("Ori pick: " + pick);
- directions = 'v';
- }
- else if(pick < 0.5){
- console.log("Ori pick: " + pick);
- directions = 'h';
- }
- //do{
- if(directions = 'h'){
- xP = Math.floor(Math.random()*(10-shipLength));
- yP = Math.floor(Math.random()*10);
- }
- else{
- xP = Math.floor(Math.random()*10);
- yP = Math.floor(Math.random()*(10-shipLength));
- }
- conflictions = false;
- for(let j = 0; j < shipLength; j++) {
- if(directions == 'v') {
- // Check down
- if(xP + j <= 9){
- if(tempBoard[xP+j][yP].value == 's') {
- conflictions = true;
- }
- }
- else{
- conflictions = true;
- }
- }
- else if (directions == 'h') {
- if(yP + j <= 9){
- if(tempBoard[xP][yP+j].value == 's'){
- conflictions = true;
- }
- }
- else{
- conflictions =true;
- }
- }
- }
- }while(conflictions == true);
- for(let j = 0; j < shipLength; j++){
- if(directions = 'v'){
- tempBoard[xP + j][yP].value = 's';
- }
- else{
- tempBoard[xP][yP+j].value = 's';
- }
- }
- ships.push({length: shipLength, direction: 'h', damage: 0, destroyed: false, x: xP, y: yP});
- }
- /*
- let shipsArray = [];
- let ships = [
- {length: 5, direction: 'h', damage: 0, destroyed: false, x: 0, y: 0},
- {length: 4, direction: 'h', damage: 0, destroyed: false, x: 2, y: 0},
- {length: 3, direction: 'h', damage: 0, destroyed: false, x: 4, y: 0},
- {length: 3, direction: 'h', damage: 0, destroyed: false, x: 6, y: 0},
- {length: 2, direction: 'h', damage: 0, destroyed: false, x: 8, y: 0}
- ];*/
- /*
- shipsArray.push(ships);
- ships = [
- {length: 5, direction: 'v', damage: 0, destroyed: false, x: 0, y: 0},
- {length: 4, direction: 'v', damage: 0, destroyed: false, x: 0, y: 2},
- {length: 3, direction: 'v', damage: 0, destroyed: false, x: 0, y: 4},
- {length: 3, direction: 'v', damage: 0, destroyed: false, x: 0, y: 6},
- {length: 2, direction: 'v', damage: 0, destroyed: false, x: 0, y: 8}
- ];*/
- return ships;
- }
- /*-----------------------AI Chat Method------------------------*/
- function aiChat(board, skillLevel, firstGame){
- //Boolean if the AI has made its first move.
- //Also determine what stage of the game we are at for the AI chat feature.
- let movesMade = 0;
- for(let i=0; i<10; i++){
- for(let j=0; j<10; j++){
- if(board[i][j].value == 'm' || board[i][j].value == 'h' || board[i][j].value == 'd') {
- movesMade++;
- }
- }
- }
- //Code for AI commenting on the difficulty.
- //This code outputs to the chat when the AI makes its first move.
- if(movesMade == 0){
- let toReturn = '';
- //Potentially remove this message. - or place it somewhere so it only posts when the player chooses the AI mode.
- if(firstGame == true){
- toReturn += "Hello! I am the Battleships AI! ";
- }
- else {
- toReturn += "Another game! Lets go! ";
- }
- //Comments on the chosen difficulty.
- if(skillLevel == 1){
- toReturn += "Hardest difficulty eh? Admirable, I'm going to be very hard to beat! \
- I may have an advantage over you as well...\
- All abilities activated!";
- }
- else if(skillLevel == 0){
- toReturn += "Wow, easiest difficulty? Really? I thought you were better than this! \
- My moves will be completely random!";
- }
- else if(skillLevel < 1 && skillLevel >= 0.7){
- toReturn += "Level " + skillLevel*10 + " is a respectable difficulty! Well done! \
- Hunting Ability Activated! Advanced Search Mode Activated! Advanced Hunt Mode Activated(With potential to not work)!";
- }
- else if(skillLevel < 0.7 && skillLevel >= 0.4){
- toReturn += "Hmmm, you have chosen level " + skillLevel*10 + "? You can do better than this! \
- Hunting Ability Activated! Advanced Search Mode Activated(With potential to not work)!";
- }
- else if(skillLevel < 0.4 && skillLevel >= 0){
- toReturn += "You a beginner? Because " + skillLevel*10 + " is not a hard level! \
- Hunting Ability Activated(With potential to not work!)";
- }
- return toReturn;
- }
- else{
- let toReturn = '';
- //Code for AI commenting on the result of the game.
- /*
- //Code for the AI commenting on winning.
- if(checkWin(???)){
- toReturn += "Yes I win!! In your face ;) ";
- if(skillLevel == 1){
- toReturn += "It is the hardest difficulty, so no shame for you. ";
- }
- else if(skillLevel == 0){
- toReturn += "I beat you on the easiest difficulty as well... I wouldn't tell your friends about this... ";
- }
- toReturn += "Want to play again?";
- return toReturn;
- }
- //Code for the AI commenting on losing.
- else if(checkWin(??)){
- toReturn += "You win! Well done, but I'll get you next time... ";
- if(skillLevel != 1){
- toReturn += "Try upping the difficulty if you are confident ;) ";
- }
- toReturn += "Want to play again? ";
- return toReturn;
- }
- */
- }
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement