I would want to select a random winner from about 2 - 10 players.
Every player have precent chance to win. Someone have 50% and someone 10%.
Let's say we have 2 players. One player have 20% and other have 80%. How do I select winner between these two?.
Players are in array
var players = {
player1: {
chance: 20 //%
}
player2: {
chance: 80 //%
}
}
//Select winner from json
(Assuming the percentages all add up to 100)
You would first have to order the players. Then take a random number from 1 to 100, and find out which player that random number falls under.
For example:
// Modified json to array so we can easily loop through them
// If you would like help turning the json to an array, I can provide code for that upon request
var players = [
{
chance: 20
},
{
chance: 40
},
{
chance: 40
}
];
// Generate random number
var perc = Math.random() * 100; // between 0 and 99.999~
// Save where we are in the percentage
var currentPerc = 0;
// Loop through the players and check who the random number chose
for ( var pID = 0; pID < players.length; pID++ ) {
// Check if the current player we are looking at has won
if (perc < (players[pID].chance + currentPerc)) {
alert("PLAYER " + (pID + 1) + " HAS WON.");
// Do player winning code here
break; // break out of the loop, we're done
} else {
currentPerc += players[pID].chance;
}
}
In the above example, imagine that the random number chose 45 (0.45 * 100 since math.random gives us 0.0 to 0.99~).
This would mean that player 2 won
0 to 20 = Player 1 wins
21 to 60 = Player 2 wins
61 to 100 = Player 3 wins
Using 45 as the random number chosen The first iteration, we check if player 1 has won. He has not, so we add player 1's percentage to the "current percentage".
Then in the second iteration we check player 2. Since 45 < (20 + 40), player 2 has won chosen. We alert that he has won and will do some code for that.
var players = [20,5,15,40,20];
var getWinner = function(players){
var random = Math.random();
var sum = 0;
for(var i = 0; i < players.length; i++){
sum+= players[i]/100;
if(random<= sum) return i;
}
}
Returns the number of the player(index 0) who wins
Related
I've been going over this question now for a couple of days and I'm still no closer to getting it right or understanding as to how to get it to run properly.
This is the current code I have:
let waterPay = prompt("Please enter the amount of water you use to get a price you need to pay, thank you!");
if (waterPay < 6000) {
console.log("The number is below 6000");
console.log (waterPay / 1000); //The outcome of this must be saved as a different let
console.log (waterPay * 15.73);// outcome of the above times by this amount
}
else if (waterPay > 6000 && waterPay <= 10500) {
console.log("The number is between 6000 and 10500");
}
else if (waterPay > 10500 && waterPay <= 35000) {
console.log("The number is between 10500 and 35000");
}
else if (waterPay > 35000) {
console.log("The number is above 35000");
}
What my code needs to do is take an input from the user stating how many litres of water they use, you can see in the code that depending on the amount of litres they use it should print out how much they owe.
The table above states that the first 6 000 litres will cost R15.73 per kilolitre.
Next, water consumption above 6 000 litres but below 10 500 litres will be
charged at R22.38 per kilolitre. Therefore, a household that has used 8000
litres will pay R139.14 (15.73 x 6 + 22.38 x 2). The table carries on in this
manner.
Im battling to figure out how I should go about working this out. Any help would be appreciated.
The data structure needed is something that pairs rates with usage thresholds. The last threshold is effectively infinite, to catch any usage above the highest. The logic is to find() the right rate object and multiply that rate tier's rate by the usage.
let rateData = [{
upTo: 6000,
rate: 15.73
},
{
upTo: 10500,
rate: 22.38
},
{
upTo: 35000,
rate: 34.0. // made this one up, not in the OP
},
{
upTo: Number.MAX_SAFE_INTEGER,
rate: 50.0. // made this one up, not in the OP
}
];
function rateDatumForUsage(usage) {
return rateData.find(r => usage <= r.upTo);
}
function costForUsage(usage) {
const rateDatum = rateDatumForUsage(usage);
return usage * rateDatum.rate;
}
console.log(`The cost of using 5000 units is (15.73*5000) ${costForUsage(5000)}`)
console.log(`The cost of using 10000 units is (22.38*10000) ${costForUsage(10000)}`)
console.log(`The cost of using 100000 units is (50*100000) ${costForUsage(100000)}`)
Total cost should be calculated by steps.
This means that, for example, if the first 10 liters cost USD 2, the following 10 liters (from 10 to 20) cost USD 1 and from 20 cost will be USD 0.5, then the total cost for 30 liters will be: 10*2 + 10*1 + 10*0.5 = 35.
This can only be achieved generically by looping. Here is the code:
const steps = [
6000,
10500,
35000
];
const rates = [
10,
20,
30
];
function calculate(used) {
let output = 0;
for (let i = 0; i < steps.length; i++) {
if (used >= steps[i]) {
output += steps[i] * rates[i];
} else {
output += (used - (steps[i - 1] || 0)) * rates[i];
break;
}
}
return output;
}
console.log(calculate(3000));
console.log(calculate(6000));
console.log(calculate(9000));
console.log(calculate(50000));
I'm having trouble understanding the outcome of a game I have developed with the help of the book 'Learning JavaScript' by Ethan Brown.
Here is the code:
//helper functions for randomizing
function rand(x,y){
return x + Math.floor((y-x+1)*Math.random());
}
function getFace(){ return ['crown','heart','spade','club','diamond','anchor'][rand(0,5)]; }
//the game
function crownsAndAnchors(){
console.log('Let\'s play Crowns and Anchors!');
let rounds = 0;
let funds = 50;
while( funds > 1 && funds < 100 ){
rounds ++;
console.log(`Round: ${rounds}`);
let totalBet = 7;
let bets = { crown: 0, heart: 0, spade:0, club:0, diamond:0, anchor:0 };
if (totalBet == 7){
totalBet = funds;
console.log('You pulled out 7p, your lucky number! Bet all on heart');
bets.heart = totalBet;
}else{
//distribute totalBet randomly
}
funds = funds - totalBet;
console.log('\tBets: ' + Object.keys(bets).map(face => `${face} ${bets[face]}p`).join(' || ') + ` (total: ${totalBet} pence)`);
const hand = [];
// roll the dice
console.log("_______________rolling the dice ____________")
for (let i = 0; i < 3; i++) {
hand.push(getFace());
}
console.log(`\tHand: ${hand.join(', ')}`);
//check for winnings
let wins = 0;
for (let i = 0; i < hand.length; i++) {
let face = hand[i];
if (bets[face] > 0) wins = wins + bets[face];
}
funds = funds + wins;
console.log(`\tWinnings: ${wins}`);
}
console.log(`\nEnding Funds: ${funds}`);
}
crownsAndAnchors();
I have hard-coded variable totalBet to be 7 to easily monitor final outcome. For example, if two out of three die outcomes are heart than the Ending Funds should be 150, correct?
However, when I run the code (Node v7.6.0) this is what I am returned:
Let's play Crowns and Anchors!
Round: 1
You pulled out 7p, your lucky number! Bet all on heart
Bets: crown: 0p || heart: 50p || spade: 0p || club: 0p || diamond: 0p || anchor: 0p (total: 50 pence)
_______________rolling the dice ____________
Hand: heart, heart, club
Winnings: 100
Ending funds: 100
I know I'm somehow updating funds incorrectly I just cannot figure out why.
Thank you so much in advance!!!
The line
funds = funds - totalBet;
is setting funds to 0, then later you get two wins of 50 added to it to give you 100.
If you eliminate that line where funds = funds - totalBet, then you get the 150 you are expecting.
Or move that line to after the dice roll and only execute it if you did not win anything.
I'm trying to make it to where when a user does a certain thing, they get between 2 and 100 units. But for every 1,000 requests I want it to add up to 3,500 units given collectively.
Here's the code I have for adding different amounts randomly to a user:
if (Math.floor(Math.random() * 1000) + 1 === 900) {
//db call adding 100
}
else if (Math.floor(Math.random() * 100) + 1 === 90) {
//db call adding 40
}
else if (Math.floor(Math.random() * 30) + 1 === 20) {
//db call adding 10
}
else if (Math.floor(Math.random() * 5) + 1 === 4) {
//db call adding 5
}
else {
//db call adding 2
}
If my math is correct, this should average around 4,332 units per 1,000 calls. But obviously it would vary and I don't want that. I'd also like it to add random amounts instead, as the units added in my example are arbitrary.
EDIT: Guys, Gildor is right that I simply want to have 3,500 units, and give them away within 1,000 requests. It isn't even entirely necessary that it always reaches that maximum of 3,500 either (I could have specified that). The important thing is that I'm not giving users too much, while creating a chance for them to win a bigger amount.
Here's what I have set up now, and it's working well, and will work even better with some tweaking:
Outside of call:
var remaining = 150;
var count = 0;
Inside of call:
count += 1;
if (count === 100) {
remaining = 150;
count = 0;
}
if (Math.floor(Math.random() * 30) + 1 === 20) {
var addAmount = Math.floor(Math.random() * 85) + 15;
if (addAmount <= remaining) {
remaining -= addAmount;
//db call adding addAmount + 2
}
else {
//db call adding 2
}
}
else if (Math.floor(Math.random() * 5) + 1 === 4) {
var addAmount1 = Math.floor(Math.random() * 10) + 1;
if (addAmount1 <= remaining) {
remaining -= addAmount1;
//db call adding addAmount1 + 2
}
else {
//db call adding 2
}
}
else {
//db call adding 2
}
I guess I should have clarified, I want a "random" number with a high likelihood of being small. That's kind of part of the gimmick, where you have low probability of getting a larger amount.
As I've commented, 1,000 random numbers between 2 and 100 that add up to 3,500 is an average number of 3.5 which is not consistent with random choices between 2 and 100. You'd have to have nearly all 2 and 3 values in order to achieve that and, in fact couldn't have more than a couple large numbers. Nothing even close to random. So, for this to even be remotely random and feasible, you'd have to pick a total much large than 3,500. A random total of 1,000 numbers between 2 and 100 would be more like 51,000.
Furthermore, you can't dynamically generate each number in a truly random fashion and guarantee a particular total. The main way to guarantee that outcome is to pre-allocate random numbers that add up to the total that are known to achieve that and then random select each number from the pre-allocated scheme, then remove that from the choice for future selections.
You could also try to keep a running total and bias your randomness if you get skewed away form your total, but doing it that way, the last set of numbers may have to be not even close to random in order to hit your total consistently.
A scheme that could work if you reset the total to support what it should be for actual randomness (e.g. to 51,000) would be to preallocated an array of 500 random numbers between 2 and 100 and then add another 500 numbers that are the complements of those. This guarantees the 51 avg number. You can then select each number randomly from the pre-allocated array and then remove it form the array so it won't be selected again. I can add code to do this in a second.
function RandResults(low, high, qty) {
var results = new Array(qty);
var limit = qty/2;
var avg = (low + high) / 2;
for (var i = 0; i < limit; i++) {
results[i] = Math.floor((Math.random() * (high - low)) + low);
//
results[qty - i - 1] = (2 * avg) - results[i];
}
this.results = results;
}
RandResults.prototype.getRand = function() {
if (!this.results.length) {
throw new Error("getRand() called, but results are empty");
}
var randIndex = Math.floor(Math.random() * this.results.length);
var value = this.results[randIndex];
this.results.splice(randIndex, 1);
return value;
}
RandResults.prototype.getRemaining = function() {
return this.results.length;
}
var randObj = new RandResults(2, 100, 1000);
// get next single random value
if (randObj.getRemaining()) {
var randomValue = randObj.getRand();
}
Working demo for a truly random selection of numbers that add up to 51,000 (which is what 1,000 random values between 2 and 100 should add up to): http://jsfiddle.net/jfriend00/wga26n7p/
If what you want is the following: 1,000 numbers that add up to 3,500 and are selected from between the range 2 to 100 (inclusive) where most numbers will be 2 or 3, but occasionally something could be up to 100, then that's a different problem. I wouldn't really use the word random to describe it because it's a highly biased selection.
Here's a way to do that. It generates 1,000 random numbers between 2 and 100, keeping track of the total. Then, afterwards it corrects the random numbers to hit the right total by randomly selected values and decrementing them until the total is down to 3,500. You can see it work here: http://jsfiddle.net/jfriend00/m4ouonj4/
The main part of the code is this:
function RandResults(low, high, qty, total) {
var results = new Array(qty);
var runningTotal = 0, correction, index, trial;
for (var i = 0; i < qty; i++) {
runningTotal += results[i] = Math.floor((Math.random() * (high - low)) + low);
}
// now, correct to hit the total
if (runningTotal > total) {
correction = -1;
} else if (runningTotal < total) {
correction = 1;
}
// loop until we've hit the total
// randomly select a value to apply the correction to
while (runningTotal !== total) {
index = Math.floor(Math.random() * qty);
trial = results[index] + correction;
if (trial >= low && trial <= high) {
results[index] = trial;
runningTotal += correction;
}
}
this.results = results;
}
This meets an objective of a biased total of 3,500 and all numbers between 2 and 100, though the probability of a 2 in this scheme is very high and the probably of a 100 in this scheme is almost non-existent.
And, here's a weighted random generator that adds up to a precise total. This uses a cubic weighting scheme to favor the lower numbers (the probably of a number goes down with the cube of the number) and then after the random numbers are generated, a correction algorithm applies random corrections to the numbers to make the total come out exactly as specified. The code for a working demo is here: http://jsfiddle.net/jfriend00/g6mds8rr/
function RandResults(low, high, numPicks, total) {
var avg = total / numPicks;
var i, j;
// calculate probabilities for each value
// by trial and error, we found that a cubic weighting
// gives an approximately correct sub-total that can then
// be corrected to the exact total
var numBuckets = high - low + 1;
var item;
var probabilities = [];
for (i = 0; i < numBuckets; i++) {
item = low + i;
probabilities[i] = avg / (item * item * item);
}
// now using those probabilities, create a steps array
var sum = 0;
var steps = probabilities.map(function(item) {
sum += item;
return sum;
});
// now generate a random number and find what
// index it belongs to in the steps array
// and use that as our pick
var runningTotal = 0, rand;
var picks = [], pick, stepsLen = steps.length;
for (i = 0; i < numPicks; i++) {
rand = Math.random() * sum;
for (j = 0; j < stepsLen; j++) {
if (steps[j] >= rand) {
pick = j + low;
picks.push(pick);
runningTotal += pick;
break;
}
}
}
var correction;
// now run our correction algorithm to hit the total exactly
if (runningTotal > total) {
correction = -1;
} else if (runningTotal < total) {
correction = 1;
}
// loop until we've hit the total
// randomly select a value to apply the correction to
while (runningTotal !== total) {
index = Math.floor(Math.random() * numPicks);
trial = picks[index] + correction;
if (trial >= low && trial <= high) {
picks[index] = trial;
runningTotal += correction;
}
}
this.results = picks;
}
RandResults.prototype.getRand = function() {
if (!this.results.length) {
throw new Error("getRand() called, but results are empty");
}
return this.results.pop();
}
RandResults.prototype.getAllRand = function() {
if (!this.results.length) {
throw new Error("getAllRand() called, but results are empty");
}
var r = this.results;
this.results = [];
return r;
}
RandResults.prototype.getRemaining = function() {
return this.results.length;
}
As some comments pointed out... the numbers in the question does not quite make sense, but conceptually there are two approaches: calculate dynamically just in time or ahead of time.
To calculate just in time:
You can maintain a remaining variable which tracks how many of 3500 left. Each time when you randomly give some units, subtract the number from remaining until it goes to 0.
In addition, to make sure each time at least 2 units are given, you can start with remaining = 1500 and give random + 2 units each time.
To prevent cases that after 1000 gives there are still balances left, you may need to add some logic to give units more aggressively towards the last few times. However it will result in not-so-random results.
To calculate ahead of time:
Generate a random list with 1000 values in [2, 100] and sums up to 3500. Then shuffle the list. Each time you want to give some units, pick the next item in the array. After 1000 gives, generate another list in the same way. This way you get much better randomized results.
Be aware that both approaches requires some kind of shared state that needs to be handled carefully in a multi-threaded environment.
Hope the ideas help.
okay i guys i just got into java script and i made a simple game it works and does everything i wanted but now i want to make it difficult so that every time the enemy health is 0 it refill but comes back stronger as in it has more health this is what i came up with this is the part that makes it refill it adds 100 but only stays 200 when it refills i want it to increase by 100 every time it becomes 0
if (enemyHealth<=0) {
enemyHealth=0;
alert("you win");
gold=gold+500;
document.FGame.Output.value=gold;
enemyHealth=100+100;
}
It's because you always set the enemyHealth to 100 + 100, which will always equal 200. What you could do is to have a totalEnemyHealth variable which increase by 100 every time the enemy dies. When you revive that enemy, you would set it's health to the new totalEnemyHealth value.
//make sure not to re-initialize this variable every time
var totalEnemyHealth = 100;
//then in your function
if (enemyHealth<=0){
enemyHealth = totalEnemyHealth += 100;
alert("you win")
gold=gold+500;
document.FGame.Output.value=gold;
}
However if you have multiple ennemies, that approach will not give the desired results. To solve your problem you will need something more object-oriented, such as all ennemies represented by an Enemy instance, where the instance would have the capability of tracking how many times it died and use this as a health multiplier.
Simple example:
var Enemy = {
baseHealth: 100,
health: 100,
deathCount: 0,
takeDamage: function (amount) {
if ((this.health -= amount) <= 0) {
this.die();
this.respawn();
}
},
die: function () {
this.deathCount++;
},
respawn: function () {
this.health = (this.deathCount + 1) * this.baseHealth;
}
};
var someEnemy = Object.create(Enemy);
console.log(someEnemy.health); //100
someEnemy.takeDamage(150); //violent attack
console.log(someEnemy.health); //200
Here is an example:
http://jsfiddle.net/9zhqg/1/
var gold = 0;
for(i = 0; i < 20; i++){
var num = Math.floor(Math.random()*10);
var enemyHealth = num *i;
if (enemyHealth<=0){
//enemyHealth=0
alert(i + "you win")
gold+= 500;
//document.FGame.Output.value=gold;
enemyHealth += 100
alert(enemyHealth);
}
}
You can see when it runs, the number of times it hit 0 out of a for loop of 20 times. Then it bounces the health back to 100. I think this is what you need. - not 100% sure if I understand your use case.
You could just add a counter. Something simple like:
var counter=1; //at start of game
if (enemyHealth<=0)
{
enemyHealth=0
alert("you win")
gold=gold+500;
document.FGame.Output.value=gold;
enemyHealth=100+(100*counter);
counter++;
}
I am trying to build a game in pure JavaScript as an exercise.
The game purpose is to answer a random math exercise before a timer runs out. The time is represented by an egg that falls on someones head; if you answered all of the math exercises correctly, you will start over, but the time will be shortened by 2 seconds.
My problem: During level 1 of the game, the time works as expected, but by level 2 time is getting shorter by half. What is causing this to happen?
Related code:
var gameTime;
//function responsible for starting The game
function StartGame() {
...
...
...
checkLevel();
getNewTime();
speed=getNewSpeed();
dh=setInterval("move(egg)",gameTime);
...
}//End start game
function checkLevel() {
if(document.getElementById("begginer").checked==true) {
fillNumbervalue(true);
gameTime=30;
}
else {
fillNumbervalue(false);
gameTime=60;
} //End else
}//End of checkLevel
function getNewSpeed () {
return (distanceBetweenEggToYudale/gameTime); //distanceBetweenEggToYudale=310
}//End function
//if player pass level this function will get down by 2 seconds the time
function getNewTime() {
for(var i=0;i<levelCount;i++)
gameTime-=2;
}//end getNewTime
//function responsible for moving The Egg
function move(eggBall) {
eggBall.imagePositionY=eggBall.imagePositionY+(gameTime/1000)*speed;
//image postion=0 at the beginning
eggBall.element.style.top=eggBall.imagePositionY+"px";
...
...
}//End move
//when the player push the answer button
function answerValidation() {
var answers=new Array();
for(var i=0;i<result.length;i++)
answers[i]=document.getElementById("txtAnswer"+(i+1)).value;
if(result[0]!=answers[0] || result[1]!=answers[1] || result[2]!=answers[2])
gameOverScreen();
else
{
score++;
levelCount++;
init(); //Initial the egg position onload of the body element
clearTxtRows();
gameTime-=2;
StartGame();
}//End else
}//End anwser validation
I know this question is loaded with code, so I would really appreciate if someone can help.
The problem is that you're reusing your gameTime variable, when what you want to do is start at the same time and decrement from that. So you want a startGameTime variable.
With only a gameTime variable:
http://jsfiddle.net/DPTJ3/1/
With a startGameTime variable to restart the gameTime value before decrement:
http://jsfiddle.net/DPTJ3/
function getNewTime() {
gameTime = startGameTime;
for (var i = 0; i < levelCount; i++) {
gameTime -= 2;
}
}
function logData() {
log = document.getElementById('log');
log.innerHTML += "LEVEL: " + levelCount + "\nGTIME: " + gameTime + "\n\n";
}
var levelCount = 1;
var startGameTime = 60;
var gameTime = 60;
logData();
for (var i = 0; i < 10; i++) {
levelCount++;
getNewTime();
logData();
}
OUTPUT
LEVEL: 1
GTIME: 60
LEVEL: 2
GTIME: 56
LEVEL: 3
GTIME: 54
LEVEL: 4
GTIME: 52
LEVEL: 5
GTIME: 50
LEVEL: 6
GTIME: 48
LEVEL: 7
GTIME: 46
LEVEL: 8
GTIME: 44
LEVEL: 9
GTIME: 42
LEVEL: 10
GTIME: 40
LEVEL: 11
GTIME: 38
EDIT
Also, if you want to accurately decrement, you should probably account for the fact that the first level is really 0 instead of one to the getNewTime() function. If you notice, it seems to decrement the first by two level degrees. To resolve this, you can:
for (var i = 0; i < levelCount - 1; i++) { // Notice the - 1