Tree exercise with a loop in javascript - javascript

I want to create a tree with *. I will give a number every time in order to specify the tree's height.
It should look something like this if I give number 4 as height for example:
*
***
*****
*******
I would like the tree to appear using console.log
I have done that:
var size = 4;
document.write(
"<center>" + Array.apply(0, new Array(size)).map(function(_, i) {
return new Array((i + 1) * 2).join(" * ");
}).join("<br>") + "</center>"
);
but it doesn't work if I use console.log

You just need to count the spaces on the left per floor.
The deepest one starts at j=0. The floor above at j=1. And so forth.
Given a height h,
floor h-1->j=0
floor h-2->j=1
floor 0->j=h-1
Notice that if you start at floor 0, you get j=h-1, and remove a space at every subsequent floor.
You can thus trivially write
const h = 4;
console.log(Array(h).fill(0).map((_,i)=>{
return ' '.repeat(h-1-i)+'*'.repeat(i*2+1)
}).join('\n'))

I created one like this.
function drawTree(height) {
for ( let i = 0; i < height ; i++ ) {
let star = '*';
let space = ' ';
for ( let j = 1; j <= i; j++ ) {
star = star + '**';
}
let gap = space.repeat(height-i-1);
star = gap + star;
console.log(star);
}
}
let number = prompt('Give number for tree height');
drawTree(number);

To clearify my comment. You won't be able to show html in the console. So you need to forget about tags. As when you are printing the tree you should know how big (height) it's going to be. So you know how many spaces will preceed your star.
Number of spaces are given by the height in total - the current "level" from top to bottom - 1
and the number of stars is given by 2 times of the current "level" plus 1
let spaces = " ".repeat(height-i-1);
let stars = "*".repeat(i*2+1);
So just use a loop to go through all the levels of the tree from top to bottom and concatinating the spaces and stars
Here's an example on how that works (example also prints out to a textarea for preview purposes as well as in the console)
https://codepen.io/relief_melone/pen/zYYRZmj

Related

How would I fix my approach to this Manhattan Skyline/Stone Wall and where did I go wrong? Javascript

I just came across this problem and thought I would give it a try, but now I'm stuck and need help if possible.
The problem I keep facing is my return is usually off by 1 or 2 but I can't figure out why not. I have traced my code back but still can't figure it out
The problem :
You are to write a program to assist an architect in drawing the skyline of a city. Building are rectangular in shape, the height of each building is represented by an element in a given array.
The above skyline above is represented like
[1,3,2,1,2,1,5,3,3,4,2]
SO FAR HERE IS WHAT I AM WORKING WITH:
const skyline =(H)=> {
let stack = [];
let count = 0;
let height = 0;
const addBlock = (value) => {
if (value > height) {
stack.push(value - height);
height = value;
count += 1;
}
}
const pop = (value) => {
while (value < height) {
height -= stack.pop();
}
if (value > height) {
addBlock(value)
}
}
for (let i = 0; i < H.length; i += 1) {
let value = H[i];
if (value < height) {
pop(value)
} else if (value > height) {
addBlock(value)
}
}
return count
}
skyline([1,3,2,1,2,1,5,3,3,4,2]) //Expect 9
// Test CASES:
let strokes = [1,3,2,1,2,1,5,3,3,4,2] // Expect 9
// let strokes = [5,8] // Expect 8
// let strokes = [1,1,1,1] // Expect 1
skyline(strokes)
Is this the basic algorithm?
* Big eats small (and equal-sized)
* Small reduces big to small
adding the difference
* Count last one standing
Examples:
[5,8]
-> 8 eats 5, count 8
[1,1,1,1]
-> 1 eats 1 eats 1 eats 1
-> count 1
[1,3,2,1,2,1,5,3,3,4,2]
-> 3 eats 1
-> 2 reduces 3 to 2 and adds 3-2
-> 1 reduces 2 to 1 and adds 2-1
-> 2 eats 1
-> 1 reduces 2 to 1 and adds 2-1
-> 5 eats 1
-> 3 reduces 5 to 3 and adds 5-3
-> 3 eats 3
-> 4 eats 3
-> 2 reduces 4 to 2 and adds 4-2
-> count 2
Total: 1 + 1 + 1 + 2 + 2 + 2 = 9
JavaScript code:
function f(A){
let result = 0;
for (let i=1; i<A.length; i++)
result += Math.max(0, A[i-1] - A[i]);
return result + A[A.length-1];
}
console.log(f([1,3,2,1,2,1,5,3,3,4,2]));
console.log(f([5,8]));
console.log(f([1,1,1,1]));
One liner :)
function f(A){
return [0].concat(A).reduce((a,b,i,A) => a + Math.max(0, A[i-1] - b)) + A[A.length-1];
}
the current answer seems to solve the problem presented, additionally I would like to point that a way to tackle this kind of problems is to solve it by hand and take notes on which steps you took to solve it.
In this case, they ask you to draw horizontal lines without picking up the pencil and one way to do that by hand is to do all the posible strokes on the same row before passing on to the next, until there are no rows left to check.
On every row, you will surely check if the current spot (array element) is greater than 0, which means that it is part of the stroke.
Now in more concise words:
While there are rowsLeft I will traverse the array. on every
traversal I will:
check if the current position is greater than 0 which means there is a
newStroke, it also means there are rowsLeft and since you want to keep
moving forward you would like to decrease the current element by one.
then, if there is a newStroke and the current element is 0 (end of the
stroke) or if it is the end of the array, I would add 1 to my numOfStrokes
count and also state that since I have just finished the stroke then there is
no newStroke at the moment.
Well that's what I did to solve the case you posted, I believe you can code it from there and I hope it helps you, then again, bruce's answer seems to be right, I just wanted to add how you could came up with the solution, there are surely many ways f doing it.
function minimalNumberOfSkylinesIn(array) {
if(array.length == 0)
return 0;
let result = array[0];
for(let i=1; i<array.length; ++i) {
let differnce = array[i] - array[i-1];
result += difference > 0 ? difference : 0;
}
return result;
}

How can I split a string into a given number of lines?

Here is my question:
Given a string, which is made up of space separated words, how can I split that into N strings of (roughly) even length, only breaking on spaces?
Here is what I've gathered from research:
I started by researching word-wrapping algorithms, because it seems to me that this is basically a word-wrapping problem. However, the majority of what I've found so far (and there is A LOT out there about word wrapping) assumes that the width of the line is a known input, and the number of lines is an output. I want the opposite.
I have found a (very) few questions, such as this that seem to be helpful. However, they are all focused on the problem as one of optimization - e.g. how can I split a sentence into a given number of lines, while minimizing the raggedness of the lines, or the wasted whitespace, or whatever, and do it in linear (or NlogN, or whatever) time. These questions seem mostly to be unanswered, as the optimization part of the problem is relatively "hard".
However, I don't care that much about optimization. As long as the lines are (in most cases) roughly even, I'm fine if the solution doesn't work in every single edge case, or can't be proven to be the least time complexity. I just need a real world solution that can take a string, and a number of lines (greater than 2), and give me back an array of strings that will usually look pretty even.
Here is what I've come up with:
I think I have a workable method for the case when N=3. I start by putting the first word on the first line, the last word on the last line, and then iteratively putting another word on the first and last lines, until my total width (measured by the length of the longest line) stops getting shorter. This usually works, but it gets tripped up if your longest words are in the middle of the line, and it doesn't seem very generalizable to more than 3 lines.
var getLongestHeaderLine = function(headerText) {
//Utility function definitions
var getLongest = function(arrayOfArrays) {
return arrayOfArrays.reduce(function(a, b) {
return a.length > b.length ? a : b;
});
};
var sumOfLengths = function(arrayOfArrays) {
return arrayOfArrays.reduce(function(a, b) {
return a + b.length + 1;
}, 0);
};
var getLongestLine = function(lines) {
return lines.reduce(function(a, b) {
return sumOfLengths(a) > sumOfLengths(b) ? a : b;
});
};
var getHeaderLength = function(lines) {
return sumOfLengths(getLongestLine(lines));
}
//first, deal with the degenerate cases
if (!headerText)
return headerText;
headerText = headerText.trim();
var headerWords = headerText.split(" ");
if (headerWords.length === 1)
return headerText;
if (headerWords.length === 2)
return getLongest(headerWords);
//If we have more than 2 words in the header,
//we need to split them into 3 lines
var firstLine = headerWords.splice(0, 1);
var lastLine = headerWords.splice(-1, 1);
var lines = [firstLine, headerWords, lastLine];
//The header length is the length of the longest
//line in the header. We will keep iterating
//until the header length stops getting shorter.
var headerLength = getHeaderLength(lines);
var lastHeaderLength = headerLength;
while (true) {
//Take the first word from the middle line,
//and add it to the first line
firstLine.push(headerWords.shift());
headerLength = getHeaderLength(lines);
if (headerLength > lastHeaderLength || headerWords.length === 0) {
//If we stopped getting shorter, undo
headerWords.unshift(firstLine.pop());
break;
}
//Take the last word from the middle line,
//and add it to the last line
lastHeaderLength = headerLength;
lastLine.unshift(headerWords.pop());
headerLength = getHeaderLength(lines);
if (headerLength > lastHeaderLength || headerWords.length === 0) {
//If we stopped getting shorter, undo
headerWords.push(lastLine.shift());
break;
}
lastHeaderLength = headerLength;
}
return getLongestLine(lines).join(" ");
};
debugger;
var header = "an apple a day keeps the doctor away";
var longestHeaderLine = getLongestHeaderLine(header);
debugger;
EDIT: I tagged javascript, because ultimately I would like a solution I can implement in that language. It's not super critical to the problem though, and I would take any solution that works.
EDIT#2: While performance is not what I'm most concerned about here, I do need to be able to perform whatever solution I come up with ~100-200 times, on strings that can be up to ~250 characters long. This would be done during a page load, so it needs to not take forever. For example, I've found that trying to offload this problem to the rendering engine by putting each string into a DIV and playing with the dimensions doesn't work, since it (seems to be) incredibly expensive to measure rendered elements.
Try this. For any reasonable N, it should do the job:
function format(srcString, lines) {
var target = "";
var arr = srcString.split(" ");
var c = 0;
var MAX = Math.ceil(srcString.length / lines);
for (var i = 0, len = arr.length; i < len; i++) {
var cur = arr[i];
if(c + cur.length > MAX) {
target += '\n' + cur;
c = cur.length;
}
else {
if(target.length > 0)
target += " ";
target += cur;
c += cur.length;
}
}
return target;
}
alert(format("this is a very very very very " +
"long and convoluted way of creating " +
"a very very very long string",7));
You may want to give this solution a try, using canvas. It will need optimization and is only a quick shot, but I think canvas might be a good idea as you can calculate real widths. You can also adjust the font to the really used one, and so on. Important to note: This won't be the most performant way of doing things. It will create a lot of canvases.
DEMO
var t = `However, I don't care that much about optimization. As long as the lines are (in most cases) roughly even, I'm fine if the solution doesn't work in every single edge case, or can't be proven to be the least time complexity. I just need a real world solution that can take a string, and a number of lines (greater than 2), and give me back an array of strings that will usually look pretty even.`;
function getTextTotalWidth(text) {
var canvas = document.createElement("canvas");
var ctx = canvas.getContext("2d");
ctx.font = "12px Arial";
ctx.fillText(text,0,12);
return ctx.measureText(text).width;
}
function getLineWidth(lines, totalWidth) {
return totalWidth / lines ;
}
function getAverageLetterSize(text) {
var t = text.replace(/\s/g, "").split("");
var sum = t.map(function(d) {
return getTextTotalWidth(d);
}).reduce(function(a, b) { return a + b; });
return sum / t.length;
}
function getLines(text, numberOfLines) {
var lineWidth = getLineWidth(numberOfLines, getTextTotalWidth(text));
var letterWidth = getAverageLetterSize(text);
var t = text.split("");
return createLines(t, letterWidth, lineWidth);
}
function createLines(t, letterWidth, lineWidth) {
var i = 0;
var res = t.map(function(d) {
if (i < lineWidth || d != " ") {
i+=letterWidth;
return d;
}
i = 0;
return "<br />";
})
return res.join("");
}
var div = document.createElement("div");
div.innerHTML = getLines(t, 7);
document.body.appendChild(div);
I'm sorry this is C#. I had created my project already when you updated your post with the Javascript tag.
Since you said all you care about is roughly the same line length... I came up with this. Sorry for the simplistic approach.
private void DoIt() {
List<string> listofwords = txtbx_Input.Text.Split(' ').ToList();
int totalcharcount = 0;
int neededLineCount = int.Parse(txtbx_LineCount.Text);
foreach (string word in listofwords)
{
totalcharcount = totalcharcount + word.Count(char.IsLetter);
}
int averagecharcountneededperline = totalcharcount / neededLineCount;
List<string> output = new List<string>();
int positionsneeded = 0;
while (output.Count < neededLineCount)
{
string tempstr = string.Empty;
while (positionsneeded < listofwords.Count)
{
tempstr += " " + listofwords[positionsneeded];
if ((positionsneeded != listofwords.Count - 1) && (tempstr.Count(char.IsLetter) + listofwords[positionsneeded + 1].Count(char.IsLetter) > averagecharcountneededperline))//if (this is not the last word) and (we are going to bust the average)
{
if (output.Count + 1 == neededLineCount)//if we are writting the last line
{
//who cares about exceeding.
}
else
{
//we're going to exceed the allowed average, gotta force this loop to stop
positionsneeded++;//dont forget!
break;
}
}
positionsneeded++;//increment the needed position by one
}
output.Add(tempstr);//store the string in our list of string to output
}
//display the line on the screen
foreach (string lineoftext in output)
{
txtbx_Output.AppendText(lineoftext + Environment.NewLine);
}
}
(Adapted from here, How to partition an array of integers in a way that minimizes the maximum of the sum of each partition?)
If we consider the word lengths as a list of numbers, we can binary search the partition.
Our max length ranges from 0 to sum (word-length list) + (num words - 1), meaning the spaces. mid = (range / 2). We check if mid can be achieved by partitioning into N sets in O(m) time: traverse the list, adding (word_length + 1) to the current part while the current sum is less than or equal to mid. When the sum passes mid, start a new part. If the result includes N or less parts, mid is achievable.
If mid can be achieved, try a lower range; otherwise, a higher range. The time complexity is O(m log num_chars). (You'll also have to consider how deleting a space per part, meaning where the line break would go, features into the calculation.)
JavaScript code (adapted from http://articles.leetcode.com/the-painters-partition-problem-part-ii):
function getK(arr,maxLength) {
var total = 0,
k = 1;
for (var i=0; i<arr.length; i++) {
total += arr[i] + 1;
if (total > maxLength) {
total = arr[i];
k++;
}
}
return k;
}
function partition(arr,n) {
var lo = Math.max(...arr),
hi = arr.reduce((a,b) => a + b);
while (lo < hi) {
var mid = lo + ((hi - lo) >> 1);
var k = getK(arr,mid);
if (k <= n){
hi = mid;
} else{
lo = mid + 1;
}
}
return lo;
}
var s = "this is a very very very very "
+ "long and convoluted way of creating "
+ "a very very very long string",
n = 7;
var words = s.split(/\s+/),
maxLength = partition(words.map(x => x.length),7);
console.log('max sentence length: ' + maxLength);
console.log(words.length + ' words');
console.log(n + ' lines')
console.log('')
var i = 0;
for (var j=0; j<n; j++){
var str = '';
while (true){
if (!words[i] || str.length + words[i].length > maxLength){
break
}
str += words[i++] + ' ';
}
console.log(str);
}
Using the Java String Split() Method to split a string we will discover How and Where to Apply This String Manipulation Technique:
We'll examine the Java Split() method's explanation and discover how to apply it. The principles are explained simply and with enough programming examples, either as a separate explanation or in the comment part of the programs.
The Java String Split() method is used to divide or split the calling Java String into pieces and return the Array, as the name implies. The delimiters("", " ", ) or regular expressions that we have supplied separately for each component or item of an array.
Syntax
String[ ] split(String regExp)
First Case: It involves initializing a Java String variable with a variety of words separated by spaces, using the Java String Split() method, and evaluating the results. We can effectively print each word without the space using the Java Split() function.
Second Case: In this case, we initialize a Java String variable and attempt to split or deconstruct the main String variable to use the String Split() method utilizing a substring of the initialized String variable.
Third Case: In this case, we will attempt to split a String using its character by taking a String variable (a single word).
You can check out other approaches to this problem on YouTube and even coding websites on google such as Coding Ninjas
This old question was revived by a recent answer, and I think I have a simpler technique than the answers so far:
const evenSplit = (text = '', lines = 1) => {
if (lines < 2) {return [text]}
const baseIndex = Math .round (text .length / lines)
const before = text .slice (0, baseIndex) .lastIndexOf (' ')
const after = text .slice (baseIndex) .indexOf (' ') + baseIndex
const index = after - baseIndex < baseIndex - before ? after : before
return [
text .slice (0, index),
... evenSplit (text .slice (index + (before > -1 ? 1 : 0)), lines - 1)
]
}
const text = `However, I don't care that much about optimization. As long as the lines are (in most cases) roughly even, I'm fine if the solution doesn't work in every single edge case, or can't be proven to be the least time complexity. I just need a real world solution that can take a string, and a number of lines (greater than 2), and give me back an array of strings that will usually look pretty even.`
const display = (lines) => console .log (lines .join ('\n'))
display (evenSplit (text, 7))
display (evenSplit (text, 5))
display (evenSplit (text, 12))
display (evenSplit (`this should be three lines, but it has a loooooooooooooooooooooooooooooooong word`, 3))
.as-console-wrapper {max-height: 100% !important; top: 0}
It works by finding the first line then recurring on the remaining text with one fewer lines. The recursion bottoms out when we have a single line. To calculate the first line, we take an initial target index which is just an equal share of the string based on its length and the number of lines. We then check to find the closest space to that index, and split the string there.
It does no optimization, and could certainly be occasionally misled by long words, but mostly it just seems to work.

Finding the nth item in a repeating list of fixed items

I have to determine the mathematical formula to calculate a particular repeating position in a series of numbers. The list of numbers repeats ad infinitum and I need to find the number every n numbers in this list. So I want to find the *n*th item in a list of repeating y numbers.
For example, if my list has 7 digits (y=7) and I need every 5th item (n=5), how do I find that item?
The list would be like this (which I've grouped in fives for ease of viewing):
12345 67123 45671 23456 71234 56712 34567
I need to find in the first grouping number 5, then in the second grouping number 3, then 1 from the third group, then 6, then 4, then 2, then 7.
This needs to work for any number for y and n. I usually use a modulus for finding *n*th items, but only when the list keeps increasing in number and not resetting.
I'm trying to do this in Javascript or JQuery as it's a browser based problem, but I'm not very mathematical so I'm struggling to solve it.
Thanks!
Edit: I'm looking for a mathematical solution to this ideally but I'll explain a little more about the problem, but it may just add confusion. I have a list of items in a carousel arrangement. In my example there are 7 unique items (it could be any number), but the list in real terms is actually five times that size (nothing to do with the groups of 5 above) with four sets of duplicates that I create.
To give the illusion of scrolling to infinity, the list position is reset on the 'last' page (there are two pages in this example as items 1-7 span across the 5 item wide viewport). Those groups above represent pages as there are 5 items per page in my example. The duplicates provide the padding necessary to fill in any blank spaces that may occur when moving to the next page of items (page 2 for instance starts with 6 and 7 but then would be empty if it weren't for the duplicated 1,2 and 3). When the page goes past the last page (so if we try to go to page 3) then I reposition them further back in the list to page one, but offset so it looks like they are still going forwards forever.
This is why I can't use an array index and why it would be useful to have a mathematical solution. I realise there are carousels out there that do similar tasks to what I'm trying to achieve, but I have to use the one I've got!
Just loop every 5 characters, like so:
var data = "12345671234567123456712345671234567";
var results = [];
for(var i = 4; i < data.length; i += 5){
results.push(data[i]);
}
//results = [5, 3, 1, 6, 4, 2, 7]
If you want to use a variable x = 5; then your for loop would look like this:
for(var i = x - 1; i < data.length; i += x){...
There is no need to know y
If your input sequence doesn't terminate, then outputting every nth item will eventually produce its own repeating sequence. The period (length) of this repetition will be the lowest common multiple of the period of the input sequence (y) and the step size used for outputting its items (x).
If you want to output only the first repetition, then something like this should do the trick (untested):
var sequence = "1234567";
var x = 5;
var y = sequence.length;
var count = lcm(x, y);
var offset = 4;
var output = [];
for (var i = 0; i < count; i += x)
{
j = (offset + i) % y;
output.push(sequence[j]);
}
You should be able to find an algorithm for computing the LCM of two integers fairly easily.
A purely mathematical definition? Err..
T(n) = T(n-1) + K For all n > 0.
T(1) = K // If user wants the first element in the series, you return the Kth element.
T(0) = 0 // If the user want's a non-existent element, they get 0.
Where K denotes the interval.
n denotes the desired term.
T() denotes the function that generates the list.
Lets assume we want every Kth element.
T(1) = T(0) + K = K
T(2) = T(1) + K = 2K
T(3) = T(2) + K = 3K
T(n) = nk. // This looks like a promising equation. Let's prove it:
So n is any n > 1. The next step in the equation is n+1, so we need to prove that
T(n + 1) = k(n + 1).
So let's have a go.
T(n+1) = T(N+1-1) + K.
T(n+1) = T(n) + K
Assume that T(n) = nk.
T(n+1) = nk + k
T(n+1) = k(n + 1).
And there is your proof, by induction, that T(n) = nk.
That is about as mathematical as you're gonna get on SO.
Nice simple recurrence relation that describes it quite well there.
After your edit I make another solution;)
var n = 5, y = 7;
for (var i = 1; i<=y; i++) {
var offset = ( i*y - (i-1)*n ) % y;
var result = 0;
if (offset === n) {
result = y;
} else {
result = (n - offset) > 0 ? n - offset : offset;
}
console.log(result);
}
[5, 3, 1, 6, 4, 2, 7] in output.
JSFIDDLE: http://jsfiddle.net/mcrLQ/4/
function get(x, A, B) {
var r = (x * A) % B;
return r ? r : B;
}
var A = 5;
var B = 7;
var C = [];
for (var x = 1; x <= B; ++x) {
C.push(get(x, A, B));
}
console.log(C);
Result: [5, 3, 1, 6, 4, 2, 7]
http://jsfiddle.net/xRFTD/
var data = "12345 67123 45671 23456 71234 56712 34567";
var x = 5;
var y = 7;
var results = [];
var i = x - 1; // enumeration in string starts from zero
while ( i <= data.length){
results.push(data[i]);
i = i + x + 1;// +1 for spaces ignoring
}

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? :-)

javascript random color with 7digits must

I found the following awesome script to create a random color with javascript.
var randColor = '#'+(Math.random()*0xFFFFFF<<0).toString(16);
only problem I have with this script is that it's not garanteed that it returns a normal 7digit hex string.
sometimes it's just 6 digits long like #e1d19.
is there a way to kind of force a 7 digit hex value?
thank you for your help.
edit: this is my actual problem:
function randColor() {
var randColor = '#'+(Math.random()*0xFFFFFF<<0).toString(16);
return randColor;
}
for (var i=0; i<100; i++) {
$("#colorpicker").append("<div class='color' title="+randColor()+" style='background:"+randColor()+"'></div>");
}
I'm creating little divs with a random color, when I click on them I grab their title attribute and I'm coloring the background of my body.
however currently my code ends in
<div style="background:rgb(176, 249, 252);" title="#8bc47d" class="color"></div>
so when I grab the title attribute the color I'm giving my body is a different one than the little div shows.
You could just pad it yourself:
function randomColor() {
var rc = (~~(Math.random() * 0xFFFFFF)).toString(16);
return '#' + new Array(7 - rc.length).join('0') + rc;
}
This trick:
new Array(n).join(char)
is a way to get n - 1 copies of "char" in a string. I subtracted the raw length of the value from 7 instead of 6 so that when the string is 5 characters long I get one zero, when 4 I get two, etc.
edit — of course (as mentioned in other answers) you can get pad zeros like this too:
return '#' + "000000".slice(rc.length) + rc;
I'd have to do one of those silly jsperf things to see which is faster :-)
var randColor = '#'+(0xFFFFFFFF-Math.random()*0xFFFFFFFF).toString(16).substr(0, 6);
Here's my (low tech) attempt:
var randColor = (Math.random()*0xFFFFFF<<0).toString(16);
while( randColor.length < 6 ) {
randColor = '0' + randColor;
}
randColor = '#' + randColor;
I think your best bet is to make 3 sets of 2-digit hex numbers (one for each R, G, and B). Then, simply pad-left each with a 0 to ensure they are all two digits. Maybe something like this untested code I am providing for reference :)
//I am GUESSING that this is how you get a 2-digit hex value ranging 0-255
var r = PadDigits(Math.random()*0xFF<<0).toString(16),2);
var g = PadDigits(Math.random()*0xFF<<0).toString(16),2);
var b = PadDigits(Math.random()*0xFF<<0).toString(16),2);
var randColor = '#'+r+g+b;
function PadDigits(n, totalDigits)
{
n = n.toString();
var pd = '';
if (totalDigits > n.length)
{
for (i=0; i < (totalDigits-n.length); i++)
{
pd += '0';
}
}
return pd + n.toString();
}
You want it to be six digits, not seven, but the resulting string should be seven characters long including the hash. Nitpicking, I know, but still. How about this:
var color = (Math.random() * 0xFFFFFF << 0).toString(16);
"#" + String(color + "000000").slice(0, 6);
If you want to pad in the beginning instead, this should do it:
var color = (Math.random() * 0xFFFFFF << 0).toString(16);
"#" + String("000000" + color).slice(-6);
To clarify, this will pad the whole string, not separate channels. I'm thinking that since you're not randomizing per channel, there's really only the red or blue channel you're looking to pad (probably red, i.e., the second snippet).
Your second problem is that you're calling randColor twice, giving you two different colors. You'll want to store the generated color in a variable and use the variable twice instead.
for (var i=0; i<100; i++) {
var color = randColor();
$("#colorpicker").append("<div class='color' title=" + color + " style='background:" + color + "'></div>");
}
Nobody posted it and this is the shortest code i got to get a random color.
'#'+Math.random().toString(16).slice(-6)
It will get a random float number 0.437920...
Convert it to Hexadecimal, you'll get something like that 0.7c13b41830e33
Take the 6 last character which will provide you a random color #
Easy to understand, short and efficient.

Categories