Is there anyway to make this code faster? - javascript

I have a code here that automatically tick a box when all three boxes are true, however this is taking forever to load as I have thousands of boxes in the sheet, is there any way to make this code quicker?
at the moment the code is making everything lag and unresponsive
function checkBox(j,k,l,m,result){
var result = true;
if ( j === true && k === true & l === true && m === true) {
result = true;
} else {
result = false;
}
return result;
}
if the first four boxes are tick, then box number 6 will automatically tick, but it's taking forever to load

Not sure what you are doing wrong, but this code took 46ms for 10,000 lines - a little longer to render on the screen.
function go(){
//set up a test table with every 10th row with all boxes ticked
let str="<table>";
for (let i=0;i<10000;i++){
str +="<tr>";
for (let j=0;j<4;j++){
str +="<td><input type='checkbox'></td>";
}
str +="<td> </td><td><input type='checkbox'</td>";
str +="</tr>";
}
str +="</table>";
container.innerHTML=str;
//start here to compute the result column
let start=(new Date()).getTime();
let table=container.querySelector("table");
let rows=table.querySelectorAll("tr");
for (let i=0;i<rows.length;i++){
let inputs=rows[i].querySelectorAll("input");
if(i%10==0){
for (let j=0;j<4;j++)inputs[j].checked=true;
}
else {
for (let j = 0; j < 4; j++) {
if (Math.random() < 0.5) inputs[j].checked = true;
}
}
inputs[4].checked=inputs[0].checked && inputs[1].checked && inputs[2].checked && inputs[3].checked;
}
alert((new Date()).getTime()-start);
}

Related

there are 'X' participants. The participants are to be divided into groups. Each group can have a minimum of 6 and a maximum of 10 participants

there are 'X' participants. The participants are to be divided into groups. Each group can have a minimum of 6 and a maximum of 10 participants. How would you approach this problem, and can you write code for this problem? Optimize for a minimum number of groups. Example: If there are 81 participants, then your program should split them into 9 groups, with each group having 9 participants.
If you have an array with 90 participants and want to create new arrays with a max you could do something like this:
let participants = []
for (let i = 0; i < 90; i++) {
participants.push("Participant" + i)
}
function splitArray(array, newArrayMaxLength) {
var chunks = [], i = 0, n = array.length;
while (i < n) {
chunks.push(array.slice(i, i += newArrayMaxLength));
}
return chunks;
}
console.log(splitArray(participants, 9));
When you call this function, you pass with it an argument stating the max length of the new arrays. If the numbers does not add up, there will only be a difference with one, so ideally you would not have to do anything else, if you span is between 6-10.
Please in the future include your code if you have done any :-)
This is a variation of the classical coin change problem with result as sequence instead of minimum coins required. The base solution is recursive and given below.
function minGroup(groupSize, totalParticipants) {
// Base case
if (totalParticipants == 0) return [];
// Initialize result
let groupArray = -1;
// Try every group that is smaller
// than totalParticipants
for (let i = 0; i < groupSize.length; i++) {
if (groupSize[i] <= totalParticipants) {
let sub_arr = minGroup(groupSize, totalParticipants - groupSize[i]);
// enters if new minGroup less than current or no current solution
if (sub_arr !== -1 && (sub_arr.length + 1 < groupArray.length || groupArray === -1)) {
groupArray = sub_arr.concat([groupSize[i]])
}
}
}
return groupArray
}
The solution can be improved on by Dynamic Programming with tabulation.
function minGroupDp(groupSize, totalParticipants) {
let dpTable = new Array(totalParticipants + 1);
// base case
dpTable[0] = [];
// Initialize all dpTable values as -1
for (let i = 1; i <= totalParticipants; i++) {
dpTable[i] = -1;
}
// Compute minimum groupSize required for all
// totalParticipantss from 1 to V
for (let i = 1; i <= totalParticipants; i++) {
// Go through all groupSize smaller than current total participants
for (let j = 0; j < groupSize.length; j++)
if (groupSize[j] <= i) {
let sub_arr = dpTable[i - groupSize[j]];
// enters if new minGroup less than current or no current solution
if (
sub_arr !== -1 &&
(sub_arr.length + 1 < dpTable[i].length || dpTable[i] === -1)
)
dpTable[i] = sub_arr.concat([groupSize[j]]);
}
}
return dpTable[totalParticipants];
}

Happy numbers - recursion

I have an issue with a recursive algorithm, that solves the problem of finding the happy numbers.
Here is the code:
function TestingFunction(number){
sumNumberContainer = new Array(0);
CheckIfNumberIsHappy(number);
}
function CheckIfNumberIsHappy(number){
var sumOfTheNumbers = 0;
for (var i = 0; i < number.length; i++) {
sumOfTheNumbers += Math.pow(parseInt(number[i]), 2);
}
console.log(sumOfTheNumbers);
if(sumOfTheNumbers == 1){
return CheckIfNumberIsHappy(sumOfTheNumbers.toString());
//return true;
} else {
sumNumberContainer.push(sumOfTheNumbers);
if(sumNumberContainer.length > 1){
for (var i = 0; i < sumNumberContainer.length - 1; i++) {
for (var j = i + 1; j < sumNumberContainer.length; j++) {
if(sumNumberContainer[i] == sumNumberContainer[j]){
return CheckIfNumberIsHappy(sumOfTheNumbers.toString());
//return false;
}
}
}
}
CheckIfNumberIsHappy(sumOfTheNumbers.toString());
}
}
Algorithm is working ALMOST fine. I've tested it out by calling function with different numbers, and console was displaying correct results. The problem is that I almost can't get any value from the function. There are only few cases in which I can get any value: If the number is build out of ,,0", and ,,1", for example 1000.
Because of that, I figured out, that I have problem with returning any value when the function is calling itself again.
Now I ended up with 2 results:
Returning the
return CheckIfNumberIsHappy(sumOfTheNumbers.toString());
which is giving an infinity looped number. For example when the number is happy, the function is printing in the console number one again and again...
Returning the
//return true
or
//return false
which gives me an undefined value
I'm a little bit in check by this problem, and I'm begging you guys for help.
I would take a step back and reexamine your problem with recursion in mind. The first thing you should think about with recursion is your edge cases — when can you just return a value without recursing. For happy numbers, that's the easy case where the sum of squares === 1 and the harder case where there's a cycle. So test for those and return appropriately. Only after that do you need to recurse. It can then be pretty simple:
function sumSq(num) {
/* simple helper for sums of squares */
return num.toString().split('').reduce((a, c) => c * c + a, 0)
}
function isHappy(n, seen = []) {
/* seen array keeps track of previous values so we can detect cycle */
let ss = sumSq(n)
// two edge cases -- just return
if (ss === 1) return true
if (seen.includes(ss)) return false
// not an edge case, save the value to seen, and recurse.
seen.push(ss)
return isHappy(ss, seen)
}
console.log(isHappy(23))
console.log(isHappy(22))
console.log(isHappy(7839))
Here's a simplified approach to the problem
const digits = x =>
x < 10
? [ x ]
: [ ...digits (x / 10 >> 0), x % 10 ]
const sumSquares = xs =>
xs.reduce ((acc, x) => acc + x * x, 0)
const isHappy = (x, seen = new Set) =>
x === 1
? true
: seen.has (x)
? false
: isHappy ( sumSquares (digits (x))
, seen.add (x)
)
for (let n = 1; n < 100; n = n + 1)
if (isHappy (n))
console.log ("happy", n)
// happy 1
// happy 7
// happy 10
// ...
// happy 97
The program above could be improved by using a technique called memoization
Your code is almost correct. You just forgot to return the result of the recursive call:
function TestingFunction(number){
sumNumberContainer = new Array(0);
if (CheckIfNumberIsHappy(number))
console.log(number);
}
function CheckIfNumberIsHappy(number){
var sumOfTheNumbers = 0;
for (var i = 0; i < number.length; i++) {
sumOfTheNumbers += Math.pow(parseInt(number[i]), 2);
}
if(sumOfTheNumbers == 1){
return true;
} else {
sumNumberContainer.push(sumOfTheNumbers);
if(sumNumberContainer.length > 1){
for (var i = 0; i < sumNumberContainer.length - 1; i++) {
for (var j = i + 1; j < sumNumberContainer.length; j++) {
if(sumNumberContainer[i] == sumNumberContainer[j]){
return false;
}
}
}
}
return CheckIfNumberIsHappy(sumOfTheNumbers.toString());
}
}
for (let i=0; i<100; ++i)
TestingFunction(i.toString()); // 1 7 10 13 ... 91 94 97
I've got the solution, which was given to me in the comments, by the user: Mark_M.
I just had to use my previous
return true / return false
also I had to return the recursive statement in the function, and return the value of the CheckIfTheNumberIsHappy function, which was called in TestingFunction.
The working code:
function TestingFunction(number){
sumNumberContainer = new Array(0);
return CheckIfNumberIsHappy(number);
}
function CheckIfNumberIsHappy(number){
var sumOfTheNumbers = 0;
for (var i = 0; i < number.length; i++) {
sumOfTheNumbers += Math.pow(parseInt(number[i]), 2);
}
console.log(sumOfTheNumbers);
if(sumOfTheNumbers == 1){
return true;
} else {
sumNumberContainer.push(sumOfTheNumbers);
if(sumNumberContainer.length > 1){
for (var i = 0; i < sumNumberContainer.length - 1; i++) {
for (var j = i + 1; j < sumNumberContainer.length; j++) {
if(sumNumberContainer[i] == sumNumberContainer[j]){
return false;
}
}
}
}
return CheckIfNumberIsHappy(sumOfTheNumbers.toString());
}
}
Thanks for the great support :)

Creating a complicated algebra function

Doing an assignment for my JavaScript class that requires me to create a function that adds every other index starting with the first and subtracting all the indexes not previously added and produces the sum. I believe the function below should work but it seems to return undefined.
function questionSix(){
let result = 0;
for(let i = 0; i < arguments.length; i++){
if(i == 0){
result += arguments[i];
}else{
if(i % 2 != 0){
result += arguments[i];
}
if(i % 2 == 0){
result -= arguments[i];
}
}
}
}
Because you aren't returning anything (there is no return statement in your code) :
function questionSix(){
let result = 0;
for(let i = 0; i < arguments.length; i++) {
if(i == 0){
result += arguments[i];
}else{
if(i % 2 != 0){
result += arguments[i];
}
if(i % 2 == 0){
result -= arguments[i];
}
}
}
return result;
}
console.log(questionSix(1,6,5,7,8,9,9,8,4,5));
However, it looks like your code isn't doing exactly what it should, here's a solution to your problem :
function questionSix(){
let result = 0; // the sum
let array = []; // the numbers added
for(let i = 0; i < arguments.length; i++) {
// was the number added ?
if(array.indexOf(i) > -1){ // Yes
result += arguments[i]; // add it to the sum
}else{ // No
result -= arguments[i]; // subtract it from the sum
array.push(arguments[i]); // add it to the array
}
}
return result; // return the sum
}
console.log(questionSix(1,6,5,7,8,9,9,8,4,5));
You haven't included a "return" statement
The clue to this (apart from there being no return statement!) is that you start with a result=0 statement, and yet you are receiving undefined.
You don't have to do a special case for i==0
When i==0, i % 2 will equal 0, so the "inner" if-then-else will do the job adequately, without the if (i==0) segment.
Swap the += and -=
However I wonder whether you have reversed the += and -= ? You want to add the 0th and all even-indexed values, don't you? And subtract the odd ones?

"Maximum call stack size exceeded" error

So I'm trying to make a Tic Tac Toe game following this tutorial. When I run it and look at the Chrome dev tools, it says Uncaught RangeError: Maximum call stack size exceeded, and point me to the line of this function:
var State = function(oldState) {
this.turn = "";
this.oMovesCount = 0;
this.result = "still running";
this.board = [];
//get the information from the previous state to use it for following states
if (typeof oldState !== "undefined") {
var len = oldState.board.length;
this.board = new Array(len);
for (var i = 0; i < len; i++) {
this.board[i] = oldState.board[i];
}
this.oMovesCount = oldState.oMovesCount;
this.result = oldState.result;
this.turn = oldState.turn;
}
//change to X or O accordingly
this.advanceTurn = function() {
//Was it just X's turn? If so, change to O. If not, change to X.
this.turn = this.turn === "x" ? "o" : "x";
};
//checks for victory
this.result = "still running";
this.isTerminal = function() {
var B = this.board;
//check to see if there has been a victory
//check rows
for(var i = 0; i <= 6; i = i + 3) {
if(B[i] !== "E" && B[i] === B[i+1] && B[i+1] == B[i+2]) {
this.result = B[i] + " has won!";
return true;
}
}
//check columns
for(var i = 0; i <= 2 ; i++) {
if(B[i] !== "E" && B[i] === B[i+3] && B[i+3] === B[i+6]) {
this.result = B[i] + " has won!";
return true;
}
}
//check diagonals
for(var i = 0, j = 4; i <= 2 ; i = i + 2, j = j - 2) {
if(B[i] !== "E" && B[i] == B[i+j] && B[i+j] === B[i + 2*j]) {
this.result = B[i] + " has won!";
return true;
}
};
//if there have been no wins, check the number of empty cells
//if there are no empty cells, it's a draw
var available = this.emptyCells();
if (available.length == 0) {
this.result = "draw";
return true;
}
else {
return false;
}
};
//keeps track of how many empty cells there are on the board
this.emptyCells = function() {
var indxs = [];
for (var i = 0; i < 9; i++) {
if (this.board[i] === "E") {
indxs.push(i);
}
}
return indxs;
}
};
I don't understand why. Here's the full code, the error shows up when you click Play then OK then on one of the cells. Here it is hosted on another site if it helps.
Thank you!
There is a typo in the AIAction method:
this.oMovesPosition = pos; //the position on the board where the O would be placed
this.minimaxVal = 0; //the minimax value of the state that the action leads to
this.applyTo = function(state) {
var next = new State(state);
//if the current turn in the current state is O, increment .oMovesCount
next.board[this.movePosition] = state.turn;
if (state.turn === "o") {
next.oMovesCount++;
}
next.advanceTurn();
return next;
};
Notice the this.oMovesPosition in the first line, but then the applyTo method refers to this.movePosition instead.
Too recursion, in fiddle line 395 you call the function minimax in recursion.
var nextScore = miniMax(nextState);
You must stop recursion before run out of memory, or convert the recursion into a loop.
In AIaction = function(pos) you have two spellings for what should be the same movePosition property:
this.oMovesPosition = pos;
and:
next.board[this.movePosition] = state.turn;
Because they are different properties, the second line will always be equivalent to this:
next.board[undefined] = state.turn;
... and so the board never actually changes. As a consequence a board is never considered terminal, and your recursion never stops.

Battleship game: Allowing hits to be registered on ships with lengths other than 4

I'm making Battleship in JavaScript for a school project and I'm stuck.
The computer randomly generates boats and the user has to try to sink all the computer's boats by entering in coordinates. The hits on a boat are saved in an array. The array contains zeros to signify the boat's length (so boat with length 4 has an array with 4 zeros). When a boat is hit, the 0 changes to 1. If all the elements are 1, the boat sinks. Problem is my code registers the hits, but only puts it in an array when you hit the boat with length 4.
Can anyone help me? Below is the code of the "game" itself:
function game() {
inputArray = [4, 3, 2];
var boats = randomBoats(inputArray);
var currentBoat = 0;
var sunkenBoat = 0;
var numberOfTurns = 0;
while (sunkenBoat !== inputArray.length) {
var hit = false;
var target = "(" + prompt("Enter targetcoordinate (x,y)") + ")";
var targetString = target.replace(/\s+/g, '');
for (var i = 0; i !== inputArray.length; i++) {
for (var j = 0; j !== boats[i].usedPositions().length; j++) {
console.log(targetString)
if (targetString === boats[i].usedPositions()[j].toString()) {
raak = true;
boats[i].hits[j] = 1;
console.log(boats[i].hits);
currentBoat = boats[i];
} else {
currentBoat = boats[i];
}
}
}
console.log(currentBoat.hits);
console.log(allEquals(currentBoat.hits, 1));
if (hit)
alert("Hit!");
else
alert("Miss!");
if (allEquals(currentBoat.hits, 1)) {
alert("Boat with length " + currentBoat.hits.length + " has sunken!");
sunkenBoat++;
}
numberOfTurns++
}
alert("You've won! You did it in " + numberOfTurns + " turns.")
}
The issue is with the else in the inner loop, as you processed each ship (outer loop) and all positions (inner loop) your
else {
currentBoat = boats[i];
}
would always set the current boat to be the last [i];
You also don't need to process any other positions or boats when you've found a hit, so break early when you detect the hit like this:
raak = false;
for(var i = 0; i < inputArray.length && !raak; i++) {
for(var j = 0; j !== boats[i].usedPositions().length; j++) {
console.log(targetString)
if(targetString === boats[i].usedPositions()[j].toString()) {
raak = true;
boats[i].hits[j] = 1;
console.log(boats[i].hits);
currentBoat = boats[i];
break;
}
}
}

Categories

Resources