Need A Lot of Assistance From An Actual js Dev

That’s awesome! It doesn’t have to be perfect, it is a learning exercise and getting it to work is the main thing. After that you can look for ways to improve but really in the early stages getting it to work is the biggest part.

The issues you are having with the prompt loop…

First the do … while construct will run the prompt at least once in every case and keep running it while the condition says so. This means you don’t need to prompt again outside the loop. This is better:

But it still won’t work as you expect it to because the problem is with the condition (size == NaN) for 2 reasons. The first reason is that size is never ever going to be NaN, NaN is a special value used to signal an error when doing math on something that is not a number type and cannot be converted into a number type or when it is an illegal math operation that cannot result in a number. Importantly NaN is a value, so you when you try compare values which are not numbers to the value NaN the result will be false because even though they are not numbers they are also not NaN. Secondly in a spectacularly confusing way, the value NaN is not equal to the value NaN so even if the value is NaN then NaN == NaN is false, so is NaN === NaN.

There are a few ways of doing what you are trying to do here, I’m going to focus on the one that is closest to the way you are trying to do it though it may introduce one or two functions you have not seen before (since I haven’t read the book, I’m not sure if these have appeared yet), so I’m not sure if it was what the author had in mind for this exercise or not. With that caveat out the way, the two functions we are going to use here are parseInt and isNan.

  • parseInt takes as its input a string (which is what we get from prompt) that may or may not contain a string representation of an integer number and tries to convert it to a number type, if it can then it returns the number it read from the string, if it cannot it returns our friend NaN. You can use it like this size = parseInt(someUserInput).
  • isNaN is a function that takes any value which may or may not be NaN and returns true if it is NaN and returns false for any other value (basically what you expect NaN == NaN to do in the first place).

Putting these together, this version should do what you are trying to do:

let size;
do {
    let input = prompt("Please enter a number.");
    size = parseInt(input);
} while (isNaN(size));

For the overall problem I had a slightly different solution. I’ve added it below to give you a chance to see another way to do it and see if you can work through how it comes together (I’ve added plenty comments to help), importantly I’ve not put it here to suggest it is a better solution or that your solution is in some way less right. There are a couple of things about how I have written my solution that I would like to highlight, these aren’t things super important for a beginner but they are super important overall and it is never too early to begin thinking about them when it comes to refactoring/tidying up your code just don’t get too hung up on them if they are getting in your way at this stage. So here is the solution I have:

// we have already discussed reading the input a fair bit so not much to add here
let size; 
do {
    let input = prompt('Please enter a number.');
    size = parseInt(input);
} while (isNaN(size));

// the symbols used for each type of cell never change so they are made constant here 
const blackCell = '#';
const whiteCell = ' ';

// the variable that we will gradually build up the grid into, it spans multiple iterations of the loop so needs to be outside
let grid = '';
for (let rowNum = 0; rowNum < size; rowNum++) { // loop size times to build up the right number of rows
    // by default make the even cells white and the odd cells black
    let evenCell = whiteCell;
    let oddCell = blackCell;

    if (rowNum % 2 == 0) { // every second row, switch the cell colors
        evenCell = blackCell;
        oddCell = whiteCell;
    }

    // the variable that we will build this row into
    let row = '';
    for (let colNum = 0; colNum < size; colNum++) { // loop size times to build the row width
        if (colNum % 2 == 0) { 
            row += evenCell; // add an even cell if the current colNum is divisable by 2
        } else {
            row += oddCell; // otherwise add an odd cell
        }
    }

    grid += row; // add the row to the grid
    grid += '\n'; // add a new line to the grid before starting the next row
    // evenCell, oddCell and row go out of scope here, there is no need to reset them they will be recreated
    // the next time through the loop.
}

console.log(grid);

The first thing to notice is that I’ve used const keyword for storing values that never change. One of the hardest things when reading or debugging code is keeping track of all the things which can change and where they are changing over time, every time you can reduce this overhead you make it much easier to work with code you have written. Using const clearly indicates that this value does not change over time and the reader doesn’t need to worry about that when they are keeping track of things.

Second thing, you sort of know this already but don’t seem completely comfortable yet… for loops are the more idiomatic way of writing loops that are based on an index counter. It is important to build your confidence with them soon, you don’t have to panic and stop all progress just keep in mind to spend a little time every few days to get more used to working with them.

Last thing, variables and scopes (this is a little more advanced in some respects). You will notice that when I create variables, I created them as close as possible to where I need to use them. This goes back to the keeping track of things changing over time point, the earlier you introduce them the more someone reading it has to keep track of. Variables created using let and const keywords are block scoped (in javascript blocks are groupings that start with a { and end with a }, they may be nested inside each other and the outer scope is visible in a nested block but a nested scope is not visible in the outer block), meaning they exist only up to the end of the block in which they are defined. Ideally you want variables defined in the smallest scope possible and as late in that scope as possible before you need to use it, this dramatically minimises the number of things to keep track of and allows the reader to know when they can forget about them. If you haven’t read much about scopes yet, don’t over think it just keep the general point in mind, if you have a good grasp of scopes then it would be a good exercise to see if you can improve your solution by reducing the “lifetime” your variables exist for. As a super advanced extra that you might see happen but really don’t have to worry about right now at all … You will see some javascript programs that create variables using the var keyword like this var size = 10;, these will (and should) use the style you have used of creating them at the start of the scope they belong to. var is a much older way to create variables, it has different scope rules and the interpreter does something called “hoisting” which means that if you define them in the middle of the scope it will move the definition to the start of the scope before running so in this case you should define them at the start to avoid confusion with how the interpreter will treat them. You won’t need to use var just now, if you are reading other peoples code though then you may see this happen and wonder why it is following a different style from what I am suggesting here.

2 Likes