Gra w statki. Kod. Brak kolizji

0

Witam,
Czy jest ktoś w stanie pomóc mi w modyfikacji kodu. Głowna zasada gry mówi, że statki nie mogą dotykać się bokami ani krawędziami. Tutaj jej brakuje. Niestety programowanie nie jest moją silną stroną. Bardzo proszę o pomoc.

(function() {

// Global Constants
var CONST = {};
CONST.AVAILABLE_SHIPS = ['carrier', 'battleship', 'destroyer', 'submarine', 'patrolboat'];
// You are player 0 and the computer is player 1
// The virtual player is used for generating temporary ships
// for calculating the probability heatmap
CONST.HUMAN_PLAYER = 0;
CONST.COMPUTER_PLAYER = 1;
CONST.VIRTUAL_PLAYER = 2;
// Possible values for the parameter `type` (string)
CONST.CSS_TYPE_EMPTY = 'empty';
CONST.CSS_TYPE_SHIP = 'ship';
CONST.CSS_TYPE_MISS = 'miss';
CONST.CSS_TYPE_HIT = 'hit';
CONST.CSS_TYPE_SUNK = 'sunk';
// Grid code:
CONST.TYPE_EMPTY = 0; // 0 = water (empty)
CONST.TYPE_SHIP = 1; // 1 = undamaged ship
CONST.TYPE_MISS = 2; // 2 = water with a cannonball in it (missed shot)
CONST.TYPE_HIT = 3; // 3 = damaged ship (hit shot)
CONST.TYPE_SUNK = 4; // 4 = sunk ship

// TODO: Utwórz ten lepszy kod OO. CONST.AVAILABLE_SHIPS powinna być tablicą
// obiektów, a nie dwóch równoległych tablic. Albo lepiej
// rozwiązaniem byłoby zapisanie "USED" i "UNUSED" jako właściwości
// pojedynczy obiekt statku.
// Te liczby odpowiadają CONST.AVAILABLE_SHIPS
//1) "pancernik" 2) "niszczyciel" 3) "okręt podwodny" 4) "patrolboat"
// Ta zmienna jest używana tylko wtedy, gdy DEBUG_MODE === true.
Game.usedShips = [CONST.UNUSED, CONST.UNUSED, CONST.UNUSED, CONST.UNUSED, CONST.UNUSED];
CONST.USED = 1;
CONST.UNUSED = 0;

// Game Statistics
function Stats(){
	this.shotsTaken = 0;
	this.shotsHit = 0;
	this.totalShots = parseInt(localStorage.getItem('totalShots'), 10) || 0;
	this.totalHits = parseInt(localStorage.getItem('totalHits'), 10) || 0;
	this.gamesPlayed = parseInt(localStorage.getItem('gamesPlayed'), 10) || 0;
	this.gamesWon = parseInt(localStorage.getItem('gamesWon'), 10) || 0;
	this.uuid = localStorage.getItem('uuid') || this.createUUID();
	if (DEBUG_MODE) {
		this.skipCurrentGame = true;
	}
}
Stats.prototype.incrementShots = function() {
	this.shotsTaken++;
};
Stats.prototype.hitShot = function() {
	this.shotsHit++;
};
Stats.prototype.wonGame = function() {
	this.gamesPlayed++;
	this.gamesWon++;
	if (!DEBUG_MODE) {
		ga('send', 'event', 'gameOver', 'win', this.uuid);
	}
};
Stats.prototype.lostGame = function() {
	this.gamesPlayed++;
	if (!DEBUG_MODE) {
		ga('send', 'event', 'gameOver', 'lose', this.uuid);
	}
};
// Zapisuje statystyki gry do lokalnego magazynu, a także przesyła je, gdzie użytkownik umieścił
// ich statki do Google Analytics, aby w przyszłości mogłem zobaczyć
// które komórki ludzkie są nieproporcjonalnie nastawione do umieszczania statków.
Stats.prototype.syncStats = function() {
	if(!this.skipCurrentGame) {
		var totalShots = parseInt(localStorage.getItem('totalShots'), 10) || 0;
		totalShots += this.shotsTaken;
		var totalHits = parseInt(localStorage.getItem('totalHits'), 10) || 0;
		totalHits += this.shotsHit;
		localStorage.setItem('totalShots', totalShots);
		localStorage.setItem('totalHits', totalHits);
		localStorage.setItem('gamesPlayed', this.gamesPlayed);
		localStorage.setItem('gamesWon', this.gamesWon);
		localStorage.setItem('uuid', this.uuid);
	} else {
		this.skipCurrentGame = false;
	}
	
	var stringifiedGrid = '';
	for (var x = 0; x < Game.size; x++) {
		for (var y = 0; y < Game.size; y++) {
			stringifiedGrid += '(' + x + ',' + y + '):' + mainGame.humanGrid.cells[x][y] + ';\n';
		}
	}

	if (!DEBUG_MODE) {
		ga('send', 'event', 'humanGrid', stringifiedGrid, this.uuid);
	}
};
// Aktualizuje pasek boczny z aktualnymi statystykami
Stats.prototype.updateStatsSidebar = function() {
	var elWinPercent = document.getElementById('stats-wins');
	var elAccuracy = document.getElementById('stats-accuracy');
	elWinPercent.innerHTML = this.gamesWon + " of " + this.gamesPlayed;
	elAccuracy.innerHTML = Math.round((100 * this.totalHits / this.totalShots) || 0) + "%";
};
// Zresetuj wszystkie statystyczne statystyki gry do zera. Nie zresetuj uuid.
Stats.prototype.resetStats = function(e) {
// Pomiń statystyki śledzenia do końca bieżącej gry lub innego
// odsetek dokładności będzie niewłaściwy (ponieważ śledzisz
// trafienia, które nie zaczęły się od początku gry)
	Game.stats.skipCurrentGame = true;
	localStorage.setItem('totalShots', 0);
	localStorage.setItem('totalHits', 0);
	localStorage.setItem('gamesPlayed', 0);
	localStorage.setItem('gamesWon', 0);
	localStorage.setItem('showTutorial', true);
	Game.stats.shotsTaken = 0;
	Game.stats.shotsHit = 0;
	Game.stats.totalShots = 0;
	Game.stats.totalHits = 0;
	Game.stats.gamesPlayed = 0;
	Game.stats.gamesWon = 0;
	Game.stats.updateStatsSidebar();
};
Stats.prototype.createUUID = function(len, radix) {
	var chars = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'.split(''),
	uuid = [], i;
	radix = radix || chars.length;

	if (len) {
		// Compact form
		for (i = 0; i < len; i++) uuid[i] = chars[0 | Math.random()*radix];
	} else {
		// rfc4122, version 4 form
		var r;

		// rfc4122 requires these characters
		uuid[8] = uuid[13] = uuid[18] = uuid[23] = '-';
		uuid[14] = '4';

		// Fill in random data.  At i==19 set the high bits of clock sequence as
		// per rfc4122, sec. 4.1.5
		for (i = 0; i < 36; i++) {
			if (!uuid[i]) {
				r = 0 | Math.random()*16;
				uuid[i] = chars[(i === 19) ? (r & 0x3) | 0x8 : r];
			}
		}
	}

	return uuid.join('');
};

// Obiekt menedżera gier
// Konstruktor
function Game(size) {
	Game.size = size;
	this.shotsTaken = 0;
	this.createGrid();
	this.init();
}
Game.size = 10; // Domyślny rozmiar siatki to 10x10
Game.gameOver = false;
// Sprawdza, czy gra jest wygrywana, a jeśli tak, ponownie zainicjuje grę
Game.prototype.checkIfWon = function() {
	if (this.computerFleet.allShipsSunk()) {
		alert('brawo!');
		Game.gameOver = true;
		Game.stats.wonGame();
		Game.stats.syncStats();
		Game.stats.updateStatsSidebar();
		this.showRestartSidebar();
	} else if (this.humanFleet.allShipsSunk()) {
		alert('srobuj ponownie');
		Game.gameOver = true;
		Game.stats.lostGame();
		Game.stats.syncStats();
		Game.stats.updateStatsSidebar();
		this.showRestartSidebar();
	}
};
// strzela do docelowego gracza w siatce.
// Zwraca {int} Constants.TYPE: Co odkryto
Game.prototype.shoot = function(x, y, targetPlayer) {
	var targetGrid;
	var targetFleet;
	if (targetPlayer === CONST.HUMAN_PLAYER) {
		targetGrid = this.humanGrid;
		targetFleet = this.humanFleet;
	} else if (targetPlayer === CONST.COMPUTER_PLAYER) {
		targetGrid = this.computerGrid;
		targetFleet = this.computerFleet;
	} else {
		// Should never be called
		console.log(".................");
	}

	if (targetGrid.isDamagedShip(x, y)) {
		return null;
	} else if (targetGrid.isMiss(x, y)) {
		return null;
	} else if (targetGrid.isUndamagedShip(x, y)) {
// zaktualizować planszę / siatkę
		targetGrid.updateCell(x, y, 'hit', targetPlayer);
// WAŻNE: Ta funkcja musi być nazwana _after_ aktualizacją komórki do "trafienia"
// ponieważ zastąpi klasę CSS "zatopioną", jeśli okaże się, że statek został zatopiony
		targetFleet.findShipByCoords(x, y).incrementDamage(); // increase the damage
		this.checkIfWon();
		return CONST.TYPE_HIT;
	} else {
		targetGrid.updateCell(x, y, 'miss', targetPlayer);
		this.checkIfWon();
		return CONST.TYPE_MISS;
	}
};
// Tworzy detektory zdarzeń kliknięcia na każdej z 100 komórek siatki
Game.prototype.shootListener = function(e) {
	var self = e.target.self;
	// Extract coordinates from event listener
	var x = parseInt(e.target.getAttribute('data-x'), 10);
	var y = parseInt(e.target.getAttribute('data-y'), 10);
	var result = null;
	if (self.readyToPlay) {
		result = self.shoot(x, y, CONST.COMPUTER_PLAYER);

		// Remove the tutorial arrow
		if (gameTutorial.showTutorial) {
			gameTutorial.nextStep();
		}
	}

	if (result !== null && !Game.gameOver) {
		Game.stats.incrementShots();
		if (result === CONST.TYPE_HIT) {
			Game.stats.hitShot();
		}
// Kula AI wystrzeliwa, gdy gracz kliknie komórkę, której jeszcze nie kliknąłeś
		self.robot.shoot();
	} else {
		Game.gameOver = false;
	}
};
// Tworzy detektory zdarzeń kliknięcia na każdym ze statków w rosterze
Game.prototype.rosterListener = function(e) {
	var self = e.target.self;
	// Usuń wszystkie klasy "umieszczania" z listy flot
	var roster = document.querySelectorAll('.fleet-roster li');
	for (var i = 0; i < roster.length; i++) {
		var classes = roster[i].getAttribute('class') || '';
		classes = classes.replace('placing', '');
		roster[i].setAttribute('class', classes);
	}

	// Move the highlight to the next step
	if (gameTutorial.currentStep === 1) {
		gameTutorial.nextStep();
	}
	
	// Set the class of the target ship to 'placing'
	Game.placeShipType = e.target.getAttribute('id');
	document.getElementById(Game.placeShipType).setAttribute('class', 'placing');
	Game.placeShipDirection = parseInt(document.getElementById('rotate-button').getAttribute('data-direction'), 10);
	self.placingOnGrid = true;
};
// Tworzy detektory zdarzeń kliknięcia na siatce ludzkiego gracza, aby obsługiwać
// umieszczenie statku po wybraniu przez użytkownika nazwy statku
Game.prototype.placementListener = function(e) {
	var self = e.target.self;
	if (self.placingOnGrid) {
		// Extract coordinates from event listener
		var x = parseInt(e.target.getAttribute('data-x'), 10);
		var y = parseInt(e.target.getAttribute('data-y'), 10);
		
	// Nie wkręcaj kierunku, jeśli użytkownik próbuje ponownie umieścić.
		var successful = self.humanFleet.placeShip(x, y, Game.placeShipDirection, Game.placeShipType);
		if (successful) {
		// Sporządzono umieszczenie tego statku
			self.endPlacing(Game.placeShipType);

		// Usuń strzałkę pomocniczą
			if (gameTutorial.currentStep === 2) {
				gameTutorial.nextStep();
			}

			self.placingOnGrid = false;
			if (self.areAllShipsPlaced()) {
				var el = document.getElementById('rotate-button');
				el.addEventListener(transitionEndEventName(),(function(){
					el.setAttribute('class', 'hidden');
					if (gameTutorial.showTutorial) {
						document.getElementById('start-game').setAttribute('class', 'highlight');
					} else {
						document.getElementById('start-game').removeAttribute('class');	
					}
				}),false);
				el.setAttribute('class', 'invisible');
			}
		}
	}
};
// Tworzy zdarzenia obsługi zdarzeń mouseover, które obsługują mouseover na
// siatka ludzkiego gracza narysuje statek fantomowy, co oznacza, że użytkownik
// można tam umieścić statek
Game.prototype.placementMouseover = function(e) {
	var self = e.target.self;
	if (self.placingOnGrid) {
		var x = parseInt(e.target.getAttribute('data-x'), 10);
		var y = parseInt(e.target.getAttribute('data-y'), 10);
		var classes;
		var fleetRoster = self.humanFleet.fleetRoster;

		for (var i = 0; i < fleetRoster.length; i++) {
			var shipType = fleetRoster[i].type;

			if (Game.placeShipType === shipType &&
				fleetRoster[i].isLegal(x, y, Game.placeShipDirection)) {
				// Virtual ship
				fleetRoster[i].create(x, y, Game.placeShipDirection, true);
				Game.placeShipCoords = fleetRoster[i].getAllShipCells();

				for (var j = 0; j < Game.placeShipCoords.length; j++) {
					var el = document.querySelector('.grid-cell-' + Game.placeShipCoords[j].x + '-' + Game.placeShipCoords[j].y);
					classes = el.getAttribute('class');
					// Check if the substring ' grid-ship' already exists to avoid adding it twice
					if (classes.indexOf(' grid-ship') < 0) {
						classes += ' grid-ship';
						el.setAttribute('class', classes);
					}
				}
			}
		}
	}
};
// Tworzy zdarzenia detekcji zdarzeń myszy, które nie rysują statku fantomowego
// na siatce ludzkiego gracza, gdy użytkownik przechodzi przez inną komórkę
Game.prototype.placementMouseout = function(e) {
	var self = e.target.self;
	if (self.placingOnGrid) {
		for (var j = 0; j < Game.placeShipCoords.length; j++) {
			var el = document.querySelector('.grid-cell-' + Game.placeShipCoords[j].x + '-' + Game.placeShipCoords[j].y);
			classes = el.getAttribute('class');
// Sprawdź, czy substrat 'grid-ship' już istnieje, aby uniknąć dodawania go dwukrotnie
			if (classes.indexOf(' grid-ship') > -1) {
				classes = classes.replace(' grid-ship', '');
				el.setAttribute('class', classes);
			}
		}
	}
};
// Click handler for the Rotate Ship button
Game.prototype.toggleRotation = function(e) {
	// Toggle rotation direction
	var direction = parseInt(e.target.getAttribute('data-direction'), 10);
	if (direction === Ship.DIRECTION_VERTICAL) {
		e.target.setAttribute('data-direction', '1');
		Game.placeShipDirection = Ship.DIRECTION_HORIZONTAL;
	} else if (direction === Ship.DIRECTION_HORIZONTAL) {
		e.target.setAttribute('data-direction', '0');
		Game.placeShipDirection = Ship.DIRECTION_VERTICAL;
	}
};
// Click handler for the Start Game button
Game.prototype.startGame = function(e) {
	var self = e.target.self;
	var el = document.getElementById('roster-sidebar');
	var fn = function() {el.setAttribute('class', 'hidden');};
	el.addEventListener(transitionEndEventName(),fn,false);
	el.setAttribute('class', 'invisible');
	self.readyToPlay = true;
// Rozwiń krok samouczek
	if (gameTutorial.currentStep === 3) {
		gameTutorial.nextStep();
	}
	el.removeEventListener(transitionEndEventName(),fn,false);
};
// Kliknij przycisk obsługi programu Restart Game
Game.prototype.restartGame = function(e) {
	e.target.removeEventListener(e.type, arguments.callee);
	var self = e.target.self;
	document.getElementById('restart-sidebar').setAttribute('class', 'hidden');
	self.resetFogOfWar();
	self.init();
};
// Funkcja debugowania służąca do umieszczania wszystkich statków i dopiero początek
Game.prototype.placeRandomly = function(e){
	e.target.removeEventListener(e.type, arguments.callee);
	e.target.self.humanFleet.placeShipsRandomly();
	e.target.self.readyToPlay = true;
	document.getElementById('roster-sidebar').setAttribute('class', 'hidden');
	this.setAttribute('class', 'hidden');
};
// Zakończenie umieszczania obecnego statku
Game.prototype.endPlacing = function(shipType) {
	document.getElementById(shipType).setAttribute('class', 'placed');
	
	// Mark the ship as 'used'
	Game.usedShips[CONST.AVAILABLE_SHIPS.indexOf(shipType)] = CONST.USED;

	// Wipe out the variable when you're done with it
	Game.placeShipDirection = null;
	Game.placeShipType = '';
	Game.placeShipCoords = [];
};
// Sprawdza, czy wszystkie statki są umieszczone
// Zwraca boolean
Game.prototype.areAllShipsPlaced = function() {
	var playerRoster = document.querySelectorAll('.fleet-roster li');
	for (var i = 0; i < playerRoster.length; i++) {
		if (playerRoster[i].getAttribute('class') === 'placed') {
			continue;
		} else {
			return false;
		}
	}
	// Reset temporary variables
	Game.placeShipDirection = 0;
	Game.placeShipType = '';
	Game.placeShipCoords = [];
	return true;
};
// Zresetuje mgłę wojny
Game.prototype.resetFogOfWar = function() {
	for (var i = 0; i < Game.size; i++) {
		for (var j = 0; j < Game.size; j++) {
			this.humanGrid.updateCell(i, j, 'empty', CONST.HUMAN_PLAYER);
			this.computerGrid.updateCell(i, j, 'empty', CONST.COMPUTER_PLAYER);
		}
	}
	// Reset all values to indicate the ships are ready to be placed again
	Game.usedShips = Game.usedShips.map(function(){return CONST.UNUSED;});
};
// Zresetowanie stylu CSS na pasku bocznym
Game.prototype.resetRosterSidebar = function() {
	var els = document.querySelector('.fleet-roster').querySelectorAll('li');
	for (var i = 0; i < els.length; i++) {
		els[i].removeAttribute('class');
	}

	if (gameTutorial.showTutorial) {
		gameTutorial.nextStep();
	} else {
		document.getElementById('roster-sidebar').removeAttribute('class');
	}
	document.getElementById('rotate-button').removeAttribute('class');
	document.getElementById('start-game').setAttribute('class', 'hidden');
	if (DEBUG_MODE) {
		document.getElementById('place-randomly').removeAttribute('class');
	}
};
Game.prototype.showRestartSidebar = function() {
	var sidebar = document.getElementById('restart-sidebar');
	sidebar.setAttribute('class', 'highlight');

	// Deregister listeners
	var computerCells = document.querySelector('.computer-player').childNodes;
	for (var j = 0; j < computerCells.length; j++) {
		computerCells[j].removeEventListener('click', this.shootListener, false);
	}
	var playerRoster = document.querySelector('.fleet-roster').querySelectorAll('li');
	for (var i = 0; i < playerRoster.length; i++) {
		playerRoster[i].removeEventListener('click', this.rosterListener, false);
	}

	var restartButton = document.getElementById('restart-game');
	restartButton.addEventListener('click', this.restartGame, false);
	restartButton.self = this;
};
// Tworzy divy HTML dla siatki dla obu graczy
Game.prototype.createGrid = function() {
	var gridDiv = document.querySelectorAll('.grid');
	for (var grid = 0; grid < gridDiv.length; grid++) {
		gridDiv[grid].removeChild(gridDiv[grid].querySelector('.no-js')); // Removes the no-js warning
		for (var i = 0; i < Game.size; i++) {
			for (var j = 0; j < Game.size; j++) {
				var el = document.createElement('div');
				el.setAttribute('data-x', i);
				el.setAttribute('data-y', j);
				el.setAttribute('class', 'grid-cell grid-cell-' + i + '-' + j);
				gridDiv[grid].appendChild(el);
			}
		}
	}
};
// inicjuje grę. Również resetuje grę, jeśli została wcześniej zainicjowana
Game.prototype.init = function() {
	this.humanGrid = new Grid(Game.size);
	this.computerGrid = new Grid(Game.size);
	this.humanFleet = new Fleet(this.humanGrid, CONST.HUMAN_PLAYER);
	this.computerFleet = new Fleet(this.computerGrid, CONST.COMPUTER_PLAYER);

	this.robot = new AI(this);
	Game.stats = new Stats();
	Game.stats.updateStatsSidebar();

	// Reset game variables
	this.shotsTaken = 0;
	this.readyToPlay = false;
	this.placingOnGrid = false;
	Game.placeShipDirection = 0;
	Game.placeShipType = '';
	Game.placeShipCoords = [];

	this.resetRosterSidebar();

// Dodaj metodę kliknięć dla metody Grid.shoot () dla wszystkich komórek
// Tylko dodaj tego słuchacza do sieci komputerowej
	var computerCells = document.querySelector('.computer-player').childNodes;
	for (var j = 0; j < computerCells.length; j++) {
		computerCells[j].self = this;
		computerCells[j].addEventListener('click', this.shootListener, false);
	}
// Dodaj listener do listy	
	var playerRoster = document.querySelector('.fleet-roster').querySelectorAll('li');
	for (var i = 0; i < playerRoster.length; i++) {
		playerRoster[i].self = this;
		playerRoster[i].addEventListener('click', this.rosterListener, false);
	}

// Dodawanie detektora kliknięć do siatki ludzkiego gracza podczas wprowadzania
	var humanCells = document.querySelector('.human-player').childNodes;
	for (var k = 0; k < humanCells.length; k++) {
		humanCells[k].self = this;
		humanCells[k].addEventListener('click', this.placementListener, false);
		humanCells[k].addEventListener('mouseover', this.placementMouseover, false);
		humanCells[k].addEventListener('mouseout', this.placementMouseout, false);
	}

	var rotateButton = document.getElementById('rotate-button');
	rotateButton.addEventListener('click', this.toggleRotation, false);
	var startButton = document.getElementById('start-game');
	startButton.self = this;
	startButton.addEventListener('click', this.startGame, false);
	var resetButton = document.getElementById('reset-stats');
	resetButton.addEventListener('click', Game.stats.resetStats, false);
	var randomButton = document.getElementById('place-randomly');
	randomButton.self = this;
	randomButton.addEventListener('click', this.placeRandomly, false);
	this.computerFleet.placeShipsRandomly();
};

// Grid object
// Constructor
function Grid(size) {
	this.size = size;
	this.cells = [];
	this.init();
}

// Inicjowanie i wypełnienie siatki
Grid.prototype.init = function() {
	for (var x = 0; x < this.size; x++) {
		var row = [];
		this.cells[x] = row;
		for (var y = 0; y < this.size; y++) {
			row.push(CONST.TYPE_EMPTY);
		}
	}
};

// Aktualizuje klasę CSS komórki w oparciu o typ przekazany
Grid.prototype.updateCell = function(x, y, type, targetPlayer) {
	var player;
	if (targetPlayer === CONST.HUMAN_PLAYER) {
		player = 'human-player';
	} else if (targetPlayer === CONST.COMPUTER_PLAYER) {
		player = 'computer-player';
	} else {
		// Should never be called
		console.log("There was an error trying to find the correct player's grid");
	}

	switch (type) {
		case CONST.CSS_TYPE_EMPTY:
			this.cells[x][y] = CONST.TYPE_EMPTY;
			break;
		case CONST.CSS_TYPE_SHIP:
			this.cells[x+1][y+1] = CONST.TYPE_SHIP;
			break;

		case CONST.CSS_TYPE_MISS:
			this.cells[x][y] = CONST.TYPE_MISS;
			break;
		case CONST.CSS_TYPE_HIT:
			this.cells[x][y] = CONST.TYPE_HIT;
			break;
		case CONST.CSS_TYPE_SUNK:
			this.cells[x][y] = CONST.TYPE_SUNK;
			break;
		default:
			this.cells[x][y] = CONST.TYPE_EMPTY;
			break;
	}
	var classes = ['grid-cell', 'grid-cell-' + x + '-' + y, 'grid-' + type];
	document.querySelector('.' + player + ' .grid-cell-' + x + '-' + y).setAttribute('class', classes.join(' '));
};
// Sprawdza, czy komórka zawiera nieuszkodzony statek
// Zwraca boolean
Grid.prototype.isUndamagedShip = function(x, y) {
	return this.cells[x][y] === CONST.TYPE_SHIP;
};
// Sprawdza, czy strzał został pominięty. To jest równoważne
// sprawdzenie, czy komórka zawiera kulę armatnią
// Zwraca boolean
Grid.prototype.isMiss = function(x, y) {
	return this.cells[x][y] === CONST.TYPE_MISS;
};
// Sprawdza, czy komórka zawiera uszkodzony statek,
// uderzysz lub zatapia.
// Zwraca boolean
Grid.prototype.isDamagedShip = function(x, y) {
	return this.cells[x][y] === CONST.TYPE_HIT || this.cells[x][y] === CONST.TYPE_SUNK;
};

// obiekt Floty
// Ten obiekt służy do śledzenia portfela statków gracza
// Konstruktor
function Fleet(playerGrid, player) {
	this.numShips = CONST.AVAILABLE_SHIPS.length;
	this.playerGrid = playerGrid;
	this.player = player;
	this.fleetRoster = [];
	this.populate();
}
// Posiada flotę
Fleet.prototype.populate = function() {
	for (var i = 0; i < this.numShips; i++) {
		// loop over the ship types when numShips > Constants.AVAILABLE_SHIPS.length
		var j = i % CONST.AVAILABLE_SHIPS.length;
		this.fleetRoster.push(new Ship(CONST.AVAILABLE_SHIPS[j], this.playerGrid, this.player));
	}
};
// umieszcza statek i zwraca, czy miejsce docelowe jest skuteczne
// Zwraca boolean
Fleet.prototype.placeShip = function(x, y, direction, shipType) {
	var shipCoords;
	for (var i = 0; i < this.fleetRoster.length; i++) {
		var shipTypes = this.fleetRoster[i].type;

		if (shipType === shipTypes &&
			this.fleetRoster[i].isLegal(x, y, direction)) {
			this.fleetRoster[i].create(x, y, direction, false);
			shipCoords = this.fleetRoster[i].getAllShipCells();

			for (var j = 0; j < shipCoords.length; j++) {
				this.playerGrid.updateCell(shipCoords[j].x, shipCoords[j].y, 'ship', this.player);
			}
			return true;
		}
	}
	return false;
};
// Miejsca statków są losowo umieszczane na pokładzie
// TODO: Unikaj umieszczania statków zbyt blisko siebie
Fleet.prototype.placeShipsRandomly = function() {
	var shipCoords;
	for (var i = 0; i < this.fleetRoster.length; i++) {
		var illegalPlacement = true;
	
		// Prevents the random placement of already placed ships
		if(this.player === CONST.HUMAN_PLAYER && Game.usedShips[i] === CONST.USED) {
			continue;
		}
		while (illegalPlacement) {
			var randomX = Math.floor(10*Math.random());
			var randomY = Math.floor(10*Math.random());
			var randomDirection = Math.floor(2*Math.random());
			
			if (this.fleetRoster[i].isLegal(randomX, randomY, randomDirection)) {
				this.fleetRoster[i].create(randomX, randomY, randomDirection, false);
				shipCoords = this.fleetRoster[i].getAllShipCells();
				illegalPlacement = false;
			} else {
				continue;
			}
		}
		if (this.player === CONST.HUMAN_PLAYER && Game.usedShips[i] !== CONST.USED) {
			for (var j = 0; j < shipCoords.length; j++) {
				this.playerGrid.updateCell(shipCoords[j].x, shipCoords[j].y, 'ship', this.player);
				Game.usedShips[i] = CONST.USED;
			}
		}
	}
};
// Znajduje statek według lokalizacji
// Zwraca obiekt statku znajdujący się pod adresem (x, y)
// Jeśli żaden statek nie istnieje w (x, y), zamiast tego zwraca null
Fleet.prototype.findShipByCoords = function(x, y) {
	for (var i = 0; i < this.fleetRoster.length; i++) {
		var currentShip = this.fleetRoster[i];
		if (currentShip.direction === Ship.DIRECTION_VERTICAL) {
			if (y === currentShip.yPosition &&
				x >= currentShip.xPosition &&
				x < currentShip.xPosition + currentShip.shipLength) {
				return currentShip;
			} else {
				continue;
			}
		} else {
			if (x === currentShip.xPosition &&
				y >= currentShip.yPosition &&
				y < currentShip.yPosition + currentShip.shipLength) {
				return currentShip;
			} else {
				continue;
			}
		}
	}
	return null;
};
// Znajduje statek według jego typu
// Param shipType to ciąg znaków
// Zwraca obiekt statku, który jest typu typu shipType
// Jeśli żaden statek nie istnieje, zwraca null.
Fleet.prototype.findShipByType = function(shipType) {
	for (var i = 0; i < this.fleetRoster.length; i++) {
		if (this.fleetRoster[i].type === shipType) {
			return this.fleetRoster[i];
		}
	}
	return null;
};
// Checks to see if all ships have been sunk
// Returns boolean
Fleet.prototype.allShipsSunk = function() {
	for (var i = 0; i < this.fleetRoster.length; i++) {
		// If one or more ships are not sunk, then the sentence "all ships are sunk" is false.
		if (this.fleetRoster[i].sunk === false) {
			return false;
		}
	}
	return true;
};

// Ship object
// Constructor
function Ship(type, playerGrid, player) {
	this.damage = 0;
	this.type = type;
	this.playerGrid = playerGrid;
	this.player = player;

	switch (this.type) {
		case CONST.AVAILABLE_SHIPS[0]:
			this.shipLength = 5;
			break;
		case CONST.AVAILABLE_SHIPS[1]:
			this.shipLength = 4;
			break;
		case CONST.AVAILABLE_SHIPS[2]:
			this.shipLength = 3;
			break;
		case CONST.AVAILABLE_SHIPS[3]:
			this.shipLength = 3;
			break;
		case CONST.AVAILABLE_SHIPS[4]:
			this.shipLength = 2;
			break;
		default:
			this.shipLength = 3;
			break;
	}
	this.maxDamage = this.shipLength;
	this.sunk = false;
}
// Sprawdza, czy umieszczenie statku jest legalne
// Zwraca boolean
Ship.prototype.isLegal = function(x, y, direction) {
	// najpierw sprawdź czy statek znajduje się w sieci ...
	if (this.withinBounds(x, y, direction)) 
	{
	// ... sprawdź, czy nie koliduje z innym statkiem
		for (var i = 0; i < this.shipLength; i++) 
		{
			if (direction === Ship.DIRECTION_VERTICAL) 
			{
				if (this.playerGrid.cells[x + i][y] === CONST.TYPE_SHIP ||
				this.playerGrid.cells[x - i][y] === CONST.TYPE_SHIP ||
					this.playerGrid.cells[x + i][y] === CONST.TYPE_MISS ||
					this.playerGrid.cells[x + i][y] === CONST.TYPE_SUNK) 
				
					{
					return false;
				     }
			} 
			else 
			{
				if (this.playerGrid.cells[x][y + i] === CONST.TYPE_SHIP ||
					this.playerGrid.cells[x][y + i] === CONST.TYPE_MISS ||
					this.playerGrid.cells[x][y + i] === CONST.TYPE_SUNK) 
					{
					return false;}				
			}			
		}		
		return true;
	} 
	else 
		return false;	
};
// Sprawdza, czy statek znajduje się w granicach sieci
// Zwraca boolean
//statek mieści się w granicach gry
Ship.prototype.withinBounds = function(x, y, direction) {
	if (direction === Ship.DIRECTION_VERTICAL) {
		return x + this.shipLength <= Game.size;
	} else {
		return y + this.shipLength <= Game.size;
	}
};
// zwiększa licznik uszkodzeń statku
// Zwraca statek
Ship.prototype.incrementDamage = function() {
	this.damage++;
	if (this.isSunk()) {
		this.sinkShip(false); // Sinks the ship
	}
};
// Sprawdza, czy statek jest zatopiony
// Zwraca boolean
Ship.prototype.isSunk = function() {
	return this.damage >= this.maxDamage;
};
// Zanurzysz statek
Ship.prototype.sinkShip = function(virtual) {
	this.damage = this.maxDamage; // Force the damage to exceed max damage
	this.sunk = true;

// Uczynienie klasy CSS zatopionej, ale tylko wtedy, gdy statek nie jest wirtualny
	if (!virtual) {
		var allCells = this.getAllShipCells();
		for (var i = 0; i < this.shipLength; i++) {
			this.playerGrid.updateCell(allCells[i].x, allCells[i].y, 'sunk', this.player);
		}
	}
};

Ship.prototype.getAllShipCells = function() {
	var resultObject = [];
	for (var i = 0; i < this.shipLength; i++) {
		if (this.direction === Ship.DIRECTION_VERTICAL) {
			resultObject[i] = {'x': this.xPosition + i, 'y': this.yPosition};
		} else {
			resultObject[i] = {'x': this.xPosition, 'y': this.yPosition + i};
		}
	}
	return resultObject;
};
// Inicjuje statek o podanym współrzędnym i kierunku (łożyska).
// Jeśli statek zostanie uznany za "wirtualny", wtedy statek zostanie zainicjowany
// jego współrzędne, ale NIE umieszcza się na siatce.
Ship.prototype.create = function(x, y, direction, virtual) {
	// This function assumes that you've already checked that the placement is legal
	this.xPosition = x;
	this.yPosition = y;
	this.direction = direction;

	// Jeśli statek jest wirtualny, nie dodaj go do sieci.
	if (!virtual) {
		for (var i = 0; i < this.shipLength; i++) {
			if (this.direction === Ship.DIRECTION_VERTICAL) {
				this.playerGrid.cells[x + i][y] = CONST.TYPE_SHIP;
			} else {
				this.playerGrid.cells[x][y + i] = CONST.TYPE_SHIP;
			}
		}
	}
	
};
// direction === 0 when the ship is facing north/south
// direction === 1 when the ship is facing east/west
Ship.DIRECTION_VERTICAL = 0;
Ship.DIRECTION_HORIZONTAL = 1;

// Tutorial Object
// Constructor
function Tutorial() {
	this.currentStep = 0;
	// Check if 'showTutorial' is initialized, if it's uninitialized, set it to true.
	this.showTutorial = localStorage.getItem('showTutorial') !== 'false';
}
// Advances the tutorial to the next step
Tutorial.prototype.nextStep = function() {
	var humanGrid = document.querySelector('.human-player');
	var computerGrid = document.querySelector('.computer-player');
	switch (this.currentStep) {
		case 0:
			document.getElementById('roster-sidebar').setAttribute('class', 'highlight');
			document.getElementById('step1').setAttribute('class', 'current-step');
			this.currentStep++;
			break;
		case 1:
			document.getElementById('roster-sidebar').removeAttribute('class');
			document.getElementById('step1').removeAttribute('class');
			humanGrid.setAttribute('class', humanGrid.getAttribute('class') + ' highlight');
			document.getElementById('step2').setAttribute('class', 'current-step');
			this.currentStep++;
			break;
		case 2:
			document.getElementById('step2').removeAttribute('class');
			var humanClasses = humanGrid.getAttribute('class');
			humanClasses = humanClasses.replace(' highlight', '');
			humanGrid.setAttribute('class', humanClasses);
			this.currentStep++;
			break;
		case 3:
			computerGrid.setAttribute('class', computerGrid.getAttribute('class') + ' highlight');
			document.getElementById('step3').setAttribute('class', 'current-step');
			this.currentStep++;
			break;
		case 4:
			var computerClasses = computerGrid.getAttribute('class');
			document.getElementById('step3').removeAttribute('class');
			computerClasses = computerClasses.replace(' highlight', '');
			computerGrid.setAttribute('class', computerClasses);
			document.getElementById('step4').setAttribute('class', 'current-step');
			this.currentStep++;
			break;
		case 5:
			document.getElementById('step4').removeAttribute('class');
			this.currentStep = 6;
			this.showTutorial = false;
			localStorage.setItem('showTutorial', false);
			break;
		default:
			break;
	}
};

// AI Object
// Optimal battleship-playing AI
// Constructor
function AI(gameObject) {
	this.gameObject = gameObject;
	this.virtualGrid = new Grid(Game.size);
	this.virtualFleet = new Fleet(this.virtualGrid, CONST.VIRTUAL_PLAYER);

	this.probGrid = []; // Probability Grid
	this.initProbs();
	this.updateProbs();
}
AI.PROB_WEIGHT = 5000; // arbitrarily big number
// jaka masa ma przynieść komórki wysokiego prawdopodobieństwa książki otwartej
AI.OPEN_HIGH_MIN = 20;
AI.OPEN_HIGH_MAX = 30;
// ile wagi daje się średnim prawdopodobieństwom książki otwarcia
AI.OPEN_MED_MIN = 15;
AI.OPEN_MED_MAX = 25;
// how much weight to give to the opening book's low probability cells
AI.OPEN_LOW_MIN = 10;
AI.OPEN_LOW_MAX = 20;
// Amount of randomness when selecting between cells of equal probability
AI.RANDOMNESS = 0.1;
// AI's opening book.
// This is the pattern of the first cells for the AI to target
AI.OPENINGS = [
	{'x': 7, 'y': 3, 'weight': getRandom(AI.OPEN_LOW_MIN, AI.OPEN_LOW_MAX)},
	{'x': 6, 'y': 2, 'weight': getRandom(AI.OPEN_LOW_MIN, AI.OPEN_LOW_MAX)},
	{'x': 3, 'y': 7, 'weight': getRandom(AI.OPEN_LOW_MIN, AI.OPEN_LOW_MAX)},
	{'x': 2, 'y': 6, 'weight': getRandom(AI.OPEN_LOW_MIN, AI.OPEN_LOW_MAX)},
	{'x': 6, 'y': 6, 'weight': getRandom(AI.OPEN_LOW_MIN, AI.OPEN_LOW_MAX)},
	{'x': 3, 'y': 3, 'weight': getRandom(AI.OPEN_LOW_MIN, AI.OPEN_LOW_MAX)},
	{'x': 5, 'y': 5, 'weight': getRandom(AI.OPEN_LOW_MIN, AI.OPEN_LOW_MAX)},
	{'x': 4, 'y': 4, 'weight': getRandom(AI.OPEN_LOW_MIN, AI.OPEN_LOW_MAX)},
	// {'x': 9, 'y': 5, 'weight': getRandom(AI.OPEN_MED_MIN, AI.OPEN_MED_MAX)},
	// {'x': 0, 'y': 4, 'weight': getRandom(AI.OPEN_MED_MIN, AI.OPEN_MED_MAX)},
	// {'x': 5, 'y': 9, 'weight': getRandom(AI.OPEN_MED_MIN, AI.OPEN_MED_MAX)},
	// {'x': 4, 'y': 0, 'weight': getRandom(AI.OPEN_MED_MIN, AI.OPEN_MED_MAX)},
	{'x': 0, 'y': 8, 'weight': getRandom(AI.OPEN_MED_MIN, AI.OPEN_MED_MAX)},
	{'x': 1, 'y': 9, 'weight': getRandom(AI.OPEN_HIGH_MIN, AI.OPEN_HIGH_MAX)},
	{'x': 8, 'y': 0, 'weight': getRandom(AI.OPEN_MED_MIN, AI.OPEN_MED_MAX)},
	{'x': 9, 'y': 1, 'weight': getRandom(AI.OPEN_HIGH_MIN, AI.OPEN_HIGH_MAX)},
	{'x': 9, 'y': 9, 'weight': getRandom(AI.OPEN_HIGH_MIN, AI.OPEN_HIGH_MAX)},
	{'x': 0, 'y': 0, 'weight': getRandom(AI.OPEN_HIGH_MIN, AI.OPEN_HIGH_MAX)}
];
// Zrzuca siatkę w oparciu o maksymalne prawdopodobieństwo i strzela do komórki
// ma największe prawdopodobieństwo zawarcia statku
AI.prototype.shoot = function() {
	var maxProbability = 0;
	var maxProbCoords;
	var maxProbs = [];
	
	// Add the AI's opening book to the probability grid
	for (var i = 0; i < AI.OPENINGS.length; i++) {
		var cell = AI.OPENINGS[i];
		if (this.probGrid[cell.x][cell.y] !== 0) {
			this.probGrid[cell.x][cell.y] += cell.weight;
		}
	}

	for (var x = 0; x < Game.size; x++) {
		for (var y = 0; y < Game.size; y++) {
			if (this.probGrid[x][y] > maxProbability) {
				maxProbability = this.probGrid[x][y];
				maxProbs = [{'x': x, 'y': y}]; // Replace the array
			} else if (this.probGrid[x][y] === maxProbability) {
				maxProbs.push({'x': x, 'y': y});
			}
		}
	}

	maxProbCoords = Math.random() < AI.RANDOMNESS ?
	maxProbs[Math.floor(Math.random() * maxProbs.length)] :
	maxProbs[0];

	var result = this.gameObject.shoot(maxProbCoords.x, maxProbCoords.y, CONST.HUMAN_PLAYER);
	
	// If the game ends, the next lines need to be skipped.
	if (Game.gameOver) {
		Game.gameOver = false;
		return;
	}

	this.virtualGrid.cells[maxProbCoords.x][maxProbCoords.y] = result;

	// If you hit a ship, check to make sure if you've sunk it.
	if (result === CONST.TYPE_HIT) {
		var humanShip = this.findHumanShip(maxProbCoords.x, maxProbCoords.y);
		if (humanShip.isSunk()) {
			// Remove any ships from the roster that have been sunk
			var shipTypes = [];
			for (var k = 0; k < this.virtualFleet.fleetRoster.length; k++) {
				shipTypes.push(this.virtualFleet.fleetRoster[k].type);
			}
			var index = shipTypes.indexOf(humanShip.type);
			this.virtualFleet.fleetRoster.splice(index, 1);

			// Update the virtual grid with the sunk ship's cells
			var shipCells = humanShip.getAllShipCells();
			for (var _i = 0; _i < shipCells.length; _i++) {
				this.virtualGrid.cells[shipCells[_i].x][shipCells[_i].y] = CONST.TYPE_SUNK;
			}
		}
	}
	// Update probability grid after each shot
	this.updateProbs();
};
// Update the probability grid
AI.prototype.updateProbs = function() {
	var roster = this.virtualFleet.fleetRoster;
	var coords;
	this.resetProbs();
// Prawdopodobieństwa nie są znormalizowane, aby pasowały do przedziału [0, 1]
// dlatego, że jesteśmy zainteresowani maksymalną wartością.

// Działa to poprzez dopasowanie każdego statku do każdej komórki w każdej orientacji
// W każdej komórce, tym bardziej legalnym sposobem, w jaki statek może przechodzić przez niego, tym bardziej
// prawdopodobnie komórka ma zawierać statek.
// Komórki otaczające znane "trafienia" otrzymują arbitralnie duże prawdopodobieństwo
// tak, że AI próbuje całkowicie zatopić statek przed przejściem dalej.

// TODO: Pomyśl o bardziej efektywnej implementacji
	for (var k = 0; k < roster.length; k++) {
		for (var x = 0; x < Game.size; x++) {
			for (var y = 0; y < Game.size; y++) {
				if (roster[k].isLegal(x, y, Ship.DIRECTION_VERTICAL)) {
					roster[k].create(x, y, Ship.DIRECTION_VERTICAL, true);
					coords = roster[k].getAllShipCells();
					if (this.passesThroughHitCell(coords)) {
						for (var i = 0; i < coords.length; i++) {
							this.probGrid[coords[i].x][coords[i].y] += AI.PROB_WEIGHT * this.numHitCellsCovered(coords);
						}
					} else {
						for (var _i = 0; _i < coords.length; _i++) {
							this.probGrid[coords[_i].x][coords[_i].y]++;
						}
					}
				}
				if (roster[k].isLegal(x, y, Ship.DIRECTION_HORIZONTAL)) {
					roster[k].create(x, y, Ship.DIRECTION_HORIZONTAL, true);
					coords = roster[k].getAllShipCells();
					if (this.passesThroughHitCell(coords)) {
						for (var j = 0; j < coords.length; j++) {
							this.probGrid[coords[j].x][coords[j].y] += AI.PROB_WEIGHT * this.numHitCellsCovered(coords);
						}
					} else {
						for (var _j = 0; _j < coords.length; _j++) {
							this.probGrid[coords[_j].x][coords[_j].y]++;
						}
					}
				}

				// Set hit cells to probability zero so the AI doesn't
				// target cells that are already hit
				if (this.virtualGrid.cells[x][y] === CONST.TYPE_HIT) {
					this.probGrid[x][y] = 0;
				}
			}
		}
	}
};
// Initializes the probability grid for targeting
AI.prototype.initProbs = function() {
	for (var x = 0; x < Game.size; x++) {
		var row = [];
		this.probGrid[x] = row;
		for (var y = 0; y < Game.size; y++) {
			row.push(0);
		}
	}
};
// Resets the probability grid to all 0.
AI.prototype.resetProbs = function() {
	for (var x = 0; x < Game.size; x++) {
		for (var y = 0; y < Game.size; y++) {
			this.probGrid[x][y] = 0;
		}
	}
};
AI.prototype.metagame = function() {
	// Inputs:
	// Proximity of hit cells to edge
	// Proximity of hit cells to each other
	// Edit the probability grid by multiplying each cell with a new probability weight (e.g. 0.4, or 3). Set this as a CONST and make 1-CONST the inverse for decreasing, or 2*CONST for increasing
};
// Finds a human ship by coordinates
// Returns Ship
AI.prototype.findHumanShip = function(x, y) {
	return this.gameObject.humanFleet.findShipByCoords(x, y);
};
// Checks whether or not a given ship's cells passes through
// any cell that is hit.
// Returns boolean
AI.prototype.passesThroughHitCell = function(shipCells) {
	for (var i = 0; i < shipCells.length; i++) {
		if (this.virtualGrid.cells[shipCells[i].x][shipCells[i].y] === CONST.TYPE_HIT) {
			return true;
		}
	}
	return false;
};
// Gives the number of hit cells the ships passes through. The more
// cells this is, the more probable the ship exists in those coordinates
// Returns int
AI.prototype.numHitCellsCovered = function(shipCells) {
	var cells = 0;
	for (var i = 0; i < shipCells.length; i++) {
		if (this.virtualGrid.cells[shipCells[i].x][shipCells[i].y] === CONST.TYPE_HIT) {
			cells++;
		}
	}
	return cells;
};

// Global constant only initialized once
var gameTutorial = new Tutorial();

// Start the game
var mainGame = new Game(10);

})();

// Array.prototype.indexOf workaround for IE browsers that don't support it
// From MDN: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/indexOf
if (!Array.prototype.indexOf) {
	Array.prototype.indexOf = function (searchElement, fromIndex) {

		var k;

		// 1. Let O be the result of calling ToObject passing
		//    the this value as the argument.
		if (this === null || this === undefined) {
			throw new TypeError('"this" is null or not defined');
		}

		var O = Object(this);

		// 2. Let lenValue be the result of calling the Get
		//    internal method of O with the argument "length".
		// 3. Let len be ToUint32(lenValue).
		var len = O.length >>> 0;

		// 4. If len is 0, return -1.
		if (len === 0) {
			return -1;
		}

		// 5. If argument fromIndex was passed let n be
		//    ToInteger(fromIndex); else let n be 0.
		var n = +fromIndex || 0;

		if (Math.abs(n) === Infinity) {
			n = 0;
		}

		// 6. If n >= len, return -1.
		if (n >= len) {
			return -1;
		}

		// 7. If n >= 0, then Let k be n.
		// 8. Else, n<0, Let k be len - abs(n).
		//    If k is less than 0, then let k be 0.
		k = Math.max(n >= 0 ? n : len - Math.abs(n), 0);

		// 9. Repeat, while k < len
		while (k < len) {
			var kValue;
			// a. Let Pk be ToString(k).
			//   This is implicit for LHS operands of the in operator
			// b. Let kPresent be the result of calling the
			//    HasProperty internal method of O with argument Pk.
			//   This step can be combined with c
			// c. If kPresent is true, then
			//    i.  Let elementK be the result of calling the Get
			//        internal method of O with the argument ToString(k).
			//   ii.  Let same be the result of applying the
			//        Strict Equality Comparison Algorithm to
			//        searchElement and elementK.
			//  iii.  If same is true, return k.
			if (k in O && O[k] === searchElement) {
				return k;
			}
			k++;
		}
		return -1;
	};
}

// Array.prototype.map workaround for IE browsers that don't support it
// From MDN: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/map
// Production steps of ECMA-262, Edition 5, 15.4.4.19
// Reference: http://es5.github.io/#x15.4.4.19
if (!Array.prototype.map) {

	Array.prototype.map = function(callback, thisArg) {

		var T, A, k;

		if (this == null) {
			throw new TypeError(" this is null or not defined");
		}

		// 1. Let O be the result of calling ToObject passing the |this| 
		//    value as the argument.
		var O = Object(this);

		// 2. Let lenValue be the result of calling the Get internal 
		//    method of O with the argument "length".
		// 3. Let len be ToUint32(lenValue).
		var len = O.length >>> 0;

		// 4. If IsCallable(callback) is false, throw a TypeError exception.
		// See: http://es5.github.com/#x9.11
		if (typeof callback !== "function") {
			throw new TypeError(callback + " is not a function");
		}

		// 5. If thisArg was supplied, let T be thisArg; else let T be undefined.
		if (arguments.length > 1) {
			T = thisArg;
		}

		// 6. Let A be a new array created as if by the expression new Array(len) 
		//    where Array is the standard built-in constructor with that name and 
		//    len is the value of len.
		A = new Array(len);

		// 7. Let k be 0
		k = 0;

		// 8. Repeat, while k < len
		while (k < len) {

			var kValue, mappedValue;

			// a. Let Pk be ToString(k).
			//   This is implicit for LHS operands of the in operator
			// b. Let kPresent be the result of calling the HasProperty internal 
			//    method of O with argument Pk.
			//   This step can be combined with c
			// c. If kPresent is true, then
			if (k in O) {

				// i. Let kValue be the result of calling the Get internal 
				//    method of O with argument Pk.
				kValue = O[k];

				// ii. Let mappedValue be the result of calling the Call internal 
				//     method of callback with T as the this value and argument 
				//     list containing kValue, k, and O.
				mappedValue = callback.call(T, kValue, k, O);

				// iii. Call the DefineOwnProperty internal method of A with arguments
				// Pk, Property Descriptor 
				// { Value: mappedValue, 
				//   Writable: true, 
				//   Enumerable: true, 
				//   Configurable: true },
				// and false.

				// In browsers that support Object.defineProperty, use the following:
				// Object.defineProperty(A, k, { 
				//   value: mappedValue, 
				//   writable: true, 
				//   enumerable: true, 
				//   configurable: true 
				// });

				// For best browser support, use the following:
				A[k] = mappedValue;
			}
			// d. Increase k by 1.
			k++;
		}

		// 9. return A
		return A;
	};
}

// Browser compatability workaround for transition end event names.
// From modernizr: http://stackoverflow.com/a/9090128
function transitionEndEventName() {
	var i,
		undefined,
		el = document.createElement('div'),
		transitions = {
			'transition':'transitionend',
			'OTransition':'otransitionend',  // oTransitionEnd in very old Opera
			'MozTransition':'transitionend',
			'WebkitTransition':'webkitTransitionEnd'
		};

	for (i in transitions) {
		if (transitions.hasOwnProperty(i) && el.style[i] !== undefined) {
			return transitions[i];
		}
	}
}

// Returns a random number between min (inclusive) and max (exclusive)
function getRandom(min, max) {
	return Math.random() * (max - min) + min;
}

// Toggles on or off DEBUG_MODE
function setDebug(val) {
	DEBUG_MODE = val;
	localStorage.setItem('DEBUG_MODE', val);
	localStorage.setItem('showTutorial', 'false');
	window.location.reload();
}

1

200 zł i załatwione.

0
Desu napisał(a):

200 zł i załatwione.

To może jakaś podpowiedź gdzie powinnam dodać warunki ?

0

to będzie kosztowało 50 zł

2

Żeby uświadomić Ci co robisz źle, zwaliłaś do wątku ponad 1300 linijek (pewnie nie swojego) kodu z prośbą o rozwiązanie jakiegoś ogólnego problemu i oczekujesz że je dostaniesz na srebrnej tacy, tak się zachowuje klient a nie programista więc ja bym się chociaż z tej wyceny cieszył.. Spróbuj to rozwiązać sama i jeśli natkniesz się na jakieś problemy na pewno znajdą się chętni żeby pomóc. Nie potrzebujesz znać do tego fizyki kwantowej, trochę logicznego myślenia wystarczy

0
Matthi napisał(a):

Żeby uświadomić Ci co robisz źle, zwaliłaś do wątku ponad 1300 linijek (pewnie nie swojego) kodu z prośbą o rozwiązanie jakiegoś ogólnego problemu i oczekujesz że je dostaniesz na srebrnej tacy, tak się zachowuje klient a nie programista więc ja bym się chociaż z tej wyceny cieszył.. Spróbuj to rozwiązać sama i jeśli natkniesz się na jakieś problemy na pewno znajdą się chętni żeby pomóc. Nie potrzebujesz znać do tego fizyki kwantowej, trochę logicznego myślenia wystarczy

Udało mi się stworzyć blokadę po wartościach większych od zmiennej pierwszego obiektu, ale podczas gry dostaję błąd. Ten sam przypadek dzieje mi się gdy dodam warunek, że inne statki muszą mieć wartości mniejsze o 1 od ustawionego już statku. Kod oczywiście, że nie jest mój.

0

A widzisz, czyli coś modyfikowałaś. To dlatego, się zastanawiałem co to za dziwne warunki tam zachodzą :D

0
Desu napisał(a):

A widzisz, czyli coś modyfikowałaś. To dlatego, się zastanawiałem co to za dziwne warunki tam zachodzą :D

Tutaj akurat wstawiony jest kod jaki otrzymałam. Wstawiając modyfikacje w ciągle otrzymuje błąd

if (direction === Ship.DIRECTION_VERTICAL) 
			{
				if (this.playerGrid.cells[x + i][y] === CONST.TYPE_SHIP ||
		 
					this.playerGrid.cells[x + i][y] === CONST.TYPE_MISS ||
					this.playerGrid.cells[x + i][y] === CONST.TYPE_SUNK) 
				
					{
					return false;
				     }
			} 
0

Sądziłam, że właśnie tutaj wystarczy dodać warunki dla ..X-1 i Y-1.. jednak niestety to nie działa. W funkcji ..Fleet.prototype.findShipByCoords = function(x, y) {.. również próbowałam zmodyfikować położenie, ale nic z tego.

0

Twoja funkcja Ship.prototype.isLegal sprawdza, czy umieszczenie statku jest legalne - zgodnie z komentarzem. Ostatnio jak grałem w statki, to te umieszczało się na początku gry, więc

  • dlaczego funkcja sprawdza, czy na prawo od Twojego statku jest fragment zatopionego statku CONST.TYPE_SUNK? To nie powinno mieć miejsca.
  • o ile jeszcze jestem w stanie zrozumieć powyższy warunek, to co ma do tego wszystkiego pudło CONST.TYPE_MISS?

Umiesz odpowiedzieć na te pytania?

0
Desu napisał(a):

Twoja funkcja Ship.prototype.isLegal sprawdza, czy umieszczenie statku jest legalne - zgodnie z komentarzem. Ostatnio jak grałem w statki, to te umieszczało się na początku gry, więc

  • dlaczego funkcja sprawdza, czy na prawo od Twojego statku jest fragment zatopionego statku CONST.TYPE_SUNK? To nie powinno mieć miejsca.
  • o ile jeszcze jestem w stanie zrozumieć powyższy warunek, to co ma do tego wszystkiego pudło CONST.TYPE_MISS?

Umiesz odpowiedzieć na te pytania?

Jeżeli dobrze rozumiem, co tutaj autor miał na myśli, to wydaje mi się, że jest to zastosowanie jakieś taktyki dla komputera, którą ma się kierować, jako warunkiem w wyborze pola, które zestrzeli w kolejnym etapie. Ale nie wiem czy o to dokładnie chodzi. Nam kazano wprowadzić modyfikacje kodu uwzględniając wygląd gry, etapy gry oraz właśnie tą główną zasadę, z którą mam problem.

1

Rozumiem, w takim razie przykro mi, ale za darmo nie zamierzam czytać tego kodu i domyślać się, co autor miał na myśli, skoro Wam ("Nam kazano"), ktoś za to zapłaci.

0

Nam w sensie studentom, ale każdy otrzymał inny kod. Więc poprawiać muszę osobiście. No nic. Dzięki za odpowiedź,.

0

Nam kazano wprowadzić modyfikacje kodu

  1. dobry sposób na naukę, dać studentom kawałek źle napisanego kodu (bo ten kod ogólnie jest napisany raczej słabo), żeby go poprawili XD w sumie ma to sens. W pracy komercyjnej też człowiek ma do czynienia ze słabo napisanymi kodami i więcej czasu spędza na ich poprawianiu niż na robieniu czegoś od nowa.

  2. podświetlaj składnie. robi się to tak:

```javascript
function a() {}
```

i wychodzi kolorowe.

function a() {}

tu w necie znalazłem z pokolorowaną już składnią kod podobny do twojego (chyba to samo, tylko z angielskimi komentarzami, więc ktokolwiek ci dał ten kod, raczej nie napisał go sam:
http://ideone.com/M89K8t )
BTW te komentarze są tłumaczone przez Google Translate chyba. Ktoś kto to wyedytował jest niepoważny XD

// przesyła je, gdzie użytkownik umieścił
// ich statki do Google Analytics, aby w przyszłości mogłem zobaczyć
// które komórki ludzkie są nieproporcjonalnie nastawione do umieszczania statków.

WTF komórki ludzkie XD XD XD

  1. poza tym mamy w tym kodzie wynajdowanie koła na nowo
var CONST = {};
CONST.AVAILABLE_SHIPS = ['carrier', 'battleship', 'destroyer', 'submarine', 'patrolboat'];
// You are player 0 and the computer is player 1
// The virtual player is used for generating temporary ships
// for calculating the probability heatmap
CONST.HUMAN_PLAYER = 0;

To nawet nie wynajdowanie koła, tylko udawanie, że się odkrywa koło, bo to i tak nie są stałe. W JavaScript jest już słówko kluczowe const i można za pomocą niego deklarować zmienne, które są "stałe", tj. nie można do nich przypisać innej wartości. Czyli można napisać tak

const AVAILABLE_SHIPS = ['carrier', 'battleship', 'destroyer', 'submarine', 'patrolboat']; 
const HUMAN_PLAYER = 0;

przy czym w JS nawet deklarując coś const można to zmieniać "w środku". Np. do tablicy pisanej z użyciem const można dokładać kolejne elementy. Tym niemniej nie można przypisać całkiem nowej tablicy. No i jest to i tak większe zabezpieczenie przed zmianą niż pisanie var i chamskie udawanie, że coś jest stałą.

A jeśli komuś zależy na stałych-stałych nawet w środku, można by zrobić obiekt z getterami:

const CONST = {
   get AVAILABLE_SHIPS() {
      return ['carrier', 'battleship', 'destroyer', 'submarine', 'patrolboat'];
   },
   get COMPUTER_PLAYER() {
      return 1;
   }
}

https://jsfiddle.net/ghzug6ya/1/

Może to nie rozwiąże twojego problemu, ale to taka uwaga techniczna.

1 użytkowników online, w tym zalogowanych: 0, gości: 1