Calculator's history in local storage even on refresh - javascript

I am doing a calculator that stores a history of previous calculations and list it in a table. The list needs to be stored in local storage of the web browser.
Since data is stored on local storage it should not lose context even on page refresh.
I am attaching my Javascript code below:
let currentTotal = 0;
let buffer = "0"; //what's on display
let previousOperator = null;
const calcScreen = document.querySelector(".calc-numbers");
document.querySelector('.calculator-buttons').addEventListener("click",function(event){
//call function buttonClick
buttonClick(event.target.innerHTML);
});
//separates de value of the button clicks into NotANumber and Numbers
function buttonClick(value){
if(isNaN(parseInt(value))){
handleSymbol(value);
}else{
handleNumber(value);
}
rerenderScreen();
}
function handleSymbol(value){
switch (value){
case "C":
buffer = "0";
currentTotal = 0;
previousOperator = null;
break;
case "=":
if(previousOperator === null){ //this would mean that there is nothing to be calculated yet
return;
}
flushOperation(parseInt(buffer));
buffer = "" + currentTotal;
previousOperator = null;
currentTotal = 0;
break;
case "←":
if(buffer.length === 1){ //if the screen is any single number, always turn it to 0 when deleting
buffer = "0";
}
else{
buffer = buffer.substring(0,buffer.length-1); //delete the numbers one by one
}
break;
default:
handleMath(value);
break;
}
}
function handleNumber(value){
if(buffer === "0"){
buffer = value;
}else{
buffer += value;
}
}
function handleMath(value){
const internalBuffer = parseInt(buffer);
if (currentTotal === 0){
currentTotal = internalBuffer;
}else{
flushOperation(internalBuffer);
}
previousOperator = value;
buffer = "0";
}
function flushOperation(internalBuffer){
if(previousOperator === "+"){
currentTotal += internalBuffer;
}else if(previousOperator === "-"){
currentTotal -= internalBuffer;
}else if(previousOperator === "x"){
currentTotal *= internalBuffer;
}else{
currentTotal /= internalBuffer;
}
}
function rerenderScreen(){
calcScreen.value = buffer;
}
I referred this link how to add a localstorage for my Calculator?
I added this code under my previous Javascript code:
let itemsArray = []
localStorage.setItem('items', JSON.stringify(itemsArray))
const data = JSON.parse(localStorage.getItem('items'))
itemsArray.push(input.value)
localStorage.setItem('items', JSON.stringify(itemsArray))
I refreshed my page. But the data is not stored locally. I tried typing localstorage in console but it was empty.
Adding screenshot of the result obtained in console tab
Iam getting this error too at the same time
Uncaught ReferenceError: input is not defined

Related

How can I stop this from writing a value to all dictionaries? (Javascript)

Intro
So I have stumbled across this problem yesterday, and I've been stumped trying to figure this out myself. I only have this problem with JavaScript.
Problem
I've been creating a programming language with JS since the start of this week, and I was enjoying myself the entire week making it. The problem here is that when I carry dictionaries across functions, it has some problems reading and writing into those dictionaries. When I check the console logs, I see that not just the dictionary in the function was written, but all of the instances of that dictionary were written.
Code
Here is the code to graph.js:
function codeToArray(code) {
let codeArray = {commands:[], vars:{x:{value:0, read_only:true},y:{value:0, read_only:false}}};
let commands = code.split("\n");
for (i = 0; i < commands.length; i++) {
let command = commands[i];
let inputs = command.split(" ");
if (inputs[0].toLowerCase() !== ";") {
// Arithmetics
if (inputs[0].toLowerCase() === "+") { // Addition
codeArray.commands.push({name:"add", variable:inputs[1], value:inputs[2], syntax_id:1});
} else if (inputs[0].toLowerCase() === "-") { // Subtraction
codeArray.commands.push({name:"subtract", variable:inputs[1], value:inputs[2], syntax_id:1});
} else if (inputs[0].toLowerCase() === "*") { // Multiplication
codeArray.commands.push({name:"multiply", variable:inputs[1], value:inputs[2], syntax_id:1});
} else if (inputs[0].toLowerCase() === "/") { // Division
codeArray.commands.push({name:"divide", variable:inputs[1], value:inputs[2], syntax_id:1});
}
// I/O
else if (inputs[0].toLowerCase() === ":") { // Set
codeArray.commands.push({name:"set", variable:inputs[1], value:inputs[2], syntax_id:1});
}
// Conditional Statements
else if (inputs[0].toLowerCase() === "if") { // If Statement
let ifCommand = "";
for (j = 4; j < inputs.length; j++) {
if (j > 4) {
ifCommand += " " + inputs[j];
} else {
ifCommand += inputs[j];
}
}
let ifCommandArray = codeToArray(ifCommand).commands[0];
codeArray.commands.push({name:"if", value1:inputs[1], condition:inputs[2], value2:inputs[3], command:ifCommandArray, syntax_id:2});
}
}
}
return codeArray
}
function parseValue(value, variables) {
let return_value = value;
console.log(value);
console.log(variables);
if (value.charAt(0) === "$") {
let variable_name = return_value.substring(1, value.length);
console.log(variable_name);
let variable = variables[variable_name];
console.log(variable);
if (variable === undefined) {
return_value = NaN;
} else {
return_value = variable.value;
}
} else {
return_value = parseFloat(value);
}
console.log(return_value);
return return_value
}
function runCodeArray(commands, variables) {
for (i = 0; i < commands.length; i++) {
let command = commands[i];
if (command.syntax_id === 1) { // Simple Syntax (Variable Value Syntax)
if (command.name === "add") { // Addition
let variable = variables[command.variable];
if (variable === undefined) {
let error_message = `Variable cannot be found (line ${i+1} ignoring comments)`;
return {commands:commands, variables:variables, return_message:error_message};
}
if (variable.read_only === true) {
let error_message = `A read-only variable was trying to be written (line ${i+1} ignoring comments)`;
return {commands:commands, variables:variables, return_message:error_message};
}
let value = parseValue(command.value, variables);
if (value === NaN) {
let error_message = `The value parameter is invalid (line ${i+1} ignoring comments)`;
return {commands:commands, variables:variables, return_message:error_message};
}
variable.value += value;
} else if (command.name === "set") { // Set
let variable = variables[command.variable];
if (variable === undefined) {
variables[command.variable] = {value:0, read_only:false};
variable = variables[command.variable];
}
if (variable.read_only === true) {
let error_message = `A read-only variable was trying to be written (line ${i+1} ignoring comments)`;
return {commands:commands, variables:variables, return_message:error_message};
}
let value = parseValue(command.value, variables);
if (value === NaN) {
let error_message = `The value parameter is invalid (line ${i+1} ignoring comments)`;
return {commands:commands, variables:variables, return_message:error_message};
}
variable.value = value;
}
}
}
return {commands:commands, variables:variables, return_message:true};
}
var url_string = ...graph.html?pattern=%3A+a+42%0D%0A%3A+b+%24a%0D%0A%3A+c+%24b%0D%0A // window.location.href;
var url = new URL(url_string);
var pattern = url.searchParams.get("pattern");
let codeArray = codeToArray(pattern);
// console.log(codeArray);
let codeArrayOut = runCodeArray(codeArray.commands, codeArray.vars); // Will return true in return_message if everything is good, and will return a string in return_message if an error occurs.
// console.log(codeArrayOut);
if (codeArrayOut.return_message !== true) {
alert("Error: " + codeArrayOut.return_message);
}
Sorry if the code is too long, boring or messy for you to read. Here is the function that's causing the most problems:
function parseValue(value, variables) {
let return_value = value;
console.log(value);
console.log(variables);
if (value.charAt(0) === "$") {
let variable_name = return_value.substring(1, value.length);
console.log(variable_name);
let variable = variables[variable_name];
console.log(variable);
if (variable === undefined) {
return_value = NaN;
} else {
return_value = variable.value;
}
} else {
return_value = parseFloat(value);
}
console.log(return_value);
return return_value
}
Outro
I'm still learning in JavaScript, so I hope that you can solve this problem (because I can't).

Create a MR and MC in a javascript calculator

Idealy, I would like my little project to have the memory functions M-, M+, MR and MC.
I was thinking of separate functions and variables to hold the M- and M+.
Is this a normal approach or there is a better one ?
Any idea what might be wrong with my script ? if there is something wrong ?
the number-display ID is the actual calculator screen
the code is :
$(document).ready(function(){
var display = "";
var operators = ["/", "*", "-", "+"];
var decimalAdded = false;
$("button").click(function() {
var key = $(this).text();
//update screen by adding display string to screen with maximum 19 numbers viewable
function updateDisplay() {
if (display.length > 19) {
$("#number-display").html(display.substr(display.length - 19, display.length));
} else {
$("#number-display").html(display.substr(0, 19));
}
}
//clear all entries by resetting display and variables
if (key === "AC" || key === "ON" || key === "MC") {
decimalAdded = false;
display = "";
$("#number-display").html("0");
}
else if (key === "OFF") {
decimalAdded = false;
display = "";
$("#number-display").html("");
}
//clear previous character and reset decimal bool if last character is decimal
else if (key === "CE") {
if (display.substr(display.length - 1, display.length) === ".") {
decimalAdded = false;
}
display = display.substr(0, display.length - 1);
updateDisplay();
}
//add key to display if key is a number
else if (!isNaN(key)) {
display += key;
updateDisplay();
}
//check that . is the first in the number before adding and add 0. or just .
else if (key === ".") {
if (!decimalAdded) {
if(display > 0){
display += key;
}
else {
display += "0" + key;
}
decimalAdded = true;
updateDisplay();
}
}
//if key is basic operator, check that the last input was a number before inputting
else if (operators.indexOf(key) > -1) {
decimalAdded = false;
//first input is a number
if (display.length > 0 && !isNaN(display.substr(display.length - 1, display.length))) {
display += key;
updateDisplay();
}
// allow minus sign as first input
else if (display.length === 0 && key === "-") {
display += key;
updateDisplay();
}
}
// calculate square root of number
else if ( $(this).id === "sqrt") {
var tempStore = display.html();
$("#number-display").html(eval(Math.sqrt(tempStore)));
decimalAdded = false;
}
// change sign of number
else if ($(this).id === "plusmn") {
var newNum = display * -1;
$("#number-display").html(newNum);
}
// create memory plus and minus and calculate MR
else if (key === "M-") {
}
else if (key === "M+") {
}
// percentage function
else if (key === "%"){
}
else if (key == "=") {
//if last input is a decimal or operator, remove from display
if (isNaN(display.substr(display.length - 1, display.length))) {
display = display.substr(0, display.length - 1);
}
var calc = display;
calc = eval(calc);
display = String(calc);
if (display.indexOf('.')) {
decimalAdded = true;
} else {
decimalAdded = false;
}
$("#number-display").html(display);
}
});});
One alternative is a switch statement, which would look something like:
switch (key) {
case "M-":
// do stuff
break;
case "M+":
// do stuff
break;
case "%":
// do stuff
break;
case "=":
// do stuff
break;
}
More documentation on MDN: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/switch

Optimization for Binary Search Tree 'remove' function

I just finished my first binary search tree remove function and it is in major need of optimization. I have spent a lot of time on this and this was the best I could manage. Is there a easier way to do this? Does anyone have any suggestions for optimization? To me, it just seems like it will necessarily be massive code.
For starters...
My Binary Search Tree...
function BST() {
this.root = null;
}
My 'remove' function...
BST.prototype.remove = function(data) {
if(this.root.data === data){
var curr = this.root.left;
while(true){
if(curr.right.left === null && curr.right.right === null){
this.root.data = curr.right.data;
curr.right = null;
break;
}
curr = curr.right;
}
}
var curr = this.root;
var found_data = this.find(data);
if(found_data.left !== null && found_data.right !== null){
var runner = found_data.right;
var runner_prev = found_data;
while(true){
if(runner.left === null && runner.right === null){
found_data.data = runner.data;
if(runner_prev.left === runner){
runner_prev.left = null;
}else{
runner_prev.right = null;
}
break;
}
runner_prev = runner;
runner = runner.left;
}
}else if(found_data.left === null || found_data.right === null){
var prev = this.prev(found_data.data);
if(prev.right === found_data){
if(found_data.left){
prev.right = found_data.left;
}else{
prev.right = found_data.right;
}
}else{
if(found_data.left){
prev.left = found_data.left;
}else{
prev.left = found_data.right;
}
}
}else{
var prev = this.prev(found_data.data);
if(prev.left === found_data){
prev.left = null;
}else{
prev.right = null;
}
}
};
You will notice that I use supporting functions within my remove() function, such as prev() and find() They are apart of my overarching BST() function and can be used anywhere within is by prefacing it using this..
Supporting functions I use within remove() (prev() and find())
BST.prototype.find = function(data) {
if(this.root === null){
return 'wrong';
}
var curr = this.root;
while(true){
if(data > curr.data){
curr = curr.right;
}else if(data < curr.data){
curr = curr.left;
}else{
if(curr.data enter code here=== data){
return curr;
}else{
return 'not here player'
}
}
}
}
BST.prototype.prev = function(data){
if(this.root === null){
return false;
}
var prev = this.root;
var curr = this.root;
while(true){
if(curr.left === null && curr.right === null){
return prev;
}
if(data < curr.data){
prev = curr;
curr = curr.left;
}else if(data > curr.data){
prev = curr;
curr = curr.right;
}else{
return prev;
}
}
}
This algorithm absolutely works, but as you can imagine, this is not the type of monster you would want to be answering a whiteboard interview question with.
It would be more efficient if you either:
Combine prev() and find() by returning both the previous node and the found node from find()
Give each node a parent pointer, and just follow it to find prev

JS Basics: How to use if/else inside a function and set to variable

I'm a JavaScript total beginner and I've gotten stuck on something that seems like it should work while trying to set a variable with a an if/else condition inside and anonymous function. Here is my code:
function changeValue(){
var newValue = (function(){
var getRadioValue = $( "input:radio[name=Radio1]:checked" ).val();
if (getRadioValue === 5){
var final = 8;
}
else if (getRadioValue === 4){
var final = 5;
}
else if (getRadioValue === 3){
var final = 3;
}
else if (getRadioValue === 2){
var final = 1;
}
else if (getRadioValue === 1){
var final = -1;
}
else
{
var final = 0;
}
return final;
})();
alert(newValue);
}
Right now, the alert is showing 0 because none of the "ifs" are returning true, but if I set the getRadioValue variable hard coded like:
var getRadioValue = 5;
then the if/else conditional works and the alert message shows 8. That makes it seem like the .val() method isn't working. However, if I simply set the alert to:
alert(getRadioValue);
The alert message does in fact display the correctly selected radio value from the radio button set on my page. So I know that is working... Now I can't figure out where I'm going wrong. It seems like since the radio value is getting assigned to getRadioValue correctly, and the conditional is working, the whole thing should work. I'm sure it's such a basic problem, but after much research I still can't seem to get it. Any help is greatly appreciated!
.val() is returning a string but you are testing for number if (getRadioValue === 5){.
You might want to do getRadioValue = parseInt(getRadioValue) first.
Demo:
getRadioValue = parseInt("5")
var final = 0; // use var once, its cleaner ;)
if (getRadioValue === 5) {
final = 8;
} else if (getRadioValue === 4) {
final = 5;
} else if (getRadioValue === 3) {
final = 3;
} else if (getRadioValue === 2) {
final = 1;
} else if (getRadioValue === 1) {
final = -1;
}
alert(final);
Thanks to CodeiSir! That was the issue. Here is my final working code for others who might run into a similar problem:
function changeValue(){
var newValue = (function(){
var getRadioValue = $( "input:radio[name=CalcItem1]:checked" ).val();
var RadioValue = parseInt(getRadioValue);
if (RadioValue === 5){
var final = 8;
}
else if (RadioValue === 4){
var final = 5;
}
else if (RadioValue === 3){
var final = 3;
}
else if (RadioValue === 2){
var final = 1;
}
else if (RadioValue === 1){
var final = -1;
}
else
{
var final = 0;
}
return final;
})();
alert(newValue);
}

Snake Game in Javascript

I'm really new to Javascript, so I decided to create a simple SnakeGame to embed in HTML. However, my code for changing the snake's direction freezes up after a few turns.
Note: I'm running this in an HTML Canvas.
Source:
var Canvas;
var ctx;
var fps = 60;
var x = 0;
var seconds = 0;
var lastLoop;
var thisLoop;
var tempFPS = 0;
var blockList = [];
var DEFAULT_DIRECTION = "Right";
var pendingDirections = [];
function update() {
x += 1;
thisLoop = new Date();
tempFPS = 1000 / (thisLoop - lastLoop);
lastLoop = thisLoop;
tempFPS = Math.round(tempFPS*10)/10;
if (x==10){
document.getElementById("FPS").innerHTML = ("FPS: " + tempFPS);
}
//Rendering
for (var i = 0; i<blockList.length; i++){
var block = blockList[i];
draw(block.x, block.y);
}
if (x==5){
x=0;
seconds+=1;
//Updates once per x frames
moveBlocks();
}
}
function moveBlocks(){
if(blockList.length === 0){
return;
}
for (var j = 0; j<pendingDirections.length; j++){
if (b >= blockList.length -1){
pendingDirections.shift();
}else {
//Iterates through each direction that is pending
var b = pendingDirections[j].block;
try{
blockList[b].direction = pendingDirections[j].direction;
} catch(err){
alert(err);
}
pendingDirections[j].block++;
}
}
for (var i = 0; i<blockList.length; i++){
var block = blockList[i];
clear(block.x, block.y);
if (block.direction == "Down"){
block.y += BLOCK_SIZE;
} else if (block.direction == "Up"){
block.y -= BLOCK_SIZE;
} else if (block.direction == "Left"){
block.x -= BLOCK_SIZE;
} else if (block.direction == "Right"){
block.x += BLOCK_SIZE;
} else {
alert(block.direction);
}
draw(block.x, block.y);
}
}
function init(){
lastLoop = new Date();
window.setInterval(update, 1000/fps);
Canvas = document.getElementById("Canvas");
ctx = Canvas.getContext("2d");
}
//The width/height of each block
var BLOCK_SIZE = 30;
//Draws a block
function draw(x, y) {
ctx.fillStyle = "#000000";
ctx.fillRect(x,y,BLOCK_SIZE,BLOCK_SIZE);
}
function clear(x,y){
ctx.fillStyle = "#FFFFFF";
ctx.fillRect(x,y,BLOCK_SIZE,BLOCK_SIZE);
}
function processInput(key){
if (key == 110){
//n (new)
newBlock(BLOCK_SIZE*4,0);
newBlock(BLOCK_SIZE*3,0);
newBlock(BLOCK_SIZE*2,0);
newBlock(BLOCK_SIZE*1,0);
newBlock(0,0);
} else if (key == 119){
changeDirection("Up");
} else if (key == 115){
changeDirection("Down");
} else if (key == 97){
changeDirection("Left");
} else if (key == 100){
changeDirection("Right");
} else if (key==122){
var pDir = "Pending Directions: ";
for (var i = 0; i<pendingDirections.length; i++){
pDir += pendingDirections[i].direction + ", ";
}
alert(pDir);
} else if (key == 120){
var dir = "Directions: ";
for (var j = 0; j<blockList.length; j++){
dir += blockList[j].direction + ", ";
}
alert(dir);
} else {
alert("KEY: " +key);
}
}
function changeDirection(d){
var LD = blockList[0].direction;
var valid = false;
if (d == "Up"){
if(LD != "Down"){
valid = true;
}
} else if (d == "Down"){
if(LD != "Up"){
valid = true;
}
} else if (d == "Left"){
if(LD != "Right"){
valid = true;
}
} else if (d == "Right"){
if(LD != "Left"){
valid = true;
}
}
if (d == LD) { valid = false;}
if (valid){
var dir = {'direction' : d, 'block' : 0};
pendingDirections.unshift(dir);
}
}
function newBlock(x, y){
var block = {'x': x, 'y' : y, 'direction' : DEFAULT_DIRECTION};
//This works: alert(block['x']);
draw(x,y);
blockList.push(block);
}
Thanks
As Evan said, the main issue is how you are handling pending directions.
The issue occurs when you turn twice in rapid succession, which causes two pending directions to be added for the same block. If these aren't handled in the correct order, then the blocks may move in the wrong direction. On every update, only one pending direction for each block is needed, so I redesigned how this is handled to avoid multiple directions on one block during a single update.
Here is the link to it: http://jsbin.com/EkOSOre/5/edit
Notice, when a change in direction is made, the pending direction on the first block is updated, overwriting any existing pending direction.
if (valid) {
blockList[0].pendingDirection = direction;
}
Then, when an update occurs, the list of blocks is looped through, and the pending direction of the next block is set to be the current direction of the current block.
if(!!nextBlock) {
nextBlock.pendingDirection = block.direction;
}
If the current block has a pending direction, set the direction to the pending direction.
if(block.pendingDirection !== null) {
block.direction = block.pendingDirection;
}
Then update the block locations like normal.
You also had various other issues, such as using a variable (b) before it was initialized, and how you caught the null/undefined error (you should just do a check for that situation and handle it appropriately), but this was the main issue with your algorithm.
You'll also want to remove the old blocks when the user hits 'n', because the old one is left, increasing the speed and number of total blocks present.
Good luck with the rest of the game, and good luck learning JavaScript.

Categories

Resources