Display images according to number set from interval - javascript

i try to display from svg ,layers according to numbers set from an interval.I have 2 random numbers (left and right) set to display from interval (10,99) both.That works good,but, i need to display layer 1(banane1) from svg if left || right belongs to interval (10,20) , then if left || right belongs to interval (20,30) to display layer 2(banane2) from svg and so on untill left || right belongs to interval (90,99) to display layer 9(banane9). There are 9 intervals and 9 layers from svg to display. Code i wrote looks like :
FIDDLE: http://jsfiddle.net/r68Bg/
for(var i = 0; i < 2; i++){
panouri = document.getElementById('panou' + i);
svgDoc = panouri.contentDocument;
}
where panou0 and panou1 are 2 svg that has layers 2 numbers where i display later random numbers set from intervals and 9 layers each with different content which must be displayed according to random numbers.
function randomIntFromInterval(min,max)
{
return Math.floor(Math.random()*(max-min+1)+min);
};
function conditions(){
left = randomIntFromInterval(10,99);
right = randomIntFromInterval(10,99);
for(var i = 0; i < 2; i++){
ecuations.push(left, right);
randoms = document.getElementById("panou" + i).contentDocument;
numere = randoms.getElementById("number");
numere.textContent = ecuations[i];
}
};
where i add into my svg (panou0 and panou1) randoms numbers from set intervals.
function setBananeState(state)
{
for(var i = 1; i < 10; i++){
svgItem = svgDoc.getElementById("banane" + i);
svgItem.setAttribute("display", "none");
svgItem = svgDoc.getElementById(state);
svgItem.setAttribute("display", "inline");
}
};
function getBanane(){
if(left || right >= 30 && left || right <= 40){
bananeState = "banane3";
setBananeState(bananeState);
}
};
Here i have all layers from svgs which contains bananas to display according to random number given and a function getBanane() which has condition to display layer1 (banane1 by id from svg) if random number is from interval (10,20).Unfortunately this doesnt work...and i must have 8 more condition to display layers from svg if random numbers are from different interval

This isn't going to work:
if(left || right == randomIntFromInterval(10,20)){
What you are doing here is a ORing left with right which will give you a boolean which you are then comparing to randomIntFromInterval. I think what you are trying to do is this:
var interval = randomIntFromInterval(10,20);
if (left == interval || right == interval) {
EDIT: Okay you changed your question. So now this:
if(left || right >= 30 && left || right <= 40){
Is not right, you can't write an if statement like that in javascript, or in most (probably all) programming languages. You can't say "if a or b is greater than x", like you would in normal English speech because it's ambiguous. You have to explicitly say "if (a is greater than x) or (b is greater than x)". So your if statement above needs to become:
if ((left >= 30 || right >=30) && (left <= 40 || right <= 40)) {
Although I'm not sure this is exactly what you want either. Because here if left==0 and right==41, then this statement would be true. I think you want either left or right to be in the interval, so your best check would be:
if ((left >= 30 && left <= 40) || (right >= 30 && right <= 40)) {

Related

Restore read position in dynamic content on next visit

I have a big chapter of a book that my user reads. Chapters can have any font-size; the window can be any size. How can I save the exact position in text (top most of currently visible window) in a database, so when user continues to read this chapter from any device, I can scroll him there?
I was trying with window.pageYOffset, then percentage of scroll position, but it's not accurate with dynamic window and font-size, and can only work in same environment (font-size, windows size).
My only idea now is to split the chapter into lines:
const lines = (chapter.match(/\r?\n/g) || '').length + 1
And then somehow find a line that is top most of the currently visible window, save its number, and scroll to it on load.
As an alternative, maybe something that can give me the currently top most visible html element so I can stick to it.
Any ideas?
Update: now I'm trying to get all the elements in the parent of the content div and iterate through them getting the element position in the viewport with getBoundingClientRect(). I have hopes for it.
First you get array of paragraphs
let children = Array.from(contentRef.current.children)
Them do binary search of the closest to zero (top of the visible screen) paragraph.
let closestIndex = binaryClosest(
children,
target => 0 - target.getBoundingClientRect().y
)
localStorage.setItem('index', closestIndex)
function binaryClosest(a, compare) {
let i = binarySearch()
if (i === 0) return 0
if (i === a.length) return i - 1
let d1 = -compare(a[i]),
d2 = compare(a[i - 1])
return d1 < d2 ? i : i - 1
function binarySearch() {
let le = 0,
ri = a.length - 1
while (le <= ri) {
let mid = (le + ri) >> 1,
cmp = compare(a[mid])
if (cmp > 0) {
le = mid + 1
} else if (cmp < 0) {
ri = mid - 1
} else {
return mid
}
}
return le
}
}
Now you can save this closestIndex in database and on next load scroll to it:
let children = Array.from(contentRef.current.children)
window.scrollTo(0, children[localStorage.getItem('index')].offsetTop)

Javascript - Flood-Fill and scanLine algorithms are line-based floods but I want square based floods

I have a flood-fill algorithm (Flood-fill) to fill a 24x24 matrix. I would like to draw a shape as similar to a square using exactly cspots spots for each group as cspots can contain any number. The total of all groups cspots value will equal (24*24) so as the drawing progresses, the areas will become less and less square-like but I would like to keep the semblance of a square. In this example, there are 10 groups of varying cspots values and they need to be all drawn within the 24*24 matrix as square-like as possible. Matrix is 24x24 here but will be bigger with more groups in production. Code:
Main code:
var cspots, // number of spots per group
gArr=[]; // global array which contains all group spots
var tArr = new Array(gArr.length); // touch array for flood-fill
for(var spot in inArr) {
for (var tspot in tArr) // initialise touch array
tArr[tspot]=0;
for(gspot in gArr) { // find lowest open y*24+x ordinal
if (gArr[gspot][0] == 0)
break;
tArr[gspot]=1;
}
cspots = inArr[spot].GD;
userFill(gArr[gspot][1],gArr[gspot][2],inArr[spot].KY,tArr);
}
function userFill(x,y,elem,tArr) {
var gord, qt=0;
if (!cspots) return;
if ((x >= 0) && (x <= 23) && (y >= 0) && (y <= 23)) {
gord = y*24 + x;
if (gArr[gord][0] != 0 || tArr[gord])
return;
gArr[gord][0] = elem;
tArr[gord] = 1;
--cspots;
userFill(x+1,y,elem,tArr);
userFill(x-1,y,elem,tArr);
// before the y-change we need to see if there are any open spots on this line
for(gord=y*24; gord<=(y*24)+23; gord++) {
if (gArr[gord][0] == 0) {
qt=1;
break;
}
}
if (!qt) {
userFill(x,y+1,elem,tArr);
userFill(x,y-1,elem,tArr);
}
}
};
This is a standard flood-fill recursive algorithm (with an accompanying touch array to mark any touches) with the additional code that I check if all x-values are set to non-zero on each x-plane before changing the y-value. This produces a matrix like this:
The problem is that it doesn't look very good (imo) as most of the areas are strung-out along the x-plane. What I want is each different group area to be in the shape of a square as much as I can. Sort-of like this example (using letters to indicate the different group areas):
V V V W W W W X X X X X
V V Y W W W W X X X X Z
Y Y Y W W W W Z Z Z Z Z
Y Y W W W W Z Z Z Z Z
... and so on
So I have changed the userFill to look at a boxX variable which is just the (sqrt of each area)+1, which hopefully I can use to limit each area to make a square-shape. And a preX variable to store the anchor point from each group area so I know how many spots have been added. Here's the new userFill:
Main code:
var tArr = new Array(gArr.length);
for(var spot in inArr) {
for (var tspot in tArr) // initialise touch array
tArr[tspot]=0;
for(gspot in gArr) { // find lowest open y*24+x ordinal
if (gArr[gspot][0] == 0)
break;
tArr[gspot]=1;
}
cspots = inArr[spot].GD;
boxX = Math.ceil(Math.sqrt(cspots));
preX = gArr[gspot][1];
userFill(gArr[gspot][1],gArr[gspot][2],inArr[spot].KY,tArr);
}
function userFill(x,y,elem,tArr) {
var gord, qt=0;
if (!cspots) return;
if ((x >= 0) && (x <= 23) && (y >= 0) && (y <= 23)) {
gord = y*24 + x;
if (gArr[gord][0] != 0 || tArr[gord])
return;
gArr[gord][0] = elem;
tArr[gord] = 1;
--cspots;
// before the x-change we need to see if we have done a boxX number of changes to maintain square-shape
if (Math.abs(x-preX) == boxX) {
userFill(preX,y+1,elem,tArr);
userFill(preX,y-1,elem,tArr);
return;
}
userFill(x+1,y,elem,tArr);
userFill(x-1,y,elem,tArr);
// before the y-change we need to see if there are any open spots on this line
for(gord=y*24; gord<=(y*24)+boxX; gord++) {
if (gArr[gord][0] == 0) {
qt=1;
break;
}
}
if (!qt) {
userFill(x,y+1,elem,tArr);
userFill(x,y-1,elem,tArr);
}
}
};
The only difference is that I check if boxX spots have been added and then call userFill recursively to change the y-plane.
Here's the output and it looks better as most areas are square-like but obviously it needs work (missing most of the spots, pale-blue group area is very oddly-shaped and not square-like at all), but I wonder if there is a better algorithm out there that changes a flood-fill from line-based to square based.
FIXED:
I used a Breadth-First Search which created square-like structures for each group area. The code is:
function bfsFill(x,y,elem,tArr) {
var gord, i=0, pt, queue=[], cnt=0;
if (!cspots) return;
if (isOutOfBounds(x,y)) return;
queue.push([x,y]);
while(cspots>0 && queue.length>0) {
pt = queue.shift();
gord = pt[1]*24 + pt[0];
tArr[gord] = 1;
gArr[gord][0] = elem;
--cspots;
var rArr = neighbours(pt);
async.eachSeries(rArr, function(el, cb2) {
if (!isOutOfBounds(el[0],el[1])) {
gord = el[1]*24 + el[0];
if (tArr[gord] == 0 && gArr[gord][0] == 0) {
for(var qi in queue) {
if (queue[qi][0] == el[0] && queue[qi][1]==el[1]) {
cb2();
return;
}
}
queue.push(el);
}
}
cb2();
}, function(err) {
});
}
};

What is wrong with this code? Am I going about this the right way?

Okay, so I'm fairly new to programming. I've been learning to code for quite sometime now, but I hadn't really MADE anything. That considered, I'm attempting to make my first project using JavaScript and make a snake game. Unfortunately, I've ran into multiple problems, which obviously is something that comes hand in hand with programming, but I am new and I'm stuck. Can someone help me figure out if I'm coding this in an efficient way. Also, I have a more specific issue. I've added basic movement functionality to the head of my snake, but I can't figure out how to get the rest of it's parts to follow. If someone could explain to me how to do this, that would be incredible. I've worked about two weeks now to try and figure it out and I'm just stumped. I'm using Raphael's JavaScript Library to generate the graphics on an SVG canvas.
/*
Libraries in use:
1. Rapheal
2. jQuery
*/
// This variable is set to an array so that we can add multiple snakeParts to our PrimarySnake.
var snakeParts = [],
// This variable uses Raphael to generate a canvas.
snakeCanvas = Raphael(10, 10, 400, 400),
// This generates a rectangle that fills the canvas.
snakeCanvasBg = snakeCanvas.rect(0,0,400,400),
// This variable is set to an array so that we can use each and every direction that is pressed.
direction = [],
// This variable is set to an array so that we can use the turn coordinates of our first snake part.
turnCoords = [];
// Generates and returns a random number between 0 and 400. This function is used to help generate the goal of our snake at a random location on the canvas.
function getRandNum () {
var rand = Math.round(Math.random()*400);
// This while loop ensures that our snakeGoal never exceeds the coordinates x = 390 or y = 390. If it did, it's parts would be cut from the canvas.
while (rand > 395) {
rand = Math.round(Math.random()*400);
}
// This while loop ensures that our rand variabe will always be divisible by 10, which is used to make sure our snakeGoal and snakePart elements are always rendered in coordinates divisible by 10.
while (rand % 10 !== 0) {
var randString = rand.toString(),
// This variable stores the whole length of our randString variable.
randStringLength = randString.length,
// This variable stores the last number of our rand as a string character.
subtractionChar = randString.charAt(randStringLength - 1),
// This variable stores the last number of our rand as a integer.
subtractionInt = parseInt(subtractionChar),
// Finally, this line subtracts the last number of our rand from the entirety and then sets that value equal to rand, ensuring that rand is always divisible by 10.
rand = rand - subtractionInt;
}
return rand;
}
// This function is called any time a button is pressed. The jQuery which method allows our code to compare if the key pressed is equal to the keyCode of a designated key.
$(document).keydown(
function (pressedDirection) {
if (pressedDirection.which === 37) {
direction.push("left");
} else if (pressedDirection.which === 38) {
direction.push("up");
} else if (pressedDirection.which === 39) {
direction.push("right");
} else if (pressedDirection.which === 40) {
direction.push("down");
} else if (pressedDirection.which === 32) {
direction.push("stop");
}
if (pressedDirection.which === 37 || pressedDirection.which === 38 || pressedDirection.which === 39 || pressedDirection.which === 40 || pressedDirection.which === 32) {
console.log(direction[direction.length - 1]);
PrimarySnake.addTurnCoords();
PrimarySnake.movePeice();
}
// This prevents our screen from scrolling when an arrow key is
pressedDirection.preventDefault();
}
);
function Snake () {
// This method generates a new peice to the Snake.
this.addPart = function () {
console.log(snakeParts.length);
snakeParts[snakeParts.length] = snakeCanvas.rect(0,0,10,10);
snakeParts[snakeParts.length - 1].attr("fill", "blue");
snakeParts[snakeParts.length - 1].attr("stroke-width", ".25");
}
// This method provides the movement functionality of our Snake.
this.moveDirection = function () {
for (value in snakeParts) {
var currentCoord = [snakeParts[value].attr("x"), snakeParts[value].attr("y")];
// This if-else statement moves the snakePart at the -value- index up, down, left, or right according to the last direction pressed.
if (direction[direction.length - 1] === "up") {
snakeParts[value].attr("y", currentCoord[1] - 10);
} else if (direction[direction.length - 1] === "down") {
snakeParts[value].attr("y", currentCoord[1] + 10);
} else if (direction[direction.length - 1] === "left") {
snakeParts[value].attr("x", currentCoord[0] - 10);
} else if (direction[direction.length - 1] === "right") {
snakeParts[value].attr("x", currentCoord[0] + 10);
}
}
}
this.moveInterval;
// This function makes our moveDirection move our snakePeice every 50 milliseconds.
this.movePeice = function () {
var moveDirection = this.moveDirection;
// clearInterval is used to eliminate any interval previously running, ensuring that our peices only move one direction at a time.
clearInterval(this.moveInterval);
this.moveInterval = setInterval(function(){moveDirection()}, 50);
}
// This function adds an array of coordinates to the turnCoords array.
this.addTurnCoords = function () {
turnCoords.push([snakeParts[0].attr("x"), snakeParts[0].attr("y")]);
}
}
// This generates a new instance of our Snake class.
var PrimarySnake = new Snake();
// This generates a new part on the canvas.
PrimarySnake.addPart();
// This fills our snakeCanvasBg with a grey color, giving us a grey background.
snakeCanvasBg.attr("fill", "#CDCDCD");
Well, your code seems nice, or at least "efficient" as you are calling it.
To make the parts of your snake follow its head, you must iterate through its parts and assign each (n+1) piece the coordinates from (n). To do so, start with the last piece and iterate up to the first one, which movement is defined by the user, like in:
this.moveDirection = function () {
// Move every piece except the head.
for (var i = snakeParts.length - 1; i > 0; i--) {
snakeParts[i].attr("x", snakeParts[i-1].attr("x"));
snakeParts[i].attr("y", snakeParts[i-1].attr("y"));
}
// Now move the head.
if (direction[direction.length - 1] === "up") {
snakeParts[value].attr("y", currentCoord[1] - 10);
} else if (direction[direction.length - 1] === "down") {
snakeParts[value].attr("y", currentCoord[1] + 10);
} else if (direction[direction.length - 1] === "left") {
snakeParts[value].attr("x", currentCoord[0] - 10);
} else if (direction[direction.length - 1] === "right") {
snakeParts[value].attr("x", currentCoord[0] + 10);
}
}
That code may need a bit of work but that's the idea. Hope it helps!

Stopping a function, Arrays, and Integer Check

So I made code for creating 5 ships in a battleship game. I succesfully made some code that layed out all the players ships. It had no bugs. I had the player write out the cords for where he wanted to position his ship. It would then write in the ship position to the corresponding part in a two dimensional array which was the game map.. Of course the cords had to be integers or it would crash and burn.
So I then made something to check if the coordinate was a integer before doing anything else. If it wasn't it would restart the function making so that the rest of the function wouldn't run. If you write in the numbers correctly there are no problems. The problem is that if you don't write in a number the function does restart but the function or some part of it must still be running because a ship gets written to the array for no reason. The cords haven't even been specified for it so I have no clue how this can be possible.
Here is the code I made for checking if its an integer and restarting the function.
userYTest = parseInt(prompt("Horizontal Coordinate position for the first unit of a ship"));
userXTest = parseInt(prompt("Vertical Coordinate position for the first unit of a ship"));
if(userXTest % 1 === 0 && userYTest % 1 === 0) {
userY = userYTest-1;
userX = userXTest-1;
direction = prompt("Now choose the direction you want the rest of your ship to face. You may use the words left, right up, or down.").toLowerCase();
}
else{
window.alert("You must enter a number between one and ten for the two coordinates.");
ship();
//ship is the name of the function
}
Here is all the code.
//These are all the different game boards you need to keep track of. Two possible values in each position 1 or 0
var user = [[0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0]];
var cpu = [[0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0]];
var userGuessed = [[0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0]];
var userHit = [[0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0]];
var cpuGuessed = [[0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0]];
var cpuHit = [[0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0]];
var clearBoard = [[0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0]];
// These are just used to set left the game board.
// I counted 10 by 10 - it should be 10 by 10
var userY = 0;
var userX = 0;
var cpuX = 0;
var cpuY = 0;
var cpuDir = 0;
var cpuWork = false;
var direction = "";
var isThere = false;
var i=0;
var userXTest;
var userYTest;
// In battleship, there is 1x5 length ship, 1x4 length ship, 2 1x3 length ship, and 1x2 length ship. down now it checks how many units are covered to see if you have all the ships. Later we need to add so they ships are the down shape
//User will add their ships here one by one. If you can think of a better have a go at it!
for(i=0;i<4;i++){
if (i===0){
window.alert("We will be placing your 1 by 5 length ship. Take note that you are playing on a 10 by 10 board.");
ship();
}
if (i===1){
window.alert("We will be placing your 1 by 4 length ship. Take note that you are playing on a 10 by 10 board.");
ship();
}
if (i===2){
window.alert("We will be placing your two 1 by 3 length ships. Take note that you are playing on a 10 by 10 board.");
ship();
ship();
}
if (i===3){
window.alert("We will be placing your 1 by 2 length ship. Take note that you are playing on a 10 by 10 board.");
ship();
}
function ship(){
userYTest = parseInt(prompt("Horizontal Coordinate position for the first unit of a ship"));
userXTest = parseInt(prompt("Vertical Coordinate position for the first unit of a ship"));
if(userXTest % 1 === 0 && userYTest % 1 === 0) {
userY = userYTest-1;
userX = userXTest-1;
direction = prompt("Now choose the direction you want the rest of your ship to face. You may use the words left, right up, or down.").toLowerCase();
}
else{
window.alert("You must enter a number between one and ten for the two coordinates.");
ship();
}
//Making sure the ship will fit and nothing is already there!
if ((userY+4-i)>9 && direction=== "down"){
window.alert("You are too close to the down edge of the board to do that. Restarting...");
ship();
}
else if ((userY-4-i)<0 && direction=== "up"){
window.alert("You are too close to the up edge of the board to do that. Restarting...");
ship();
}
else if ((userX+4-i)>9 && direction=== "right"){
window.alert("You are too close to the bottom edge of the board to do that. Restarting...");
ship();
}
else if ((userX-4-i)<0 && direction=== "left"){
window.alert("You are too close to the top edge of the board to do that. Restarting...");
ship();
}
else if (user[userY][userX] === 1) {
window.alert("Coordinate already used. Please try again");
ship();
}
else if (user[userY][userX] === null || user[userY][userX] === ""){
window.alert("That coordinate isn't on the board. Restarting...");
ship();
}
else if(direction ==="left" || direction ==="right" || direction ==="up" || direction ==="down") {
for(var a=1; a<5-i; a++){
if(direction=== "down"){
if(user[userY+a][userX] === 1){
window.alert("Can't place your ship in that direction, another ship is in your way.");
isThere=true;
}
}
if(direction=== "up"){
if(user[userY-a][userX] === 1){
window.alert("Can't place your ship in that direction, another ship is in your way.");
isThere=true;
}
}
if(direction=== "right"){
if(user[userY][userX+a] === 1 ){
window.alert("Can't place your ship in that direction, another ship is in your way.");
isThere=true;
}
}
if(direction=== "left"){
if(user[userY][userX-a] === 1){
window.alert("Can't place your ship in that direction, another ship is in your way.");
isThere=true;
}
}
if(isThere===true){
isThere = false;
ship();
return false;
}
else{
user[userY][userX] = 1;
}
}
}
else{
window.alert("Sorry but you didn't type in the direction you wanted your ship to go correctly. Restarting...");
ship();
}
// Building Ship 1x5
for(var b=1; b<5-i; b++){
if (direction==="left"){
user[userY][userX-b] =1;
}
else if (direction==="right"){
user[userY][userX+b] =1;
}
else if (direction==="up"){
user[userY-b][userX] =1;
}
else if (direction==="down"){
user[userY+b][userX] =1;
}
}
}
}
console.log(user);
First, understand that calling a function within itself does not stop running the original function. Try this (jsfiddle) to see how it works:
var i = 0;
function askDogsName() {
var dogsName = prompt("What is the dog's name?");
if (dogsName != "Rover") {
askDogsName();
}
i++;
document.body.innerHTML += "i = " + i
+ "; dog's name: " + dogsName + '<br />';
}
askDogsName();
After the new recursion of the function has completed, the original one simply carries on where it left off; it does not 'restart'. So this is not a good way of responding to user input that is not valid, especially because you are using global variables. Each recursion of the function can alter those variables in a way that can become difficult to predict, before returning control to its 'parent' (the recursion of the function that called it).
What you can do instead is to use return values to check whether the correct input has been given or not:
function ship() {
var c;
while (!c) {
c = getValidCoords();
}
x = c[0];
y = c[1];
// then make the ship at x, y
}
function getValidCoords() {
y = parseInt(prompt("Horizontal Coordinate position for the first unit of a ship"));
x = parseInt(prompt("Vertical Coordinate position for the first unit of a ship"));
// conduct various tests on x and y
if (testsFail) {
return false;
}
return [x, y];
}
You can't recurse when its wrong. Try something like this:
var done;
while (!done) {
if(userXTest % 1 === 0 && userYTest % 1 === 0) {
userY = userYTest-1;
userX = userXTest-1;
direction = prompt("Now choose the direction you want the rest of your ship to face. You may use the words left, right up, or down.").toLowerCase();
... All the other tests that are after the else part ...
else { // if its a good answer
done = true;
}
}
else{
window.alert("You must enter a number between one and ten for the two coordinates.");
}
}
You will want some way they can say they want to quit too.

Use jquery to dynamically number table columns diagonally

Hi there fellow coders,
I'm looking to find a way to fill a pre-built dynamic blank table with numbering (and colouring if possible) like so:
As you can see the numbering is ascending order diagonally. I know there's probably some way to calculate the number based on the tables td index but can't quite figure out how to do that for every column diagonally. Any help would be appreciated.
Update: Ok back from my Holidays. Thanks to all you clever people for your replies. As I'm sure you've all had to experience the pain in the neck clients can be, I've been told the spec has changed(again). This being the case I've had to put the grid/matrix into a database and output using a pivot table. Every square has to be customizable color-wise.
Nothing is going to waste though I have learnt quite a few nifty new javascript/jquery tricks from your responses I didn't know about before, so thanks, and I'll be sure to pay it forward :)
Here's what I came up with in the end.
Given you said "colouring if possible" I'll provide an example solution that doesn't do colours quite the way you want (it does it in a way that I found easier to code and more attractive to look at) but which does handle all the numbering correctly for varying table sizes.
The function below assumes the table already exists; in this demo I've included code that generates a table to whatever size you specify and then calls the function below to do the numbering and colours.
function numberDiagonally(tableId) {
var rows = document.getElementById(tableId).rows,
numRows = rows.length,
numCols = rows[0].cells.length,
sq = numRows + numCols - 1,
d, x, y,
i = 1,
dc,
c = -1,
colors = ["green","yellow","orange","red"];
diagonalLoop:
for (d = 0; d < sq; d++) {
dc = "diagonal" + d;
for (y = d, x = 0; y >= 0; y--, x++) {
if (x === numCols)
continue diagonalLoop;
if (y < numRows)
$(rows[y].cells[x]).html(i++).addClass(dc);
}
}
for (d = 0; d < sq; d++)
$(".diagonal" + d).css("background-color", colors[c=(c+1)%colors.length]);
}
Demo: http://jsfiddle.net/7NZt3/2
The general idea I came up with was to imagine a square twice as big as whichever of the x and y dimensions is bigger and then use a loop to create diagonals from the left edge of that bounding square going up and to the right - i.e., in the order you want the numbers. EDIT: Why twice as big as longer side? Because that's the first thing that came into my head when I started coding it and it worked (note that the variable i that holds the numbers that get displayed is not incremented for the imaginary cells). Now that I've had time to think, I realise that my sq variable can be set precisely to one less than the number of rows plus the columns - a number that ends up rather smaller for non-square tables. Code above and fiddle updated accordingly.
Note that the background colours could be set directly in the first loop, but instead I opted to assign classes and set the loops for each class later. Seemed like a good idea at the time because it meant individual diagonals could be easily selected in jQuery with a single class selector.
Explaining exactly how the rest works is left as an exercise for the reader...
UPDATE - this version does the colouring more like you asked for: http://jsfiddle.net/7NZt3/1/ (in my opinion not as pretty, but each to his own).
This fiddle populates an existing table with numbers and colors. It is not limited to being a 5x5 table. I didn't understand the logic of 15 being orange rather than yellow, so I simply grouped the diagonal cells into color regions.
// we're assuming the table exists
var $table = $('table'),
// cache the rows for quicker access
$rows = $table.find('tr'),
// determine number of rows
_rows = $rows.length,
// determine number of cells per row
_cols = $rows.first().children().length,
// determine total number of cells
max = _rows * _cols,
// current diagonal offset (for coloring)
d = 1,
// current row
r = 0,
// current cell
c = 0;
for (var i=1; i <= max; i++) {
// identify and fill the cell we're targeting
$rows.eq(r).children().eq(c)
.addClass('d' + d)
.text(i);
if (i < max/2) {
// in the first half we make a "line-break" by
// moving one row down and resetting to first cell
if (!r) {
r = c + 1;
c = 0;
d++;
continue;
}
} else {
// in the second half our "line-break" changes to
// moving to the last row and one cell to the right
if (c + 1 == _cols) {
c = 1 + r;
r = _rows -1;
d++;
continue;
}
}
r--;
c++;
}
Here's a jsFiddle that does what you asked for - http://jsfiddle.net/jaspermogg/MzNr8/8/
I took the liberty of making it a little bit user-customisable; it's interesting to see how long it takes the browser to render a 1000x1000 table using this method :-D
Assuming that each cell has an id of [column]x[row], here are teh codez for how to fill in the numbers of a square table of side length sidelength.
//populate the cells with numbers according to the spec
function nums(){
var xpos = 0
var ypos = 0
var cellval = 1
for(i=0;i<2*sidelength;i++){
if(i >= sidelength){
ypos = sidelength - 1
xpos = 1 + i - sidelength
$('td#' + xpos + 'x' + ypos).text(cellval)
cellval = cellval + 1
while(xpos + 1 < sidelength){
ypos = ypos-1
xpos = xpos+1
$('td#' + xpos + 'x' + ypos).text(cellval)
cellval = cellval + 1
}
} else {
ypos = i
xpos = 0
$('td#' + xpos + 'x' + ypos).text(cellval)
cellval = cellval + 1
while(!(ypos-1 < 0)){
ypos = ypos-1
xpos = xpos+1
$('td#' + xpos + 'x' + ypos).text(cellval)
cellval = cellval + 1
}
}
}
}
And here they are for how to colour the bugger.
// color the cells according to the spec
function cols(){
if(+$('td#0x0').text() === 99){
return false
} else {
$('td').each(function(index, element){
if(+$(this).text() > 22)
{
$(this).attr("bgcolor", "red")
}
if(+$(this).text() <= 22)
{
$(this).attr("bgcolor", "orange")
}
if(+$(this).text() <= 14)
{
$(this).attr("bgcolor", "yellow")
}
if(+$(this).text() <= 6)
{
$(this).attr("bgcolor", "green")
}
})
}
}
Enjoy, eh? :-)

Categories