CodeWars challenge. Which test is causing the fail? - javascript

Can anyone find out what is wrong with this code? I run the code on CodeWars and pass every test except one... sadly it does not display what the input was for that specific test so it is very difficult to figure it out.
Here are the challenge instructions:
The new "Avengers" movie has just been released! There are a lot of people at the cinema box office standing in a huge line. Each of them has a single 100, 50 or 25 dollars bill. A "Avengers" ticket costs 25 dollars.
Vasya is currently working as a clerk. He wants to sell a ticket to every single person in this line.
Can Vasya sell a ticket to each person and give the change if he initially has no money and sells the tickets strictly in the order people follow in the line?
Return YES, if Vasya can sell a ticket to each person and give the change. Otherwise return NO.
I found that the code works for ALL tests if I swap the check for amount50 >= 1 and amount25 >= 1 with the amount25 >= 3 but I am not sure WHY this works.
function tickets(peopleInLine){
let amount25 = 0;
let amount50 = 0;
let amount100 = 0;
for(let i = 0; i < peopleInLine.length; i++){
if(peopleInLine[i] === 100){
if(amount25 >= 3){
amount25 -= 3;
amount100++;
}else if(amount25 >= 1 && amount50 >= 1){
amount25 -= 1;
amount50 -= 1;
amount100++;
}else{
return "NO";
}
}
if(peopleInLine[i] === 50){
if(amount25 >= 1){
amount25--;
amount50++;
} else {
return "NO";
}
}
if(peopleInLine[i] === 25){
amount25++;
}
}
return "YES";
}

On Codewars you can put console.log statements (or equivalent statements in languages other than JavaScript) in your code to print the input parameters or other variables when you're having trouble figuring out what is going wrong in your code or with your assumptions about the input. I just did this with your code and saw that the test your code is failing on is [ 25, 25, 25, 25, 50, 100, 50 ], so that should show you exactly why your code would be failing when in response to getting a $100 you first try to return three $25s as change instead of checking for a $50 and $25 first -- you receive four $25s, one of which you give as change to the first person with a $50, but then because you give the remaining three $25s (rather than the $50 and one $25) as change to the person with the $100, you no longer have a $25 to make change for the last person's $50.

Related

How to determine possible combinations of items based on item resources?

I'm a current software development student looking to get some help with my latest self-learning project.
My coworkers and I play Settlers of Catan, so a couple of weeks ago I thought it would be a neat idea if I could make a site that would tell a person what they can buy with the resource cards they have in their hand.
For those who don't know, the basic Catan purchases are as follows:
Building
Cost
City
2 wheat, 3 ore
Settlement
1 wood, 1 brick, 1 wool, 1 ore
Road
1 wood, 1 brick
Dev. Card
1 wool, 1 wheat, 1 ore
What I need to do is take a players hand, which has any number of resource cards, and run it through a function that will determine a list of possible options along with the cards left over.
As an example it should return something like:
Option 1: You can build 1 City, 1 Road. 1 Sheep left over.
Option 2: You can build 1 Settlement. 3 Ore and 1 Wheat left over.
The function that I am currently using in JavaScript is shown below:
/* Below dictionary is updated via HTML inputs
Also sheep == wool, ignore the lack of using the accurate card name
*/
var resources = { 'wood': 1, 'brick': 1, 'sheep': 1, 'wheat': 2, 'ore': 3 };
/* Takes resources (your hand), then tries to determine what
the player can build with that hand */
function basicBuilder(resources) {
var buildDict = { 'roads': 0, 'settlements': 0, 'cities': 0, 'dcards': 0 }
while (resources['wheat'] >= 2 && resources['ore'] >= 3) {
resources['wheat'] -= 2;
resources['ore'] -= 3;
buildDict['cities'] += 1;
}
while (resources['wood'] >= 1 && resources['brick'] >= 1 && resources['sheep'] >= 1 && resources['wheat'] >= 1) {
resources['wood'] -= 1;
resources['brick'] -= 1;
resources['sheep'] -= 1;
resources['wheat'] -= 1;
buildDict['settlements'] += 1;
}
while (resources['sheep'] >= 1 && resources['wheat'] >= 1 && resources['ore'] >= 1) {
resources['sheep'] -= 1;
resources['wheat'] -= 1;
resources['ore'] -= 1;
buildDict['dcards'] += 1;
}
while (resources['wood'] >= 1 && resources['brick'] >= 1) {
resources['wood'] -= 1;
resources['brick'] -= 1;
buildDict['roads'] += 1;
}
return buildDict;
}
This way would work fine if none of the buildings shared resources, but since some buildings use the same cards it doesn't suit my purpose. For example if you use the resources that I supplied, buildDict['settlements'] will equal 0 since all the wheat was already used up by the city.
There has to be a better and cleaner way to go about this, so my question to all of you is this:
How can I best determine the players possible build choices on their turn?
As a reminder, the input will be a hand of resources in dictionary form.
The output should be similar to:
Option {n}: You can build {x} Cities, {x} Settlements, {x} Roads, etc... with {x} cards leftover
Bonus points for any of the following:
Solutions that easily allow for additional buildings later on (expansion packs)
Solutions that can somehow accept resource trading (in Catan, 4 of a resource can be traded in for 1 of any other resource. If you own a port, this can be reduced to either 3 or 2 for one trades)
Solutions that will still allow for the display of what the leftover cards are
EDIT - Reworded the question to be more specific per bots request, very new to stackoverflow. See past question above
With a hand (dictionary) full of resource cards, what is a good JavaScript way to find all the possible combinations of buildings that could be purchased?
Each building could be purchased multiple times
There is no maximum or fixed hand size
When a resource is used for a building, it is removed from the hand

Codewars Kata - 4th Kyu - Codewars style ranking system - "+1 problem"

I thought that this kata will be very cool and easy to get back to js after a break.
I was so wrong lol.
So the URL to kata is here with all of the logic and math informations, i'll put the necessary ones below.
URL:
https://www.codewars.com/kata/51fda2d95d6efda45e00004e/train/javascript
Code:
class User {
constructor() {
this.rank = -8;
this.progress = 0;
this.rankTable=[-8,-7,-6,-5,-4,-3,-2,-1,1,2,3,4,5,6,7,8];
this.rankIndicator=0;
}
incProgress(rankOfActivity) {
if (rankOfActivity == 0 || rankOfActivity > 8 || rankOfActivity < -8) throw new error("Rank input out of range");
if (rankOfActivity <= this.rank - 2) return;
let diff = this.rankTable.indexOf(rankOfActivity)-this.rankTable.indexOf(this.rank);
if (diff==0) this.progress+=3;
else if(diff==-1) this.progress+=1;
else if(this.rank!=8){
this.progress+= 10*diff*diff;
while(this.progress>=100 && this.rank<8){
this.progress-=100;
this.rankIndicator++;
this.rank=this.rankTable[this.rankIndicator];
}
}
if (this.rank==8) this.progress=0;
}
}
Completing an activity that is ranked one ranking lower than the user's will be worth 1 point
After i saw that, my point of view was:
If the difference between activity rank and user's rank was -1 ,for example:
User's rank is -2 (index 6 in rankTable array)
Activity ranked at -3 (index 5 in rankTable array)
The difference would be 5-6 = -1
So it should add up 1 point of progress, and it looks like it doesn't do that and i cant figure it out why it doesn't add up.
Here are bunch of errors to show that it happens on any rank.
After applying rank of -1 the progress was expected to be 21, but was actually 20
After applying rank of 3 the progress was expected to be 61, but was actually 60
After applying rank of 8 the progress was expected to be 51, but was actually 50
//...
//if (rankOfActivity <= (this.rank - 2)) return;
//bug
let diff = (this.rankTable.indexOf(rankOfActivity)) - (this.rankTable.indexOf(this.rank));
if (diff <=-2)return;//
//fixed
//...
Personally, i do not like array and indexOf use here. Using a rank counter of [0 to 15] would be a little better.

Code in Javascript, using if, else and prompt.

I am trying to write a code to answer the following. I have options of prizes. To be eligible for the prizes, you need to be within the age range of 20 and 40. If you are not eligible an alert saying you are not eligible will appear. If you are eligible; prompt will ask you for which prize you want and you need to answer with a numeric value. After they answer they will receive an alert that says "You will receive (prize, collected from the array) in your post within 2 weeks."
I have gotten this far with my code:
var prize = [
"0 = iPhone",
"1 = iPad",
"2 = iMac",
"3 = iPod"
];
var age = prompt("Please enter your age");
if (20 >= age && age <= 40){
alert("Sorry, you are not eligible for a prize.");
} else {
prompt("Which prize would you like to receive?");
} else if {
Would someone want to give me a hand? Thanks :)
You have mixed up a lot of the logic there, and actually put the "success" code within the "failure" condition.
I have no idea what you intend to do with the second prompt to choose the prize - and have even less clue why someone's age is the limiting factor in being eligible for a prize - but here is some logic that will correctly filter your desired age range:
var age = prompt("Please enter your age");
if (age >= 20 && age <= 40){
// handle successful prize claim here
}
else {
alert("Sorry, you are not eligible for a prize.");
}

else statement within nested if statements. How does this code know which else statement to execute?

I get the nested if loops (same as using && operator), but how does this code here know which conditions to execute with no conditions and just back to back else statements? One of them is within the nested if statements. I can tell that's obviously why this works the way it does, I just don't get how. Also, I know how to write this in several more readable ways testing multiple conditions. Please just explain what is happening with this code here. How does it know to output "You are too old" or "You are too young?"
var age = prompt("Please enter Your age here :");
var min_age=18;
var max_age=40;
if(age>=min_age){
if(age<=max_age){
console.log("You meet the requirements for this competition");
}else{
console.log("You are too old");
}
}else{
console.log("You are too young");
}
The if-then-else ambiguity is known for a long time. All languages have solved it by defining that an else will match the first perceding if. So:
if (a)
if (b)
x = 1;
else
x = 2;
resolves to:
if (a) {
if (b) {
x = 1;
}
else {
x = 2;
}
}
EDIT by Nisar's reuest:
The if statement is defined as:
if (<condition>) <statement> [else <statement>]
This means that a <statement> in the above may also be an if statement. So, for example:
if (<condition>) if (<condition>) [else <statement>] [else <statement>]
As each else part is optional, the compiler has no way of knowing when it sees an else part to which if it belongs. To solve that the language defines that an else always matches the first preceding if.
The brackets {} set the limit.
Try to think in pseudocode, look beyond the characters and think about what is happening.
Reading in order:
If you are old enough
If your are not too old
'You meet the requirements for this competition'
OTHERWISE
'You are too old'
END
OTHERWISE
'You are too young'
END
Note how indentation can help see the limits of the conditions. Each indented part can be separated.
Firstly, let's indent your code.
var age = prompt("Please enter Your age here :");
var min_age = 18;
var max_age = 40;
if (age >= min_age)
{
if (age <= max_age)
{
console.log("You meet the requirements for this competition");
}
else
{
console.log("You are too old");
}
}
else
{
console.log("You are too young");
}
Starting off..
var age = prompt("Please enter Your age here :");
Let's say you enter 21 in the prompt box, so age=21
We initialize
var min_age = 18;
var max_age = 40;
Now let's look at the first if condition.
if (age >= min_age)
If you substitute the values,this translates to
if (21 >= 18)
This is true,therefore we go inside the if block and not to the else.
The next line is.
if (age <= max_age)
This translates to
if (21 <= 40)
Considering this is also true, we print You meet the requirements for this competition.
The most important take-away from this is, indent your code, and the rest becomes pretty simple.
There are just 3 Options
too young
correct age
too old
First Check - is the person old enough?
if(age>=min_age)
Second check - is the person too old?
if(age<=max_age)
the only possible option left after this if statment is FALSE :
too old

Run a function as far as a variable reaches specific values

I have a canvas game which calls a function incScore every time an action is performed in the game to increase the score.
Inside incScore I have a few if statements to draw a particular image to represent a level number on the canvas.
I also want to have a sound play once per level up. The way I've gone about things the lvlup sound will play every time the score matches the if statement.
Can anyone please help me get this so that the sound will only play once when the level changes and not again until the next level change? I'm also mention I'm using jQuery incase it has anything that could help me.
incScore(); //everytime an action in the game causes the score to increase
function incScore(){
if (scoreTotal < 500){
lvlimg = "L01";
drawLevel(lvlimg);
lvlupSound();
}
else if (scoreTotal > 500 && scoreTotal < 1000){
lvlimg = "L02";
drawLevel(lvlimg);
lvlupSound();
}
else{
lvlimg = "L03";
drawLevel(lvlimg);
lvlupSound();
}
}
You could shorten your function and use a semi static property to save the state. Using that, you can compare the current level to the previous and play a sound if they differ.
function incScore(){
incScore.level = incScore.level || 'L0'; //< initialize property
lvlimg = "L0" + scoreTotal < 500 ? 1 : scoreTotal < 1000 ? 2 : 3;
drawLevel(lvlimg);
if (incScore.level!=='L0' &&
incScore.level !== lvlimg) { lvlupSound(); };
// ^compare local level to current
incScore.level = lvlimg;
// ^ update local level
}
[edit, based on comment] The third line is a so called ternary, or conditional operator. See MDN. You can use more conditions.
To avoid playing a sound before the score has reached a first level, you could use
if (incScore.level!=='L0' && incScore.level !== lvlimg).
I've created a mockup jsFiddle
A simple solution could be comparing the current level to the old one, to detect when the level changed:
function scoreToLevel(score)
if(score < 500){
return 1
}else if (score < 1000){
return 2
}else{
return 3
}
}
function incScore()
var next_level = scoreToLevel(scoreTotal)
if(next_level !== current_level){
lvlimg = "L0" + next_level;
drawLevel(lvlimg)
lvlupSound()
}
}
The easiest solution is to factor the sound out of those if statements. If the levels are nice and regular like that(every 500 points) and the points always increase in a way that you will always land exactly on an even multiple of 500 when you level up, something like this should do:
if(scoreTotal % 500 === 0 && scoreTotal < 1001)
{
lvlupSound();
}
If you won't always land directly on the gate to the next level(maybe the player can earn anywhere between 1 and 15 points at a time) then you should be able to get by using something along the lines of this before you increment the player's score:
if( (scoreTotal % 500) > ((scoreTotal + increment) % 500)
{
lvlupSound();
}
if your level boundries are not regular like that obviously it gets a little bit more complex, but that should get you started.
That is because you have the in every statement for every score (which means from 0 to infinite).
You will need to write inner if statements such as;
if (scoreTotal < 500){
lvlimg = "L01";
drawLevel(lvlimg);
if(scoreTotal x times of each the level) // That means for each level completed
{
lvlupSound();
}
}
If your score increment is only 1, then only play the tone when the score equals the threshold for a new level.
If they can increase their score by more than 1, then you could pass the number of points in and check the score before and after to see if the numbers fall on each side of the threshold.
If that still doesn't work, some more info on the "level" and points would be appreciated.
Try something like this (demo):
var scoreTotal,
lastLevel = 0,
levels = [500, 1000, 2500, 5000, 10000, 25000, 50000, 75000],
currentLevel = 0,
lvlImg;
function incScore() {
while (scoreTotal > levels[currentLevel]) {
currentLevel++;
}
if (lastLevel !== currentLevel) {
lastLevel = currentLevel;
// gives a two digit number with a leading zero
lvlImg = ('0' + currentLevel).slice(-2);
drawLevel("L" + lvlimg);
lvlupSound();
}
}
Then you can easily add additional levels by adding the score cutoff to the levels variable.

Categories