Hey guys this is my first post on here so take it easy on me! Apologies in advance for how basic this question is as I'm a beginner. I'm in the process of self learning and googling has been my best friend so far but I'm struggling to work out what's going wrong here. Maybe it is my approach altogether...
I am building a very simple game of Yahtzee with Javascript as my first project. Most of the program works smoothly however I can't seem to get the logic right for a full house. For anyone that doesn't know Yahtzee is played with 5 dice and a full house is a pair combined with 3 of a kind so for example [1, 1, 1, 6, 6] or [4, 4, 5, 5, 5]. I have a generated array with .sort() applied so my thinking is the logic should be if index 0 = index 2 and index 3 = index 4 OR index 0 = index 1 and index 2 = index 4. I have tried with multiple nested if statements and without nested parentheses but no luck there either. I understand it must be how I've used the logical operator as the first parentheses of code in each if statement works by itself.
function fullHouseFunc() {
if ((newRoll[0] === newRoll[2])&&(newRoll[3] === newRoll[4])) {
fullHouse.innerHTML = 25;
} else if ((newRoll[0] === newRoll[2])&&(newRoll[3] === newRoll[4])) {
fullHouse.innerHTML = 25;
}
};
You were almost there, just change the indices in the first if statement to 0 === 1 and 2 === 4. You had both statements checking 0 === 2 and 3 === 4:
let fullHouse = document.querySelector('.fh')
let newRoll = [4,4,5,5,5]
function fullHouseFunc() {
if ((newRoll[0] === newRoll[1])&&(newRoll[2] === newRoll[4])) {
fullHouse.innerHTML = 25;
} else if ((newRoll[0] === newRoll[2])&&(newRoll[3] === newRoll[4])) {
fullHouse.innerHTML = 25;
}
}
fullHouseFunc()
<div class='fh'></div>
Related
I know there's like 8 line solutions to convert integers to binary, but I'm trying my hand at creating a little program that does the same thing with arrays. I'm using 3 arrays, the first stores the original number to be converted and all the values of dividing that number by 2 and then rounding down when there's a remainder, aka [122, 61, 61, 30.5, 30, 15.5, 15, etc. etc.], and the second array will store the binary digits based on if remainder of division is true || false, aka [0,1,0,1,1,1,1]. Not yet written, but at the end I'll take the binaryArray and reverse and toString it to get 1111010, the correct binary for 211.
Obviously I'm doing more than one thing wrong, but I'm getting close as I can see the correct initial results when I console.log the main function. Any help here is appreciated, except I don't need to know how to do this entire concept easier, as I've already studied the easier solutions and am attempting this on purpose for practice.
Run the code snippet to see that the output is close to the solution, but obviously lastNumArray is not being updated and the entire thing is not looping.
let num = 122;
let array = [num];
let binaryArray = [];
let lastNumArray = array[array.length - 1];
function convertToBinary(number) {
let lastNumArray = number;
var result = (number - Math.floor(number)) !== 0;
if (result) {
binaryArray.push('1') &&
array.push(lastNumArray / 2) &&
array.push(Math.floor(array[array.length - 1]))
} else {
binaryArray.push('0') &&
array.push(lastNumArray / 2) && //this pushes 61
array.push(Math.floor(array[array.length - 1]))
}
}
while (array > 1) {
convertToBinary(lastNumArray) &&
lastNumArray.push(array[array.length - 1])
}
console.log(array)
console.log(binaryArray)
console.log(lastNumArray)
Any help or pointers here would be much appreciated. I've tried for loops, do while loops, and more and I'm getting close, but I really want to find out what I'm doing wrong here so I can learn. This is the first little function I've tried to write solo, and it's definitely keeping me humble!
You could try something like that with recursive call
let results = []
let binary = []
function cb(number) {
if (number === 0) return
results.push(number)
results.push(number / 2)
results.push(Math.floor(number / 2))
const last_index = results.length - 1
if (results[last_index] === results[last_index - 1]) {
binary.push("0")
} else {
binary.push("1")
}
cb(results[last_index])
}
cb(122)
console.log(results)
console.log(binary)
console.log(binary.reverse().join(""))
I have thought about this alot but i cant find a good solution..that is also fast in Javascript.
I have an array of objects..the objects are game searches for a random player.
The array may look like this:
const GameSearches[
{fromPlayerId:"378329",goalScore:20}
{fromPlayerId:"125342",goalScore:20}
{fromPlayerId:"378329",goalScore:20}
{fromPlayerId:"918273",goalScore:20}
{fromPlayerId:"378329",goalScore:20}
]
In this array i need to rund a function called CreateNewGame(Player1,Player2).
In this array i could create games with for example index 0 and 1. Index 2 and 3. Index 4 would be left in the array as there are no more players to match on.
Anyone got a good solution to this? It would really help me out.
I have tried different filter and map without finding a good solution.
The output should call a function createnewgame
Example:
createNewGame(GameSearches[0].from,GameSearches[1].from)
this function will be called as there are two players looking for a game. they do not have they same fromPlayerId so they should match.
I see some comments on that StackOverflow is not a free codingservice..the app has thousands of lines..this is only a small part. Im asking becouse i cant figure out the logic on how to to this. I do not need a full working example.
You can try something like this
const GameSearches = [
{fromPlayerId:"378329",goalScore:20},
{fromPlayerId:"125342",goalScore:20},
{fromPlayerId:"378329",goalScore:20},
{fromPlayerId:"918273",goalScore:20},
{fromPlayerId:"378329",goalScore:20}
];
const createNewGames = (player1, player2) => console.log(player1.fromPlayerId, player2.fromPlayerId)
const getMatch = (GameSearches) => {
while([...new Set(GameSearches)].length > 1){
const player1 = GameSearches[0];
GameSearches.shift();
const player2Index = GameSearches.findIndex(el => el.fromPlayerId !== player1.fromPlayerId)
const player2 = GameSearches[player2Index];
GameSearches.splice(player2Index,1)
createNewGames(player1, player2);
}
}
getMatch(GameSearches);
I think maybe i can use the suggestion of a for loop..and it will work fine.
for (let i = 0; i < games20GoalScore.length; i = i + 2) {
if (games20GoalScore[i + 1] !== undefined) {
console.log(games20GoalScore[i] + " : " + games20GoalScore[i + 1]);
if (games20GoalScore[i].from !== games20GoalScore[i + 1].from) {
console.log("Match");
}
}
}
This code is run each time the array get a new item.
I am writing a script for Premiere pro where I can add markers in the timeline and export a still for each marker in one go. However, when I write a function to check if the still has been previously created, the functions tells me it finds the previously created still, but then still creates a new one.
So basically: Function returns true, but still executes the else{}
//checks if the frame that is about to be exported already exists
if(checkIfExist(app.project.rootItem, outputFile)){
alert("frame already exists");
}else{
//This is where the actual still gets created and imported
activeSequence.exportFramePNG(time, outputFileName);
//here the previously created item gets moved to the appropriate bin (This is working great ATM)
moveToBin(outputFile);
}
}
}
//This function is meant to check if an item exists in the project bin. It does this by looping though all the items in the array from the start.
function checkIfExist(currentItem, name){
for(var i = 0; i<currentItem.children.numItems; i++){
currentChild = currentItem.children[i];
if(currentChild.name.toUpperCase() === name.toUpperCase()){
alert("Found: " + currentChild.name);
return true;
}if(currentChild.type == ProjectItemType.BIN){
checkIfExist(currentChild, name);
}
}
return false;
}
I think it happens because of the recursion you do:
if(currentChild.type == ProjectItemType.BIN){
checkIfExist(currentChild, name);
}
If this one gets kicked off before you can return true, you will start to run the function for a second time.
Now the first run can return a true, while the second (or even 3th, or 4th, etc) can return false and thus creating a new one, while also finding it.
Also if possible try to use arr.find or arr.findIndex and check if the value is -1 (or not found). This will make your code shorter, cleaner and less open for errors :)
But this will not work for nested arrays. Then you need to make an other function to first make a flat copy that includes all nested array before you do the arr.find or arr.findIndex. Still think that is the better solution.
You can use this to make nested array into a flat one:
let arr1 = [1,2,3,[1,2,3,4, [2,3,4]]];
function flattenDeep(arr1) {
return arr1.reduce((acc, val) => Array.isArray(val) ? acc.concat(flattenDeep(val)) : acc.concat(val), []);
}
flattenDeep(arr1);// [1, 2, 3, 1, 2, 3, 4, 2, 3, 4]
Let me be the first to say that this isn't something I normally do, but out of curiousity, I'll see if anyone has a good idea on how to handle a problem like this.
The application I am working on is a simulated example of the game Let's make a Deal featuring the Monty Hall problem.
I won't go into details about my implementation, but it more or less allows a user to enter a number of how many games they want to simulate, and then if an option is toggled off, the player of those x games won't switch their choice, while if it is toggled on, they will switch their choice every single instance of the game.
My object generator looks like this:
const game = function(){
this[0] = null;
this[1] = null;
this[2] = null;
this.pick = Math.floor(Math.random() * 3);
this.correctpick = Math.floor(Math.random() * 3);
this[this.correctpick] = 1;
for (let i=0; i<3; i++){
if ((this[i] !== 1) && (i !== this.pick)){
this.eliminated = i;
break;
}
}
}
const games = arg => {
let ret = [];
for(let i=0; i<arg; i++){
ret.push(new game);
}
return ret;
}
This structure generates an array which i stringify later that looks like this:
[
{
"0": 1,
"1": null,
"2": null,
"pick": 2,
"correctpick": 0,
"eliminated": 1
},
{
"0": null,
"1": null,
"2": 1,
"pick": 2,
"correctpick": 2,
"eliminated": 0
}
]
As sloppy as the constructor for game looks, the reason is because I have refactored it into having as few function calls as possible, where now I'm literally only calling Math functions at the current time (I removed any helper functions that made the code easier to read, in opt for performance).
This app can be ran both in the browser and in node (cross platform), but I have clamped the arg a user can pass into the games function to 5 million. Any longer than that and the process (or window) freezes for longer than a few seconds, or even potentially crashes.
Is there anything else I can do to increase performance if a huge number is given by a user? Also, if you need more information, I will be happy to supply it!
Thanks!
The obvious performance optimisation would be not to create and store 5 million objects at all, relieving memory pressure. Instead you'd create the objects on the fly only when you need them and throw them away immediately after. I'm not sure what your app does, but it sounds like you want to re-use the same game instances when evaluating results with the different options. In that case, you need to store them of course - but I'd advise to re-think the design and consider immediately evaluating each game with all possible options, accumulating only the results for each choice of options but not keeping all games in memory.
Apart from that, I'd recommend to simplify a bit:
You can drop that loop completely and use some clever arithmetic to find the eliminated option: this.eliminated = this.pick == this.correctpick ? +!this.pick : 3 - this.pick - this.correctpick;. Or use a simple lookup table this.eliminated = [1, 2, 1, 2, 0, 0, 1, 0, 0][this.pick * 3 + this.correctpick].
I'd avoid changing the type of the array elements from null (reference) to 1 (number). Just keep them as integers and initialise your elements with 0 instead.
Don't store 6 properties in your object that are completely redundant. You only need 2 of them: pick and correctpick - everything else can be computed on the fly from them when you need it. Precomputing and storing it would only be advantageous if the computation was heavy and the result was used often. Neither of this is the case, but keeping a low memory footprint is important (However, don't expect much from this).
Not sure about your implementation, but do you really need an Array?
How about only using results (see snippet)?
If it's blocking the browser that worries you, maybe delegating the work to a web worker is the solution for that: see this jsFiddle for a web worker version of this snippet.
(() => {
document.querySelector("#doit")
.addEventListener("click", playMontyHall().handleRequest);
function playMontyHall() {
const result = document.querySelector("#result");
const timing = document.querySelector("#timing");
const nOfGames = document.querySelector("#nGames");
const switchDoors = document.querySelector("#switchyn");
// Create a game
const game = (doSwitch) => {
const doors = [0, 1, 2];
const pick = Math.floor(Math.random() * 3);
const correctPick = Math.floor(Math.random() * 3);
const eliminated = doors.filter(v => v !== pick && v !== correctPick)[0];
return {
correctpick: correctPick,
pick: doSwitch ? doors.filter(v => v !== pick && v !== eliminated)[0] : pick,
eliminated: eliminated,
};
};
const getWinner = game => ~~(game.correctpick === game.pick);
// Sum wins using a generator function
const winningGenerator = function* (doSwitch, n) {
let wins = 0;
while (n--) {
wins += getWinner(game(doSwitch));
yield wins;
}
};
// calculate the number of succeeded games
const calculateGames = (nGames, switchAlways) => {
const funNGames = winningGenerator(switchAlways, nGames);
let numberOfWins = 0;
while (nGames--) {
numberOfWins = funNGames.next().value;
}
return numberOfWins;
}
const cleanUp = playOut => {
result.textContent =
"Playing ... (it may last a few seconds)";
timing.textContent = "";
setTimeout(playOut, 0);
};
const report = results => {
timing.textContent = `This took ${
(performance.now() - results.startTime).toFixed(3)} milliseconds`;
result.innerHTML =
`<b>${!results.switchAlways ? "Never s" : "Always s"}witching doors</b>:
${results.winners} winners out of ${results.nGames} games
(${((results.winners/+results.nGames)*100).toFixed(2)}%)`;
};
// (public) handle button click
function clickHandle() {
cleanUp(() => {
const nGames = nOfGames.value || 5000000;
const switchAlways = switchDoors.checked;
report({
switchAlways: switchAlways,
startTime: performance.now(),
winners: calculateGames(nGames, switchAlways),
nGames: nGames
});
});
}
return {
handleRequest: clickHandle
};
}
})();
body {
margin: 2em;
font: normal 12px/15px verdana, arial;
}
#timing {
color: red;
}
<p><input type="number" id="nGames" value="5000000"> N of games</p>
<p><input type="checkbox" id="switchyn"> Always switch doors</p>
<p><button id="doit">Play</button>
<p id="result"></p>
<p id="timing"></p>
Alright Odd results, not so much as they are expected. However I'm not sure how to over come it, I am having one of those days where every logical thing is the equivalent of a massive brain fart for me. Anyway. Lets say for the sake of ease. My array is numeric only nothing else in there.. My array ranges from 1-50 so my results upon sorting it are similar to 1, 10, 11, 12, 13.... 2, 20, 21, 22, 23... etc. When I need it to go like 1,2,3,4,5,6,7,8,9,10,11,12...
My simple little canned function is..
function sortJSONresultsByWidgetID(a,b)
{
if(parseInt(a.wigetID) == parseInt(b.wigetID))
{
return 0;
}
return parseInt(a.wigetID) > parseInt(b.wigetID) ? 1 : -1;
}
for reference I parseInt due to the JSON the way my JSON handles when I post it back and forth from the DB, I store the actual JSON in the DB and when passing it to the PHP it wraps quotes around the number turning them from INT to string (or from what I notice that may be browser based).
So here I am stuck now cause I want these things listed in a particular order and my brain wont work today.
EDIT example of me sorting results:
dashboardJSON.widgets.sort(sortJSONresultsByWidgetID);
You need to parse the ints with a radix of 10 and use the === operator instead of ==. I think that should do it.
function sortJSONresultsByWidgetID(a,b)
{
var widgetAId = parseInt(a.wigetID, 10);
var widgetBId = parseInt(b.wigetID, 10);
if(widgetAId === widgetBId)
{
return 0;
}
return widgetAId > widgetBId ? 1 : -1;
}
UPDATE - Here's with Ellian's optimization:
function sortJSONresultsByWidgetID(a,b)
{
return parseInt(a.wigetID, 10) - parseInt(b.wigetID, 10);
}