Ship placement verification function for Battleship gameWrapper for jquery ajax to ensure redirects occur on...
What happened to QGIS 2.x
How can I be pwned if I'm not registered on the compromised site?
Graphing random points on the XY-plane
It took me a lot of time to make this, pls like. (YouTube Comments #1)
Make me a metasequence
Reason why dimensional travelling would be restricted
Are there any other Chaos-worshipping races?
How to lift/raise/repair a segment of concrete slab?
Get length of the longest sequence of numbers with the same sign
How do ISS astronauts "get their stripes"?
How to mitigate "bandwagon attacking" from players?
Second-rate spelling
Is the withholding of funding notice allowed?
The need of reserving one's ability in job interviews
Canadian citizen, on US no-fly list. What can I do in order to be allowed on flights which go through US airspace?
lead or lag function to get several values, not just the nth
Why is working on the same position for more than 15 years not a red flag?
Is it possible to convert a suspension fork to rigid by drilling it?
What type of investment is best suited for a 1-year investment on a down payment?
Why can't we make a perpetual motion machine by using a magnet to pull up a piece of metal, then letting it fall back down?
If nine coins are tossed, what is the probability that the number of heads is even?
Does an unattuned Frost Brand weapon still glow in freezing temperatures?
Misplaced tyre lever - alternatives?
Dystopian novel where telepathic humans live under a dome
Ship placement verification function for Battleship game
Wrapper for jquery ajax to ensure redirects occur on clientsideMultiplayer bowling in Ruby, with variable skillJavaScript API for RESTBush wanderer console gameData Driven (ability) system2d game enemy entities factories, probably in need of refactoringHandling collision on a turn-based 2D gameOffline .io style game built in UnitySimple function returning 1 if the Mean = Mode, or 0 if notC++ Battleship player AI
$begingroup$
I wrote server-side Battleship game simulator in nodeJs/Javascript:
- A random player who begins is chosen.
- Both place their ships. Software recognizes if they are placed correctly.
- One of the players shoots at a position on the 10×10 field. If it's not this players turn, the program recognizes it; if it's the player's turn the program checks if the player hit a ship of the opponent. If he/she hit a ship, he/she can shoot again. If a ship is destroyed, the software recognizes that...
Its source code is available at: https://github.com/ndsvw/battleship
I also wrote 36 test cases (npm install, npm run test) and it works.
I would like to improve the code and want to make sure that it does always work (all imaginable scenarios).
An example: the file src/field.js contains checkShipArray(arr) that takes an array like [67, 77, 31, 41, 51, 61, 71, 0, 1, 2, 16, 17, 18, 96, 97, 98, 99] and returns an object with a status 'success'/'fail' and an array of ships:
{
status: 'success',
ships:
[
[ 31, 41, 51, 61, 71 ],
[ 67, 77 ],
[ 0, 1, 2 ],
[ 16, 17, 18 ],
[ 96, 97, 98, 99 ]
]
}
But the code that makes this is ~200 lines long. My main problem:
The 2 functions getCollisionPosOfHorizontalShip and getCollisionPosOfVerticalShip do almost look the same but I can't figure out how to write it shorter.
This is the whole field.js file:
const PositionSet = require('./positionset');
const RandomFieldGenerator = require('./random-field-generator');
module.exports = class Feld {
constructor(options) {
options = options || {};
this.SAMEPLAYERSTURNAFTERHIT = typeof options.SAMEPLAYERSTURNAFTERHIT === 'undefined' ? true : options.SAMEPLAYERSTURNAFTERHIT;
this.REQUIREDSHIPS = options.REQUIREDSHIPS || [0, 1, 2, 1, 1]; // default: 0x 1er, 1x 2er, 2x 3er, 1x 4er, 1x 5er
this.FIELD_HEIGHT = options.FIELD_HEIGHT || 10;
this.FIELD_WIDTH = options.FIELD_WIDTH || 10;
this.COLLISION_RULES = options.COLLISION_RULES || {
ALLOW_CORNER_COLLISIONS: true // in the default field: [0,1,2,3,4,15,16] for example
};
this.SHIPCOUNTER = 0;
this.SHIPPOSCOUNTER = 0;
for (let i = 0; i < this.REQUIREDSHIPS.length; i++) {
if (this.REQUIREDSHIPS[i] > 0) {
this.SHIPCOUNTER += this.REQUIREDSHIPS[i];
}
this.SHIPPOSCOUNTER += this.REQUIREDSHIPS[i] * (i + 1);
}
this.ships = [];
this.hits = [];
this.misses = [];
if (this.REQUIREDSHIPS.length > this.FIELD_WIDTH && this.REQUIREDSHIPS.length > this.FIELD_WIDTH) {
throw new Error('At least 1 ship seems to be larger than the field.');
}
if (this.SHIPPOSCOUNTER > this.FIELD_WIDTH * this.FIELD_HEIGHT) {
throw new Error('The field is not large enough for all ships.');
}
}
isShipAt(pos) {
return this.ships.some((s) => s.includes(pos));
}
hasAlreadyBeenHit(pos) {
return this.hits.includes(pos);
}
hasAlreadyBeenMissed(pos) {
return this.misses.includes(pos);
}
isShipDestroyedAt(pos, opponentFeld) {
const ship = this.ships.find((s) => s.includes(pos)) || null;
return (ship !== null && ship.every((p) => opponentFeld.hasAlreadyBeenHit(p)));
}
setShips(arr) {
const data = this.checkShipArray(arr);
if (data.status === 'success') {
this.ships = data.ships;
return {
status: 'success'
};
}
return {
status: data.status,
reason: data.reason
};
}
setRandomShips() {
// only works for the default field so far
const rfg = new RandomFieldGenerator();
return this.setShips(rfg.generateField());
}
checkShipArray(arr) {
// eliminate duplicates
arr = Array.from(new Set(arr));
// sort ascending
arr.sort((a, b) => a - b);
// check whether all ships are placed
if (arr.length !== this.SHIPPOSCOUNTER) {
return {
status: 'fail',
reason: 'A problem occured. The following ships need to be placed: ' + this.getRequiredShipsListAsText()
};
}
// Check whether all ships are placed within the field
if (arr.some((s) => s < 0 || s > this.FIELD_HEIGHT * this.FIELD_WIDTH - 1)) {
return {
status: 'fail',
reason: 'A problem occured. Ships need to be placed within the field.'
};
}
// getting an array with all ships
const data = this.getShipsOfArray(arr);
const ships = data.shipArray;
const shipsH = data.shipArrayH;
const shipsV = data.shipArrayV;
// check whether the number of ships and their sized are correct
if (ships.length === this.SHIPCOUNTER) {
// deep copy the requirements; for each ship of length x: decrement the value of the index x.
// after that: check if all values of the array are 0.
const reqCheckArr = JSON.parse(JSON.stringify(this.REQUIREDSHIPS));
for (const s of ships) {
reqCheckArr[s.length - 1]--;
}
if (reqCheckArr.some((x) => x !== 0)) {
return {
status: 'fail',
reason: 'A problem occured. The following ships need to be placed: ' + this.getRequiredShipsListAsText()
};
}
} else {
return {
status: 'fail',
reason: 'A problem occured. The following ships need to be placed: ' + this.getRequiredShipsListAsText()
};
}
// Check whether all parts of the horizontal ships are in the same row (don't accept [8,9,10,11,12] in the default match)
for (const s of shipsH) {
const row = Math.floor(s[0] / this.FIELD_WIDTH);
for (let i = 1; i < s.length; i++) {
if (Math.floor(s[i] / this.FIELD_WIDTH) !== row) {
return {
status: 'fail',
reason: 'A problem occured. The following ships need to be placed: ' + this.getRequiredShipsListAsText()
};
}
}
}
// iterate over all ships and check whether they are at forbidden positions
const forbiddenPositions = this.getCollisionPos(shipsH, shipsV);
for (const s of ships) {
if (s.some((pos) => forbiddenPositions.hasPos(pos))) {
return {
status: 'fail',
reason: 'A problem occured. Ships must not collide!'
};
}
}
return {
status: 'success',
ships
};
}
getShipsOfArray(arr) {
const shipArray = [];
const shipArrayH = [];
const shipArrayV = [];
const arrH = []; // Array, that contains all the position of the horizontal ships.
// find vertical ships.
for (const s of arr) {
// if the position is already part of a ship, continue
if (shipArray.some((sh) => sh.includes(s))) {
continue;
}
let i = 0;
while (arr.includes(s + (i + 1) * this.FIELD_WIDTH)) {
i++;
}
if (i === 0) {
arrH.push(s);
} else {
const newShip = [];
for (let j = s; j < s + (i + 1) * this.FIELD_WIDTH; j += this.FIELD_WIDTH) {
newShip.push(j);
}
shipArray.push(newShip);
shipArrayV.push(newShip);
}
}
// find horizontal ships.
for (const s of arrH) {
// if the position is already part of a ship, continue
if (shipArray.some((sh) => sh.includes(s))) {
continue;
}
let i = 0;
const currentRow = Math.floor(s / this.FIELD_WIDTH);
// as long as the current position is in arr && if we are still in the same row => increment i
while (arr.includes(s + i + 1) && Math.floor((s + i + 1) / this.FIELD_WIDTH) === currentRow) {
i++;
}
if (i !== 0) {
const newShip = [];
for (let j = s; j < s + i + 1; j++) {
newShip.push(j);
}
shipArray.push(newShip);
shipArrayH.push(newShip);
}
}
return {
shipArray,
shipArrayH,
shipArrayV
};
}
getCollisionPos(shipsH, shipsV) {
const collisionPos = new PositionSet(this.FIELD_HEIGHT, this.FIELD_WIDTH);
for (const s of shipsH) {
collisionPos.union(this.getCollisionPosOfHorizontalShip(s));
}
for (const s of shipsV) {
collisionPos.union(this.getCollisionPosOfVerticalShip(s));
}
return collisionPos;
}
getCollisionPosOfHorizontalShip(s) {
const collisionPos = new PositionSet(this.FIELD_HEIGHT, this.FIELD_WIDTH);
// position in front of the ship and behind the ship are forbidden.
if (s[0] % this.FIELD_WIDTH > 0) {
collisionPos.add(s[0] - 1);
}
if ((s[s.length - 1] + 1) % this.FIELD_WIDTH > 0) {
collisionPos.add(s[s.length - 1] + 1);
}
// rows next to the ship and in parallel to the ship are forbidden
for (let i = 0; i < s.length; i++) {
collisionPos.add(s[i] - this.FIELD_WIDTH);
collisionPos.add(s[i] + this.FIELD_WIDTH);
}
// positions at the corners are (maybe) forbidden
if (!this.COLLISION_RULES.ALLOW_CORNER_COLLISIONS) {
if (s[0] % this.FIELD_WIDTH > 0) {
collisionPos.add(s[0] - (this.FIELD_WIDTH + 1));
collisionPos.add(s[0] + (this.FIELD_WIDTH - 1));
}
if ((s[0] + 1) % this.FIELD_WIDTH > 0) {
collisionPos.add(s[s.length - 1] - (this.FIELD_WIDTH - 1));
collisionPos.add(s[s.length - 1] + (this.FIELD_WIDTH + 1));
}
}
return collisionPos;
}
getCollisionPosOfVerticalShip(s) {
const collisionPos = new PositionSet(this.FIELD_HEIGHT, this.FIELD_WIDTH);
// position in front of the ship and behind the ship are forbidden.
collisionPos.add(s[0] - this.FIELD_WIDTH);
collisionPos.add(s[s.length - 1] + this.FIELD_WIDTH);
// rows next to the ship and in parallel to the ship are forbidden
for (let i = 0; i < s.length; i++) {
if (s[i] % this.FIELD_WIDTH > 0) {
collisionPos.add(s[i] - 1);
}
if ((s[i] + 1) % this.FIELD_WIDTH > 0) {
collisionPos.add(s[i] + 1);
}
}
// positions at the corners are (maybe) forbidden
if (!this.COLLISION_RULES.ALLOW_CORNER_COLLISIONS) {
if (s[0] % this.FIELD_WIDTH > 0) {
collisionPos.add(s[0] - (this.FIELD_WIDTH + 1));
collisionPos.add(s[s.length - 1] + (this.FIELD_WIDTH - 1));
}
if ((s[0] + 1) % this.FIELD_WIDTH > 0) {
collisionPos.add(s[0] - (this.FIELD_WIDTH - 1));
collisionPos.add(s[s.length - 1] + (this.FIELD_WIDTH + 1));
}
}
return collisionPos;
}
getRequiredShipsListAsText() {
const reqShips = [];
for (let i = 0; i < this.REQUIREDSHIPS.length; i++) {
if (this.REQUIREDSHIPS[i] > 0) {
reqShips.push(this.REQUIREDSHIPS[i] + 'x ' + (i + 1) + 'er');
}
}
return reqShips.join(', ');
}
};
javascript game node.js validation battleship
New contributor
Alpha is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.
$endgroup$
add a comment |
$begingroup$
I wrote server-side Battleship game simulator in nodeJs/Javascript:
- A random player who begins is chosen.
- Both place their ships. Software recognizes if they are placed correctly.
- One of the players shoots at a position on the 10×10 field. If it's not this players turn, the program recognizes it; if it's the player's turn the program checks if the player hit a ship of the opponent. If he/she hit a ship, he/she can shoot again. If a ship is destroyed, the software recognizes that...
Its source code is available at: https://github.com/ndsvw/battleship
I also wrote 36 test cases (npm install, npm run test) and it works.
I would like to improve the code and want to make sure that it does always work (all imaginable scenarios).
An example: the file src/field.js contains checkShipArray(arr) that takes an array like [67, 77, 31, 41, 51, 61, 71, 0, 1, 2, 16, 17, 18, 96, 97, 98, 99] and returns an object with a status 'success'/'fail' and an array of ships:
{
status: 'success',
ships:
[
[ 31, 41, 51, 61, 71 ],
[ 67, 77 ],
[ 0, 1, 2 ],
[ 16, 17, 18 ],
[ 96, 97, 98, 99 ]
]
}
But the code that makes this is ~200 lines long. My main problem:
The 2 functions getCollisionPosOfHorizontalShip and getCollisionPosOfVerticalShip do almost look the same but I can't figure out how to write it shorter.
This is the whole field.js file:
const PositionSet = require('./positionset');
const RandomFieldGenerator = require('./random-field-generator');
module.exports = class Feld {
constructor(options) {
options = options || {};
this.SAMEPLAYERSTURNAFTERHIT = typeof options.SAMEPLAYERSTURNAFTERHIT === 'undefined' ? true : options.SAMEPLAYERSTURNAFTERHIT;
this.REQUIREDSHIPS = options.REQUIREDSHIPS || [0, 1, 2, 1, 1]; // default: 0x 1er, 1x 2er, 2x 3er, 1x 4er, 1x 5er
this.FIELD_HEIGHT = options.FIELD_HEIGHT || 10;
this.FIELD_WIDTH = options.FIELD_WIDTH || 10;
this.COLLISION_RULES = options.COLLISION_RULES || {
ALLOW_CORNER_COLLISIONS: true // in the default field: [0,1,2,3,4,15,16] for example
};
this.SHIPCOUNTER = 0;
this.SHIPPOSCOUNTER = 0;
for (let i = 0; i < this.REQUIREDSHIPS.length; i++) {
if (this.REQUIREDSHIPS[i] > 0) {
this.SHIPCOUNTER += this.REQUIREDSHIPS[i];
}
this.SHIPPOSCOUNTER += this.REQUIREDSHIPS[i] * (i + 1);
}
this.ships = [];
this.hits = [];
this.misses = [];
if (this.REQUIREDSHIPS.length > this.FIELD_WIDTH && this.REQUIREDSHIPS.length > this.FIELD_WIDTH) {
throw new Error('At least 1 ship seems to be larger than the field.');
}
if (this.SHIPPOSCOUNTER > this.FIELD_WIDTH * this.FIELD_HEIGHT) {
throw new Error('The field is not large enough for all ships.');
}
}
isShipAt(pos) {
return this.ships.some((s) => s.includes(pos));
}
hasAlreadyBeenHit(pos) {
return this.hits.includes(pos);
}
hasAlreadyBeenMissed(pos) {
return this.misses.includes(pos);
}
isShipDestroyedAt(pos, opponentFeld) {
const ship = this.ships.find((s) => s.includes(pos)) || null;
return (ship !== null && ship.every((p) => opponentFeld.hasAlreadyBeenHit(p)));
}
setShips(arr) {
const data = this.checkShipArray(arr);
if (data.status === 'success') {
this.ships = data.ships;
return {
status: 'success'
};
}
return {
status: data.status,
reason: data.reason
};
}
setRandomShips() {
// only works for the default field so far
const rfg = new RandomFieldGenerator();
return this.setShips(rfg.generateField());
}
checkShipArray(arr) {
// eliminate duplicates
arr = Array.from(new Set(arr));
// sort ascending
arr.sort((a, b) => a - b);
// check whether all ships are placed
if (arr.length !== this.SHIPPOSCOUNTER) {
return {
status: 'fail',
reason: 'A problem occured. The following ships need to be placed: ' + this.getRequiredShipsListAsText()
};
}
// Check whether all ships are placed within the field
if (arr.some((s) => s < 0 || s > this.FIELD_HEIGHT * this.FIELD_WIDTH - 1)) {
return {
status: 'fail',
reason: 'A problem occured. Ships need to be placed within the field.'
};
}
// getting an array with all ships
const data = this.getShipsOfArray(arr);
const ships = data.shipArray;
const shipsH = data.shipArrayH;
const shipsV = data.shipArrayV;
// check whether the number of ships and their sized are correct
if (ships.length === this.SHIPCOUNTER) {
// deep copy the requirements; for each ship of length x: decrement the value of the index x.
// after that: check if all values of the array are 0.
const reqCheckArr = JSON.parse(JSON.stringify(this.REQUIREDSHIPS));
for (const s of ships) {
reqCheckArr[s.length - 1]--;
}
if (reqCheckArr.some((x) => x !== 0)) {
return {
status: 'fail',
reason: 'A problem occured. The following ships need to be placed: ' + this.getRequiredShipsListAsText()
};
}
} else {
return {
status: 'fail',
reason: 'A problem occured. The following ships need to be placed: ' + this.getRequiredShipsListAsText()
};
}
// Check whether all parts of the horizontal ships are in the same row (don't accept [8,9,10,11,12] in the default match)
for (const s of shipsH) {
const row = Math.floor(s[0] / this.FIELD_WIDTH);
for (let i = 1; i < s.length; i++) {
if (Math.floor(s[i] / this.FIELD_WIDTH) !== row) {
return {
status: 'fail',
reason: 'A problem occured. The following ships need to be placed: ' + this.getRequiredShipsListAsText()
};
}
}
}
// iterate over all ships and check whether they are at forbidden positions
const forbiddenPositions = this.getCollisionPos(shipsH, shipsV);
for (const s of ships) {
if (s.some((pos) => forbiddenPositions.hasPos(pos))) {
return {
status: 'fail',
reason: 'A problem occured. Ships must not collide!'
};
}
}
return {
status: 'success',
ships
};
}
getShipsOfArray(arr) {
const shipArray = [];
const shipArrayH = [];
const shipArrayV = [];
const arrH = []; // Array, that contains all the position of the horizontal ships.
// find vertical ships.
for (const s of arr) {
// if the position is already part of a ship, continue
if (shipArray.some((sh) => sh.includes(s))) {
continue;
}
let i = 0;
while (arr.includes(s + (i + 1) * this.FIELD_WIDTH)) {
i++;
}
if (i === 0) {
arrH.push(s);
} else {
const newShip = [];
for (let j = s; j < s + (i + 1) * this.FIELD_WIDTH; j += this.FIELD_WIDTH) {
newShip.push(j);
}
shipArray.push(newShip);
shipArrayV.push(newShip);
}
}
// find horizontal ships.
for (const s of arrH) {
// if the position is already part of a ship, continue
if (shipArray.some((sh) => sh.includes(s))) {
continue;
}
let i = 0;
const currentRow = Math.floor(s / this.FIELD_WIDTH);
// as long as the current position is in arr && if we are still in the same row => increment i
while (arr.includes(s + i + 1) && Math.floor((s + i + 1) / this.FIELD_WIDTH) === currentRow) {
i++;
}
if (i !== 0) {
const newShip = [];
for (let j = s; j < s + i + 1; j++) {
newShip.push(j);
}
shipArray.push(newShip);
shipArrayH.push(newShip);
}
}
return {
shipArray,
shipArrayH,
shipArrayV
};
}
getCollisionPos(shipsH, shipsV) {
const collisionPos = new PositionSet(this.FIELD_HEIGHT, this.FIELD_WIDTH);
for (const s of shipsH) {
collisionPos.union(this.getCollisionPosOfHorizontalShip(s));
}
for (const s of shipsV) {
collisionPos.union(this.getCollisionPosOfVerticalShip(s));
}
return collisionPos;
}
getCollisionPosOfHorizontalShip(s) {
const collisionPos = new PositionSet(this.FIELD_HEIGHT, this.FIELD_WIDTH);
// position in front of the ship and behind the ship are forbidden.
if (s[0] % this.FIELD_WIDTH > 0) {
collisionPos.add(s[0] - 1);
}
if ((s[s.length - 1] + 1) % this.FIELD_WIDTH > 0) {
collisionPos.add(s[s.length - 1] + 1);
}
// rows next to the ship and in parallel to the ship are forbidden
for (let i = 0; i < s.length; i++) {
collisionPos.add(s[i] - this.FIELD_WIDTH);
collisionPos.add(s[i] + this.FIELD_WIDTH);
}
// positions at the corners are (maybe) forbidden
if (!this.COLLISION_RULES.ALLOW_CORNER_COLLISIONS) {
if (s[0] % this.FIELD_WIDTH > 0) {
collisionPos.add(s[0] - (this.FIELD_WIDTH + 1));
collisionPos.add(s[0] + (this.FIELD_WIDTH - 1));
}
if ((s[0] + 1) % this.FIELD_WIDTH > 0) {
collisionPos.add(s[s.length - 1] - (this.FIELD_WIDTH - 1));
collisionPos.add(s[s.length - 1] + (this.FIELD_WIDTH + 1));
}
}
return collisionPos;
}
getCollisionPosOfVerticalShip(s) {
const collisionPos = new PositionSet(this.FIELD_HEIGHT, this.FIELD_WIDTH);
// position in front of the ship and behind the ship are forbidden.
collisionPos.add(s[0] - this.FIELD_WIDTH);
collisionPos.add(s[s.length - 1] + this.FIELD_WIDTH);
// rows next to the ship and in parallel to the ship are forbidden
for (let i = 0; i < s.length; i++) {
if (s[i] % this.FIELD_WIDTH > 0) {
collisionPos.add(s[i] - 1);
}
if ((s[i] + 1) % this.FIELD_WIDTH > 0) {
collisionPos.add(s[i] + 1);
}
}
// positions at the corners are (maybe) forbidden
if (!this.COLLISION_RULES.ALLOW_CORNER_COLLISIONS) {
if (s[0] % this.FIELD_WIDTH > 0) {
collisionPos.add(s[0] - (this.FIELD_WIDTH + 1));
collisionPos.add(s[s.length - 1] + (this.FIELD_WIDTH - 1));
}
if ((s[0] + 1) % this.FIELD_WIDTH > 0) {
collisionPos.add(s[0] - (this.FIELD_WIDTH - 1));
collisionPos.add(s[s.length - 1] + (this.FIELD_WIDTH + 1));
}
}
return collisionPos;
}
getRequiredShipsListAsText() {
const reqShips = [];
for (let i = 0; i < this.REQUIREDSHIPS.length; i++) {
if (this.REQUIREDSHIPS[i] > 0) {
reqShips.push(this.REQUIREDSHIPS[i] + 'x ' + (i + 1) + 'er');
}
}
return reqShips.join(', ');
}
};
javascript game node.js validation battleship
New contributor
Alpha is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.
$endgroup$
$begingroup$
The code that is included in my question works absolutely fine. And all the tests of the project are successful. But it was -->ME<-- who wrote the test cases. So I'm not 100% sure whether there is MAYBE a scenario that I didn't think about that does not work as it should. (placing 2 2x1 ships on a 2x2 field with special options or something crazy....) :)
$endgroup$
– Alpha
1 hour ago
$begingroup$
all in all: It works absolutely fine but one can almost never say that there are 100% no bugs.
$endgroup$
– Alpha
1 hour ago
$begingroup$
OK Looks good. Have you tried pasting whole file? Does it cut off? Would be easier for reviewers if you can do it. :)
$endgroup$
– 422_unprocessable_entity
1 hour ago
$begingroup$
ok. Was not sure about that because the file has requirements and I though, seeing it on GitHub would be easier.
$endgroup$
– Alpha
1 hour ago
$begingroup$
my bad. I thought you wanted the whole file reviewed. Sorry about it
$endgroup$
– 422_unprocessable_entity
33 mins ago
add a comment |
$begingroup$
I wrote server-side Battleship game simulator in nodeJs/Javascript:
- A random player who begins is chosen.
- Both place their ships. Software recognizes if they are placed correctly.
- One of the players shoots at a position on the 10×10 field. If it's not this players turn, the program recognizes it; if it's the player's turn the program checks if the player hit a ship of the opponent. If he/she hit a ship, he/she can shoot again. If a ship is destroyed, the software recognizes that...
Its source code is available at: https://github.com/ndsvw/battleship
I also wrote 36 test cases (npm install, npm run test) and it works.
I would like to improve the code and want to make sure that it does always work (all imaginable scenarios).
An example: the file src/field.js contains checkShipArray(arr) that takes an array like [67, 77, 31, 41, 51, 61, 71, 0, 1, 2, 16, 17, 18, 96, 97, 98, 99] and returns an object with a status 'success'/'fail' and an array of ships:
{
status: 'success',
ships:
[
[ 31, 41, 51, 61, 71 ],
[ 67, 77 ],
[ 0, 1, 2 ],
[ 16, 17, 18 ],
[ 96, 97, 98, 99 ]
]
}
But the code that makes this is ~200 lines long. My main problem:
The 2 functions getCollisionPosOfHorizontalShip and getCollisionPosOfVerticalShip do almost look the same but I can't figure out how to write it shorter.
This is the whole field.js file:
const PositionSet = require('./positionset');
const RandomFieldGenerator = require('./random-field-generator');
module.exports = class Feld {
constructor(options) {
options = options || {};
this.SAMEPLAYERSTURNAFTERHIT = typeof options.SAMEPLAYERSTURNAFTERHIT === 'undefined' ? true : options.SAMEPLAYERSTURNAFTERHIT;
this.REQUIREDSHIPS = options.REQUIREDSHIPS || [0, 1, 2, 1, 1]; // default: 0x 1er, 1x 2er, 2x 3er, 1x 4er, 1x 5er
this.FIELD_HEIGHT = options.FIELD_HEIGHT || 10;
this.FIELD_WIDTH = options.FIELD_WIDTH || 10;
this.COLLISION_RULES = options.COLLISION_RULES || {
ALLOW_CORNER_COLLISIONS: true // in the default field: [0,1,2,3,4,15,16] for example
};
this.SHIPCOUNTER = 0;
this.SHIPPOSCOUNTER = 0;
for (let i = 0; i < this.REQUIREDSHIPS.length; i++) {
if (this.REQUIREDSHIPS[i] > 0) {
this.SHIPCOUNTER += this.REQUIREDSHIPS[i];
}
this.SHIPPOSCOUNTER += this.REQUIREDSHIPS[i] * (i + 1);
}
this.ships = [];
this.hits = [];
this.misses = [];
if (this.REQUIREDSHIPS.length > this.FIELD_WIDTH && this.REQUIREDSHIPS.length > this.FIELD_WIDTH) {
throw new Error('At least 1 ship seems to be larger than the field.');
}
if (this.SHIPPOSCOUNTER > this.FIELD_WIDTH * this.FIELD_HEIGHT) {
throw new Error('The field is not large enough for all ships.');
}
}
isShipAt(pos) {
return this.ships.some((s) => s.includes(pos));
}
hasAlreadyBeenHit(pos) {
return this.hits.includes(pos);
}
hasAlreadyBeenMissed(pos) {
return this.misses.includes(pos);
}
isShipDestroyedAt(pos, opponentFeld) {
const ship = this.ships.find((s) => s.includes(pos)) || null;
return (ship !== null && ship.every((p) => opponentFeld.hasAlreadyBeenHit(p)));
}
setShips(arr) {
const data = this.checkShipArray(arr);
if (data.status === 'success') {
this.ships = data.ships;
return {
status: 'success'
};
}
return {
status: data.status,
reason: data.reason
};
}
setRandomShips() {
// only works for the default field so far
const rfg = new RandomFieldGenerator();
return this.setShips(rfg.generateField());
}
checkShipArray(arr) {
// eliminate duplicates
arr = Array.from(new Set(arr));
// sort ascending
arr.sort((a, b) => a - b);
// check whether all ships are placed
if (arr.length !== this.SHIPPOSCOUNTER) {
return {
status: 'fail',
reason: 'A problem occured. The following ships need to be placed: ' + this.getRequiredShipsListAsText()
};
}
// Check whether all ships are placed within the field
if (arr.some((s) => s < 0 || s > this.FIELD_HEIGHT * this.FIELD_WIDTH - 1)) {
return {
status: 'fail',
reason: 'A problem occured. Ships need to be placed within the field.'
};
}
// getting an array with all ships
const data = this.getShipsOfArray(arr);
const ships = data.shipArray;
const shipsH = data.shipArrayH;
const shipsV = data.shipArrayV;
// check whether the number of ships and their sized are correct
if (ships.length === this.SHIPCOUNTER) {
// deep copy the requirements; for each ship of length x: decrement the value of the index x.
// after that: check if all values of the array are 0.
const reqCheckArr = JSON.parse(JSON.stringify(this.REQUIREDSHIPS));
for (const s of ships) {
reqCheckArr[s.length - 1]--;
}
if (reqCheckArr.some((x) => x !== 0)) {
return {
status: 'fail',
reason: 'A problem occured. The following ships need to be placed: ' + this.getRequiredShipsListAsText()
};
}
} else {
return {
status: 'fail',
reason: 'A problem occured. The following ships need to be placed: ' + this.getRequiredShipsListAsText()
};
}
// Check whether all parts of the horizontal ships are in the same row (don't accept [8,9,10,11,12] in the default match)
for (const s of shipsH) {
const row = Math.floor(s[0] / this.FIELD_WIDTH);
for (let i = 1; i < s.length; i++) {
if (Math.floor(s[i] / this.FIELD_WIDTH) !== row) {
return {
status: 'fail',
reason: 'A problem occured. The following ships need to be placed: ' + this.getRequiredShipsListAsText()
};
}
}
}
// iterate over all ships and check whether they are at forbidden positions
const forbiddenPositions = this.getCollisionPos(shipsH, shipsV);
for (const s of ships) {
if (s.some((pos) => forbiddenPositions.hasPos(pos))) {
return {
status: 'fail',
reason: 'A problem occured. Ships must not collide!'
};
}
}
return {
status: 'success',
ships
};
}
getShipsOfArray(arr) {
const shipArray = [];
const shipArrayH = [];
const shipArrayV = [];
const arrH = []; // Array, that contains all the position of the horizontal ships.
// find vertical ships.
for (const s of arr) {
// if the position is already part of a ship, continue
if (shipArray.some((sh) => sh.includes(s))) {
continue;
}
let i = 0;
while (arr.includes(s + (i + 1) * this.FIELD_WIDTH)) {
i++;
}
if (i === 0) {
arrH.push(s);
} else {
const newShip = [];
for (let j = s; j < s + (i + 1) * this.FIELD_WIDTH; j += this.FIELD_WIDTH) {
newShip.push(j);
}
shipArray.push(newShip);
shipArrayV.push(newShip);
}
}
// find horizontal ships.
for (const s of arrH) {
// if the position is already part of a ship, continue
if (shipArray.some((sh) => sh.includes(s))) {
continue;
}
let i = 0;
const currentRow = Math.floor(s / this.FIELD_WIDTH);
// as long as the current position is in arr && if we are still in the same row => increment i
while (arr.includes(s + i + 1) && Math.floor((s + i + 1) / this.FIELD_WIDTH) === currentRow) {
i++;
}
if (i !== 0) {
const newShip = [];
for (let j = s; j < s + i + 1; j++) {
newShip.push(j);
}
shipArray.push(newShip);
shipArrayH.push(newShip);
}
}
return {
shipArray,
shipArrayH,
shipArrayV
};
}
getCollisionPos(shipsH, shipsV) {
const collisionPos = new PositionSet(this.FIELD_HEIGHT, this.FIELD_WIDTH);
for (const s of shipsH) {
collisionPos.union(this.getCollisionPosOfHorizontalShip(s));
}
for (const s of shipsV) {
collisionPos.union(this.getCollisionPosOfVerticalShip(s));
}
return collisionPos;
}
getCollisionPosOfHorizontalShip(s) {
const collisionPos = new PositionSet(this.FIELD_HEIGHT, this.FIELD_WIDTH);
// position in front of the ship and behind the ship are forbidden.
if (s[0] % this.FIELD_WIDTH > 0) {
collisionPos.add(s[0] - 1);
}
if ((s[s.length - 1] + 1) % this.FIELD_WIDTH > 0) {
collisionPos.add(s[s.length - 1] + 1);
}
// rows next to the ship and in parallel to the ship are forbidden
for (let i = 0; i < s.length; i++) {
collisionPos.add(s[i] - this.FIELD_WIDTH);
collisionPos.add(s[i] + this.FIELD_WIDTH);
}
// positions at the corners are (maybe) forbidden
if (!this.COLLISION_RULES.ALLOW_CORNER_COLLISIONS) {
if (s[0] % this.FIELD_WIDTH > 0) {
collisionPos.add(s[0] - (this.FIELD_WIDTH + 1));
collisionPos.add(s[0] + (this.FIELD_WIDTH - 1));
}
if ((s[0] + 1) % this.FIELD_WIDTH > 0) {
collisionPos.add(s[s.length - 1] - (this.FIELD_WIDTH - 1));
collisionPos.add(s[s.length - 1] + (this.FIELD_WIDTH + 1));
}
}
return collisionPos;
}
getCollisionPosOfVerticalShip(s) {
const collisionPos = new PositionSet(this.FIELD_HEIGHT, this.FIELD_WIDTH);
// position in front of the ship and behind the ship are forbidden.
collisionPos.add(s[0] - this.FIELD_WIDTH);
collisionPos.add(s[s.length - 1] + this.FIELD_WIDTH);
// rows next to the ship and in parallel to the ship are forbidden
for (let i = 0; i < s.length; i++) {
if (s[i] % this.FIELD_WIDTH > 0) {
collisionPos.add(s[i] - 1);
}
if ((s[i] + 1) % this.FIELD_WIDTH > 0) {
collisionPos.add(s[i] + 1);
}
}
// positions at the corners are (maybe) forbidden
if (!this.COLLISION_RULES.ALLOW_CORNER_COLLISIONS) {
if (s[0] % this.FIELD_WIDTH > 0) {
collisionPos.add(s[0] - (this.FIELD_WIDTH + 1));
collisionPos.add(s[s.length - 1] + (this.FIELD_WIDTH - 1));
}
if ((s[0] + 1) % this.FIELD_WIDTH > 0) {
collisionPos.add(s[0] - (this.FIELD_WIDTH - 1));
collisionPos.add(s[s.length - 1] + (this.FIELD_WIDTH + 1));
}
}
return collisionPos;
}
getRequiredShipsListAsText() {
const reqShips = [];
for (let i = 0; i < this.REQUIREDSHIPS.length; i++) {
if (this.REQUIREDSHIPS[i] > 0) {
reqShips.push(this.REQUIREDSHIPS[i] + 'x ' + (i + 1) + 'er');
}
}
return reqShips.join(', ');
}
};
javascript game node.js validation battleship
New contributor
Alpha is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.
$endgroup$
I wrote server-side Battleship game simulator in nodeJs/Javascript:
- A random player who begins is chosen.
- Both place their ships. Software recognizes if they are placed correctly.
- One of the players shoots at a position on the 10×10 field. If it's not this players turn, the program recognizes it; if it's the player's turn the program checks if the player hit a ship of the opponent. If he/she hit a ship, he/she can shoot again. If a ship is destroyed, the software recognizes that...
Its source code is available at: https://github.com/ndsvw/battleship
I also wrote 36 test cases (npm install, npm run test) and it works.
I would like to improve the code and want to make sure that it does always work (all imaginable scenarios).
An example: the file src/field.js contains checkShipArray(arr) that takes an array like [67, 77, 31, 41, 51, 61, 71, 0, 1, 2, 16, 17, 18, 96, 97, 98, 99] and returns an object with a status 'success'/'fail' and an array of ships:
{
status: 'success',
ships:
[
[ 31, 41, 51, 61, 71 ],
[ 67, 77 ],
[ 0, 1, 2 ],
[ 16, 17, 18 ],
[ 96, 97, 98, 99 ]
]
}
But the code that makes this is ~200 lines long. My main problem:
The 2 functions getCollisionPosOfHorizontalShip and getCollisionPosOfVerticalShip do almost look the same but I can't figure out how to write it shorter.
This is the whole field.js file:
const PositionSet = require('./positionset');
const RandomFieldGenerator = require('./random-field-generator');
module.exports = class Feld {
constructor(options) {
options = options || {};
this.SAMEPLAYERSTURNAFTERHIT = typeof options.SAMEPLAYERSTURNAFTERHIT === 'undefined' ? true : options.SAMEPLAYERSTURNAFTERHIT;
this.REQUIREDSHIPS = options.REQUIREDSHIPS || [0, 1, 2, 1, 1]; // default: 0x 1er, 1x 2er, 2x 3er, 1x 4er, 1x 5er
this.FIELD_HEIGHT = options.FIELD_HEIGHT || 10;
this.FIELD_WIDTH = options.FIELD_WIDTH || 10;
this.COLLISION_RULES = options.COLLISION_RULES || {
ALLOW_CORNER_COLLISIONS: true // in the default field: [0,1,2,3,4,15,16] for example
};
this.SHIPCOUNTER = 0;
this.SHIPPOSCOUNTER = 0;
for (let i = 0; i < this.REQUIREDSHIPS.length; i++) {
if (this.REQUIREDSHIPS[i] > 0) {
this.SHIPCOUNTER += this.REQUIREDSHIPS[i];
}
this.SHIPPOSCOUNTER += this.REQUIREDSHIPS[i] * (i + 1);
}
this.ships = [];
this.hits = [];
this.misses = [];
if (this.REQUIREDSHIPS.length > this.FIELD_WIDTH && this.REQUIREDSHIPS.length > this.FIELD_WIDTH) {
throw new Error('At least 1 ship seems to be larger than the field.');
}
if (this.SHIPPOSCOUNTER > this.FIELD_WIDTH * this.FIELD_HEIGHT) {
throw new Error('The field is not large enough for all ships.');
}
}
isShipAt(pos) {
return this.ships.some((s) => s.includes(pos));
}
hasAlreadyBeenHit(pos) {
return this.hits.includes(pos);
}
hasAlreadyBeenMissed(pos) {
return this.misses.includes(pos);
}
isShipDestroyedAt(pos, opponentFeld) {
const ship = this.ships.find((s) => s.includes(pos)) || null;
return (ship !== null && ship.every((p) => opponentFeld.hasAlreadyBeenHit(p)));
}
setShips(arr) {
const data = this.checkShipArray(arr);
if (data.status === 'success') {
this.ships = data.ships;
return {
status: 'success'
};
}
return {
status: data.status,
reason: data.reason
};
}
setRandomShips() {
// only works for the default field so far
const rfg = new RandomFieldGenerator();
return this.setShips(rfg.generateField());
}
checkShipArray(arr) {
// eliminate duplicates
arr = Array.from(new Set(arr));
// sort ascending
arr.sort((a, b) => a - b);
// check whether all ships are placed
if (arr.length !== this.SHIPPOSCOUNTER) {
return {
status: 'fail',
reason: 'A problem occured. The following ships need to be placed: ' + this.getRequiredShipsListAsText()
};
}
// Check whether all ships are placed within the field
if (arr.some((s) => s < 0 || s > this.FIELD_HEIGHT * this.FIELD_WIDTH - 1)) {
return {
status: 'fail',
reason: 'A problem occured. Ships need to be placed within the field.'
};
}
// getting an array with all ships
const data = this.getShipsOfArray(arr);
const ships = data.shipArray;
const shipsH = data.shipArrayH;
const shipsV = data.shipArrayV;
// check whether the number of ships and their sized are correct
if (ships.length === this.SHIPCOUNTER) {
// deep copy the requirements; for each ship of length x: decrement the value of the index x.
// after that: check if all values of the array are 0.
const reqCheckArr = JSON.parse(JSON.stringify(this.REQUIREDSHIPS));
for (const s of ships) {
reqCheckArr[s.length - 1]--;
}
if (reqCheckArr.some((x) => x !== 0)) {
return {
status: 'fail',
reason: 'A problem occured. The following ships need to be placed: ' + this.getRequiredShipsListAsText()
};
}
} else {
return {
status: 'fail',
reason: 'A problem occured. The following ships need to be placed: ' + this.getRequiredShipsListAsText()
};
}
// Check whether all parts of the horizontal ships are in the same row (don't accept [8,9,10,11,12] in the default match)
for (const s of shipsH) {
const row = Math.floor(s[0] / this.FIELD_WIDTH);
for (let i = 1; i < s.length; i++) {
if (Math.floor(s[i] / this.FIELD_WIDTH) !== row) {
return {
status: 'fail',
reason: 'A problem occured. The following ships need to be placed: ' + this.getRequiredShipsListAsText()
};
}
}
}
// iterate over all ships and check whether they are at forbidden positions
const forbiddenPositions = this.getCollisionPos(shipsH, shipsV);
for (const s of ships) {
if (s.some((pos) => forbiddenPositions.hasPos(pos))) {
return {
status: 'fail',
reason: 'A problem occured. Ships must not collide!'
};
}
}
return {
status: 'success',
ships
};
}
getShipsOfArray(arr) {
const shipArray = [];
const shipArrayH = [];
const shipArrayV = [];
const arrH = []; // Array, that contains all the position of the horizontal ships.
// find vertical ships.
for (const s of arr) {
// if the position is already part of a ship, continue
if (shipArray.some((sh) => sh.includes(s))) {
continue;
}
let i = 0;
while (arr.includes(s + (i + 1) * this.FIELD_WIDTH)) {
i++;
}
if (i === 0) {
arrH.push(s);
} else {
const newShip = [];
for (let j = s; j < s + (i + 1) * this.FIELD_WIDTH; j += this.FIELD_WIDTH) {
newShip.push(j);
}
shipArray.push(newShip);
shipArrayV.push(newShip);
}
}
// find horizontal ships.
for (const s of arrH) {
// if the position is already part of a ship, continue
if (shipArray.some((sh) => sh.includes(s))) {
continue;
}
let i = 0;
const currentRow = Math.floor(s / this.FIELD_WIDTH);
// as long as the current position is in arr && if we are still in the same row => increment i
while (arr.includes(s + i + 1) && Math.floor((s + i + 1) / this.FIELD_WIDTH) === currentRow) {
i++;
}
if (i !== 0) {
const newShip = [];
for (let j = s; j < s + i + 1; j++) {
newShip.push(j);
}
shipArray.push(newShip);
shipArrayH.push(newShip);
}
}
return {
shipArray,
shipArrayH,
shipArrayV
};
}
getCollisionPos(shipsH, shipsV) {
const collisionPos = new PositionSet(this.FIELD_HEIGHT, this.FIELD_WIDTH);
for (const s of shipsH) {
collisionPos.union(this.getCollisionPosOfHorizontalShip(s));
}
for (const s of shipsV) {
collisionPos.union(this.getCollisionPosOfVerticalShip(s));
}
return collisionPos;
}
getCollisionPosOfHorizontalShip(s) {
const collisionPos = new PositionSet(this.FIELD_HEIGHT, this.FIELD_WIDTH);
// position in front of the ship and behind the ship are forbidden.
if (s[0] % this.FIELD_WIDTH > 0) {
collisionPos.add(s[0] - 1);
}
if ((s[s.length - 1] + 1) % this.FIELD_WIDTH > 0) {
collisionPos.add(s[s.length - 1] + 1);
}
// rows next to the ship and in parallel to the ship are forbidden
for (let i = 0; i < s.length; i++) {
collisionPos.add(s[i] - this.FIELD_WIDTH);
collisionPos.add(s[i] + this.FIELD_WIDTH);
}
// positions at the corners are (maybe) forbidden
if (!this.COLLISION_RULES.ALLOW_CORNER_COLLISIONS) {
if (s[0] % this.FIELD_WIDTH > 0) {
collisionPos.add(s[0] - (this.FIELD_WIDTH + 1));
collisionPos.add(s[0] + (this.FIELD_WIDTH - 1));
}
if ((s[0] + 1) % this.FIELD_WIDTH > 0) {
collisionPos.add(s[s.length - 1] - (this.FIELD_WIDTH - 1));
collisionPos.add(s[s.length - 1] + (this.FIELD_WIDTH + 1));
}
}
return collisionPos;
}
getCollisionPosOfVerticalShip(s) {
const collisionPos = new PositionSet(this.FIELD_HEIGHT, this.FIELD_WIDTH);
// position in front of the ship and behind the ship are forbidden.
collisionPos.add(s[0] - this.FIELD_WIDTH);
collisionPos.add(s[s.length - 1] + this.FIELD_WIDTH);
// rows next to the ship and in parallel to the ship are forbidden
for (let i = 0; i < s.length; i++) {
if (s[i] % this.FIELD_WIDTH > 0) {
collisionPos.add(s[i] - 1);
}
if ((s[i] + 1) % this.FIELD_WIDTH > 0) {
collisionPos.add(s[i] + 1);
}
}
// positions at the corners are (maybe) forbidden
if (!this.COLLISION_RULES.ALLOW_CORNER_COLLISIONS) {
if (s[0] % this.FIELD_WIDTH > 0) {
collisionPos.add(s[0] - (this.FIELD_WIDTH + 1));
collisionPos.add(s[s.length - 1] + (this.FIELD_WIDTH - 1));
}
if ((s[0] + 1) % this.FIELD_WIDTH > 0) {
collisionPos.add(s[0] - (this.FIELD_WIDTH - 1));
collisionPos.add(s[s.length - 1] + (this.FIELD_WIDTH + 1));
}
}
return collisionPos;
}
getRequiredShipsListAsText() {
const reqShips = [];
for (let i = 0; i < this.REQUIREDSHIPS.length; i++) {
if (this.REQUIREDSHIPS[i] > 0) {
reqShips.push(this.REQUIREDSHIPS[i] + 'x ' + (i + 1) + 'er');
}
}
return reqShips.join(', ');
}
};
javascript game node.js validation battleship
javascript game node.js validation battleship
New contributor
Alpha is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.
New contributor
Alpha is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.
edited 3 mins ago
200_success
130k16153417
130k16153417
New contributor
Alpha is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.
asked 2 hours ago
AlphaAlpha
1112
1112
New contributor
Alpha is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.
New contributor
Alpha is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.
Alpha is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.
$begingroup$
The code that is included in my question works absolutely fine. And all the tests of the project are successful. But it was -->ME<-- who wrote the test cases. So I'm not 100% sure whether there is MAYBE a scenario that I didn't think about that does not work as it should. (placing 2 2x1 ships on a 2x2 field with special options or something crazy....) :)
$endgroup$
– Alpha
1 hour ago
$begingroup$
all in all: It works absolutely fine but one can almost never say that there are 100% no bugs.
$endgroup$
– Alpha
1 hour ago
$begingroup$
OK Looks good. Have you tried pasting whole file? Does it cut off? Would be easier for reviewers if you can do it. :)
$endgroup$
– 422_unprocessable_entity
1 hour ago
$begingroup$
ok. Was not sure about that because the file has requirements and I though, seeing it on GitHub would be easier.
$endgroup$
– Alpha
1 hour ago
$begingroup$
my bad. I thought you wanted the whole file reviewed. Sorry about it
$endgroup$
– 422_unprocessable_entity
33 mins ago
add a comment |
$begingroup$
The code that is included in my question works absolutely fine. And all the tests of the project are successful. But it was -->ME<-- who wrote the test cases. So I'm not 100% sure whether there is MAYBE a scenario that I didn't think about that does not work as it should. (placing 2 2x1 ships on a 2x2 field with special options or something crazy....) :)
$endgroup$
– Alpha
1 hour ago
$begingroup$
all in all: It works absolutely fine but one can almost never say that there are 100% no bugs.
$endgroup$
– Alpha
1 hour ago
$begingroup$
OK Looks good. Have you tried pasting whole file? Does it cut off? Would be easier for reviewers if you can do it. :)
$endgroup$
– 422_unprocessable_entity
1 hour ago
$begingroup$
ok. Was not sure about that because the file has requirements and I though, seeing it on GitHub would be easier.
$endgroup$
– Alpha
1 hour ago
$begingroup$
my bad. I thought you wanted the whole file reviewed. Sorry about it
$endgroup$
– 422_unprocessable_entity
33 mins ago
$begingroup$
The code that is included in my question works absolutely fine. And all the tests of the project are successful. But it was -->ME<-- who wrote the test cases. So I'm not 100% sure whether there is MAYBE a scenario that I didn't think about that does not work as it should. (placing 2 2x1 ships on a 2x2 field with special options or something crazy....) :)
$endgroup$
– Alpha
1 hour ago
$begingroup$
The code that is included in my question works absolutely fine. And all the tests of the project are successful. But it was -->ME<-- who wrote the test cases. So I'm not 100% sure whether there is MAYBE a scenario that I didn't think about that does not work as it should. (placing 2 2x1 ships on a 2x2 field with special options or something crazy....) :)
$endgroup$
– Alpha
1 hour ago
$begingroup$
all in all: It works absolutely fine but one can almost never say that there are 100% no bugs.
$endgroup$
– Alpha
1 hour ago
$begingroup$
all in all: It works absolutely fine but one can almost never say that there are 100% no bugs.
$endgroup$
– Alpha
1 hour ago
$begingroup$
OK Looks good. Have you tried pasting whole file? Does it cut off? Would be easier for reviewers if you can do it. :)
$endgroup$
– 422_unprocessable_entity
1 hour ago
$begingroup$
OK Looks good. Have you tried pasting whole file? Does it cut off? Would be easier for reviewers if you can do it. :)
$endgroup$
– 422_unprocessable_entity
1 hour ago
$begingroup$
ok. Was not sure about that because the file has requirements and I though, seeing it on GitHub would be easier.
$endgroup$
– Alpha
1 hour ago
$begingroup$
ok. Was not sure about that because the file has requirements and I though, seeing it on GitHub would be easier.
$endgroup$
– Alpha
1 hour ago
$begingroup$
my bad. I thought you wanted the whole file reviewed. Sorry about it
$endgroup$
– 422_unprocessable_entity
33 mins ago
$begingroup$
my bad. I thought you wanted the whole file reviewed. Sorry about it
$endgroup$
– 422_unprocessable_entity
33 mins ago
add a comment |
0
active
oldest
votes
Your Answer
StackExchange.ifUsing("editor", function () {
return StackExchange.using("mathjaxEditing", function () {
StackExchange.MarkdownEditor.creationCallbacks.add(function (editor, postfix) {
StackExchange.mathjaxEditing.prepareWmdForMathJax(editor, postfix, [["\$", "\$"]]);
});
});
}, "mathjax-editing");
StackExchange.ifUsing("editor", function () {
StackExchange.using("externalEditor", function () {
StackExchange.using("snippets", function () {
StackExchange.snippets.init();
});
});
}, "code-snippets");
StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "196"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);
StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});
function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: false,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: null,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});
}
});
Alpha is a new contributor. Be nice, and check out our Code of Conduct.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f214795%2fship-placement-verification-function-for-battleship-game%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
0
active
oldest
votes
0
active
oldest
votes
active
oldest
votes
active
oldest
votes
Alpha is a new contributor. Be nice, and check out our Code of Conduct.
Alpha is a new contributor. Be nice, and check out our Code of Conduct.
Alpha is a new contributor. Be nice, and check out our Code of Conduct.
Alpha is a new contributor. Be nice, and check out our Code of Conduct.
Thanks for contributing an answer to Code Review Stack Exchange!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
Use MathJax to format equations. MathJax reference.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f214795%2fship-placement-verification-function-for-battleship-game%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
$begingroup$
The code that is included in my question works absolutely fine. And all the tests of the project are successful. But it was -->ME<-- who wrote the test cases. So I'm not 100% sure whether there is MAYBE a scenario that I didn't think about that does not work as it should. (placing 2 2x1 ships on a 2x2 field with special options or something crazy....) :)
$endgroup$
– Alpha
1 hour ago
$begingroup$
all in all: It works absolutely fine but one can almost never say that there are 100% no bugs.
$endgroup$
– Alpha
1 hour ago
$begingroup$
OK Looks good. Have you tried pasting whole file? Does it cut off? Would be easier for reviewers if you can do it. :)
$endgroup$
– 422_unprocessable_entity
1 hour ago
$begingroup$
ok. Was not sure about that because the file has requirements and I though, seeing it on GitHub would be easier.
$endgroup$
– Alpha
1 hour ago
$begingroup$
my bad. I thought you wanted the whole file reviewed. Sorry about it
$endgroup$
– 422_unprocessable_entity
33 mins ago