Codewars JavaScript fundamental problem help (Arrays) - javascript

I've been trying to resolve the following problem:
You live in the city of Cartesia where all roads are laid out in a perfect grid. You arrived ten minutes too early to an appointment, so you decided to take the opportunity to go for a short walk. The city provides its citizens with a Walk Generating App on their phones -- everytime you press the button it sends you an array of one-letter strings representing directions to walk (eg. ['n', 's', 'w', 'e']). You always walk only a single block for each letter (direction) and you know it takes you one minute to traverse one city block, so create a function that will return true if the walk the app gives you will take you exactly ten minutes (you don't want to be early or late!) and will, of course, return you to your starting point. Return false otherwise.
Note: you will always receive a valid array containing a random assortment of direction letters ('n', 's', 'e', or 'w' only). It will never give you an empty array (that's not a walk, that's standing still!).
Here is the code I wrote:
function walkTime(walk) {
//insert brilliant code here
var walkLength = walk.length;
if (walkLength === 10) {
return true;
}
else {
return false;
}
}
findEndPosition = (Arr) => {
var y = 0
if (Arr.length > 10) {
return false
}
else {
Arr.forEach((x) => {
if (x === 'n') {
y++;
}
if (x === 's') {
y--;
}
if (x === 'e') {
y++;
}
if (x === 'w') {
y--;
}
})
};
if (y === 0) {
return true;
}
else {
return false;
}
}
const isValidWalk = (walk) => {
if(walkTime(walk) === true && findEndPosition(walk) === true){
return true
}
else {
return false
}
}
console.log(isValidWalk(['w','e','w','e','w','e','w','e','w','e','w','e']));
I keep trying to passing all the tests except for two. Unfortunately it's not telling me what inputs it's using that keep failing :/. Anyone think they know what's going on, this is driving me crazy! Thanks in advance!

If your goal is only to check if the walk will take exactly 10 minutes, it should be enough to test that the walk array is 10 in length and the walk steps are valid. Isn't it so?
In your code, you have a function for solving the end position. There is a clear mistake as steps to west and east are changing the y variable. Is your actual problem more related to this one?

Just wanted to let you guys know I found this solution. It worked through all the tests! I'm sure it could be written a lot better, if you guys got suggestions I'd appreciate it! Anyways here it is!
function walkTime(walk) {
//insert brilliant code here
var walkLength = walk.length;
if (walkLength === 10) {
return true;
}
else {
return false;
}
}
const findEndPosition = (Arr) => {
var y = 0;
var x = 0;
if (Arr.length > 10) {
return false
}
else {
Arr.forEach((movement) => {
if (movement === 'n') {
y++;
}
if (movement === 's') {
y--;
}
if (movement === 'e') {
x++;
}
if (movement === 'w') {
x--;
}
})
};
const newLocation = [x,y];
if (newLocation.toString() === '0,0') {
return true;
}
else {
return false;
}
}
const isValidWalk = (walk) => {
if(walkTime(walk) === true && findEndPosition(walk) === true){
return true
}
else {
return false
}
}
console.log(isValidWalk(['n','s','e','w','n','s','e','w','e','w']));

Related

check the alphabetical order

I am a newbie who is trying hard to have a grip on javascript. please help me to consolidate my fundamentals.
input will be a string of letters.
following are the requirements.
function should return true if following conditions satisfy:
letters are in alphabetical order. (case insensitive)
only one letter is passed as input. example :
isAlphabet ('abc') === true
isAlphabet ('aBc') === true
isAlphabet ('a') === true
isAlphabet ('mnoprqst') === false
isAlphabet ('') === false
isAlphabet ('tt') === false
function isAlphabet(letters) {
const string = letters.toLowerCase();
for (let i = 0; i < string.length; i++) {
const diff = string.charCodeAt(i + 1) - string.charCodeAt(i);
if (diff === 1) {
continue;
} else if (string === '') {
return false;
} else if (string.length === 1) {
return true;
} else {
return false;
}
}
return true;
}
It's generally a better practice to start your function off with dealing with the edge-cases rather than putting them somewhere in the middle. That way, the function returns as soon as it can - and it's a lot easier to read than a waterfall of if..else statements.
function isAlphabet(letters) {
if ("" == letters) {
return false;
}
if (1 == letters.length) {
return true;
}
const string = letters.toLowerCase();
// carry on with your loop here.
}
You've got the right idea, but it can be simplified to just fail on a particular error condition, i.e when a smaller character follows a larger one:
function isAlphabet(letters) {
const string = letters.toLowerCase();
let lastChar;
for (let i = 0; i < string.length; i++) {
// Grab a character
let thisChar = string.charCodeAt(i);
// Check for the failure case, when a lower character follows a higher one
if (i && (thisChar < lastChar)) {
return false;
}
// Store this character to check the next one
lastChar = thisChar;
}
// If it got this far then input is valid
return true;
}
console.log(isAlphabet("abc"));
console.log(isAlphabet("aBc"));
console.log(isAlphabet("acb"));
You can use the simple way to achieve the same as below
function isAlphabet(inputString)
{
var sortedString = inputString.toLowerCase().split("").sort().join("");
return sortedString == inputString.toLowerCase();
}
console.log("abc = " + isAlphabet("abc"));
console.log("aBc = " + isAlphabet("aBc"));
console.log("acb = " + isAlphabet("acb"));
console.log("mnoprqst = " + isAlphabet("mnoprqst"));
Note: Mark the answer is resolves your problem.

Codingame : A child's play

I have a problem with a puzzle named "A child's play" of Codingame. I code in typescript !
The statement is :
For several years now, in elementary schools, we have seen the emergence of a new educational model, playful programming. The students must program a small robot using assembly blocks. This allows them to get familiar with programming from an early age while exercising their logic and perception of space.
You are a student at one such school. The purpose of the exercise is simple: your teacher has crafted a circuit for your robot, told you how many moves n the robot may make, and you must find out the final position of the robot at end of execution.
To do this you need to know some principles of robot operation.
– When the robot encounters an obstacle (represented by #) it turns right (on same operation) until there's no obstacle ahead anymore. Otherwise on an empty area (represented by .) it moves straight ahead.
– The robot initially moves upwards.
– The robot stops after n moves.
– The top left corner represents the coordinates (0,0)
– The robot's environment is represented as follows, where O is the robot's initial position:
...#........
...........#
............
............
..#O........
..........#.
I'm block at the test 4, because my solution is not optimized.
It gives me in the console: The process timed out. This may mean that your solution is not optimized enough to handle some cases.
I tried to change the loop for a "while" loop and change and change the "switch" condition, for an "if-else" condition.
Can you help me to find a better solution or a other way to do the tests?
var inputs: string[] = readline().split(' ');
const w: number = parseInt(inputs[0]);
const h: number = parseInt(inputs[1]);
const n: number = parseInt(readline());
let zone: string[][] = [];
let robot: robot = { x: 0, y: 0 };
interface robot {
x: number,
y: number
}
for (let i = 0; i < h; i++) {
const line: string = readline();
zone = [...zone, line.split('')]
}
zone.forEach((line, y) => {
line.forEach((place, x) => {
if (place === "O") {
robot.x = x;
robot.y = y;
}
})
})
function getLoc(robot: robot, zone: string[][], tours: number) {
let direct: string = "T";
var i = 0;
while (i < tours) {
if (direct === "T") {
if (zone[robot.y - 1][robot.x] === '#') {
robot.x++;
direct = "R";
} else {
robot.y--;
}
} else if (direct === "R") {
if (zone[robot.y][robot.x + 1] === '#') {
robot.y++;
direct = "B";
} else {
robot.x++;
}
} else if (direct === "B") {
if (zone[robot.y + 1][robot.x] === '#') {
robot.x--;
direct = "L";
} else {
robot.y++;
}
} else if (direct === "L") {
if (zone[robot.y][robot.x - 1] === '#') {
robot.y--;
direct = "T";
} else {
robot.x--;
}
}
i++;
}
return robot
}
console.time("getLoc")
let res: robot = getLoc(robot, zone, n);
console.timeEnd("getLoc")
console.log(`${res.x} ${res.y}`)
The robot will go into a loop.
You have to figure out how long the loop is, then how many times it goes through it, then complete the last partial loop.
I recommend keeping an object saying when it was last at a given position and orientation. When you find that it repeats, you now know the length of the loop and can jump over the repetitive behavior.
thanks for your tips, it was helped me for the resolution of the problem ! I did change the structure of main code, I did add three functions, getSteps() to get remaining moves and detect if there is a loop, moveRobot() to move the robot and get all moves. getLoc() to get the final position with the resultat of getSteps(). I reach the 8nth test, but i'm blocked at the 9nth test. The answer is "1 3", but I get "2 4" ! I don't know how to solve this problem without break the rest.
The map is :
#####
#...#
#.#.#
#...#
##O##
The code is :
var inputs: string[] = readline().split(' ');
const w: number = parseInt(inputs[0]);
const h: number = parseInt(inputs[1]);
const n: number = parseInt(readline());
let zone: string[][] = [];
let robot: robot = { x: 0, y: 0 };
let startRobot: startRobot = { x: 0, y: 0, loops: 1, steps: 0 };
interface startRobot extends robot {
loops: number,
steps: number
}
interface robot {
x: number,
y: number
}
for (let i = 0; i < h; i++) {
const line: string = readline();
zone = [...zone, line.split('')]
console.error(line)
}
zone.forEach((line, y) => {
line.forEach((place, x) => {
if (place === "O") {
robot.x = x;
robot.y = y;
startRobot.x = x;
startRobot.y = y;
}
})
})
function getSteps(robot: robot, zone: string[][], steps: number, start: startRobot) {
let direct: string = "T";
var i: number = 0;
var s: number = 0;
let quotient: number = 0;
let newSteps: number = 0;
while (i < steps) {
let resfunction = moveRobot(direct, zone, robot);
robot = resfunction.robot;
direct = resfunction.direct;
i++;
start.steps++;
if (robot.x === start.x && robot.y === start.y) {
s++;
}
if (s === start.loops) {
quotient = steps / start.steps;
newSteps = steps - start.steps * (Math.floor(quotient) - 1);
break;
}
}
return newSteps
}
function moveRobot(direct: string, zone: string[][], robot: robot) {
if (direct === "T") {
if (robot.y - 1 >= zone.length) {
if (zone[robot.y][robot.x] === '#') {
robot.x++;
direct = "R";
} else {
robot.y--;
}
} else {
if (zone[robot.y - 1][robot.x] === '#') {
robot.x++;
direct = "R";
} else {
robot.y--;
}
}
} else if (direct === "R") {
if (robot.x + 1 >= zone[0].length) {
if (zone[robot.y][robot.x] === '#') {
robot.y++;
direct = "B";
} else {
robot.x++;
}
} else {
if (zone[robot.y][robot.x + 1] === '#') {
robot.y++;
direct = "B";
} else {
robot.x++;
}
}
} else if (direct === "B") {
if (robot.y + 1 >= zone.length) {
if (zone[robot.y][robot.x] === '#') {
robot.x--;
direct = "L";
} else {
robot.y++;
}
} else {
if (zone[robot.y + 1][robot.x] === '#') {
robot.x--;
direct = "L";
} else {
robot.y++;
}
}
} else if (direct === "L") {
if (robot.x - 1 >= zone[0].length) {
if (zone[robot.y][robot.x] === '#') {
robot.y--;
direct = "T";
} else {
robot.x--;
}
} else {
if (zone[robot.y][robot.x - 1] === '#') {
robot.y--;
direct = "T";
} else {
robot.x--;
}
}
}
return { direct, robot }
}
function getLoc(robot: robot, zone: string[][], steps: number, start: startRobot) {
let direct: string = "T";
var i: number = 0;
while (i < steps) {
let resfunction = moveRobot(direct, zone, robot);
robot = resfunction.robot;
direct = resfunction.direct;
i++;
}
return robot
}
// console.time("getLoc")
let newSteps: number = getSteps(robot, zone, n, startRobot);
let res: robot = getLoc(robot, zone, newSteps, startRobot);
// console.timeEnd("getLoc")
console.log(`${res.x} ${res.y}`)

for loop in javascript is skipping else if condition half the time

I'm was just fiddling around with javascript and I wrote function using Math.random that I thought would return a coin-flip. Then I was curious so I ran it through a loop to test how often it flips true/false. I found out my loop is skipping about half of the else if conditions, and was able to verify this by catching them in the errors var. So, why is it doing this?
var truths = 0;
var alternativetruths = 0;
var errors = 0;
function game() {
var score = Math.random()*10;
return score>5;
}
for(i=0;i<999999;i++) {
if (game() === true) {
truths++
} else if (game() === false) {
alternativetruths++
} else {
errors++
}
}
console.log("truths:",truths,"alternativetruths:",alternativetruths,"errors:",errors)
truths: 500393 alternativetruths: 249580 errors: 250026
Your code calls game() twice. If the first call isn't true, then the second might or might not be true.
Just call game() once and assign the result to a variable. Don't make explicit comparisons to true and false; if statements work off boolean values, and your function already returns one of those.
for (var i = 0; i < 999999; i++) {
var result = game();
if (result)
truths++;
else
alternativetruths++;
}
Because you're calling game twice, and thus getting two different random flags.
The minimal change is to remember the number:
for(i=0;i<999999;i++) {
var flag = game();
if (flag === true) {
truths++
} else if (flag === false) {
alternativetruths++
} else {
errors++
}
}
But a couple of other notes:
If flag is a boolean (and it is, it's the result of the > operator), then if (flag === true) is pointless. Just use if (flag). The result of the === operator is a boolean too, so if you don't trust them to be true or false, where do you stop? :-) if ((flag === true) === true)?
Separately, if (flag === false) should just be if (!flag).
If flag is a boolean (and it is), then if you have if (flag), having else if (!flag) and then else doesn't make any sense. There is no way you'll reach that final else. Just if (flag) { } else { } is all you need.
But, game isn't fair, it has a very slight bias toward returning false. Remember, the range returned by Math.random() * 10 is 0 to just under 10, so checking for > 5 means you're skipping the midpoint. Because you're dealing with very small fractional numbers, you don't notice the bias, but it's there; it would be more obvious if you rounded to whole numbers, at which point it would be roughly 40%/60% true/false. You want >= 5 for fair results.
game can rather moer succinctly be written: return Math.random() >= 0.5;.
Because you're not declaring i, you're falling prey to The Horror of Implicit Globals (that's a post on my anemic little blog). Remember to declare your variables.
Re > vs. >=, here's an example where I've rounded to whole numbers to make the effect clearer:
for (var n = 0; n < 4; ++n) {
setTimeout(test.bind(null, n, true), 200 * n);
setTimeout(test.bind(null, n, false), 200 * n + 100);
}
function test(num, gte) {
var truths = 0;
var alternativetruths = 0;
var errors = 0;
function game() {
var score = Math.floor(Math.random() * 10);
return gte ? score >= 5 : score > 5;
}
for (var i = 0; i < 999999; i++) {
var flag = game();
if (flag) {
truths++;
} else {
alternativetruths++;
}
}
showStats(num, gte, truths, alternativetruths);
}
function showStats(num, gte, truths, alternativetruths) {
var total = truths + alternativetruths; // Should be 999999 of course
var truthsPercent = (truths * 100) / total;
var altPercent = (alternativetruths * 100) / total;
console.log(num, gte ? ">=" : ">", "truths:", truths, "alternativetruths:", alternativetruths, "(" + truthsPercent.toFixed(2) + "% vs. " + altPercent.toFixed(2) + "%)");
}
.as-console-wrapper {
max-height: 100% !important;
}
You need to assign game to a var before test for its value. Otherwise, everytime yout check the value with game() you will check a new value. So it can be false at the first check and true at the second and for this reason increment your errors.
Try this:
for(i=0;i<999999;i++) {
let gameResult = game();
if (gameResult === true) {
truths++
} else if (gameResult === false) {
alternativetruths++
} else {
errors++
}
}

I cannot return the real variable on processed recursion?

I have been doing this recursion in javascript; however I cannot return the real value of x on return. Instead, it is returning the processed value. The code is doing it's job but it's returning the processed variable on recursion. I tried to store the variable on x, but I still fail.
I want to return the last call stack to get the real variable.
This code returns 0 is Even, 1 is Even - how can the code be changed such that these cases would work as expected?
function isEven(x) {
var y =x;
if (x<0) {
x = x * -1;
}
if ( x===0 ) {
return console.log(y+' is Even');
} else if( x===1 ) {
return console.log(y+' is Odd');
} else {
return isEven(x-2);
}
// →
console.log(isEven(10));
console.log(isEven(-11));
}
You cannot access the initial value using your code.
The simplest way to achieve this goal is to add a function parameter, which will store the original value:
function isEven(x, initial) {
initial = initial || x; // so that isEven(10) => isEven(10, 10)
if (x<0) {
x = x * -1;
}
if(x===0) {
return initial+' is Even';
} else if(x===1) {
return initial+' is Odd';
} else
return isEven(x-2, initial);
}
// →
console.log(isEven(10));
console.log(isEven(-11));
However, the correct solution is to separate the initial call and recursive calls. For example, it can be achieved using nested functions.
It is also a good idea to abstract logics (boolean) and displayed information (string).
function isEvenString(initial) {
function isEvenBool(x) {
if (x < 0) {
x = x * -1;
}
if (x === 0) {
return true;
}
if (x === 1) {
return false;
}
return isEvenBool(x - 2);
}
return initial + (isEvenBool(initial) ? " is Even" : " is Odd");
}
// →
console.log(isEvenString(10));
console.log(isEvenString(-11));
P.S. Note that this isEven function is good for education purposes, but absolutely useless in practice. It takes 1 000 000 function calls to determine that 2 000 000 is even whilst it can be done using one line of code in O(1) operations:
function isEvenString(x) {
return x % 2 === 0;
}
I assume what you're trying to do is print the original value that was given, not the final value from the recursion. But you're reassigning y every time you recurse, so it doesn't contain the original value.
One solution is to split the function up into a main function and a recursive internal function.
function isEven(x) {
var y =x;
function isEvenRecurse(x) {
if (x<0) {
x = x * -1;
}
if(x===0) {
return y+' is Even';
} else if(x===1) {
return y+' is Odd';
} else {
return isEvenRecurse(x-2);
}
}
isEvenRecurse(y);
}
Another way is to pass an extra argument to the function when recursing.
function isEven(x, y) {
if (arguments.length == 1) {
y = x;
}
if (x<0) {
x = x * -1;
}
if(x===0) {
return y+' is Even';
} else if(x===1) {
return y+' is Odd';
} else {
return isEven(x-2, y);
}
}

How to get nearest key index in associative JavaScript array if key does not exist?

So, this might be a weird thing to try to do, but I'm curious if it's possible:
Say I have an associative array like this:
myarray[50] = 'test1'
myarray[100] = 'test2'
I can access 'test1' by it's key, of course:
myarray[50]; // returns 'test1'
But is there a way where if I have an index key of '60', that I can look in the array and if key 60 isn't there, get the value of the next "closest" key, '50'?
The use-case for this is that I am trying to set up cue-points for a video, and if the user seeks and misses a cue point, I want to display the information from the last cue point the user seeked beyond.
I think I can check for the existence of the key with the 'in' operator. But if it's not found, how can I get the "previous" or "next smallest" array key that DOES exist?
I assume the only way to do this is to iterate through the array, saving the "last" index value until the exit condition of "index > myKey" is found. The thing is, if it's a long video with lots of queue points and the user seeks frequently, iterating through the entire array of cue points each time might be slow. Is there a better, faster way to do this?
You'd have to write your own function:
function getClosestTo(val, array) {
if (array[val] !== undefined) {
return val;
} else {
var upper = val;
var upperMatched = false;
var lower = val;
var lowerMatched = false;
while(upper < this.length) {
if (array[++upper] !== undefined) {
upperMatched = true;
break;
};
};
while(lower > -1) {
if (array[--lower] !== undefined) {
lowerMatched = true;
break;
};
};
if (upperMatched && lowerMatched) {
return upper - val < val - lower ? upper : lower;
} else if (upperMatched) {
return upper;
} else if (lowerMatched) {
return lower;
};
};
return -1;
};
You could also add this as a method of the Array prototype, to make (what I think) is more readable:
Array.prototype.getClosestTo = function (val) {
if (this[val] !== undefined) {
return val;
} else {
var upper = val;
var upperMatched = false;
var lower = val;
var lowerMatched = false;
while(upper < this.length) {
if (this[++upper] !== undefined) {
upperMatched = true;
break;
};
};
while(lower > -1) {
if (this[--upper] !== undefined) {
lowerMatched = true;
break;
};
};
if (upperMatched && lowerMatched) {
return upper - val < val - lower ? upper : lower;
} else if (upperMatched) {
return upper;
} else if (lowerMatched) {
return lower;
};
};
return -1;
};
// Usage:
// var closestKey = theArray.getClosestTo(50);

Categories

Resources