Dynamically populate value of array in a Div - javascript

I'm creating an function that can shuffle and deal poker deck to user based on number of player provided by the user in a input field. I've completed the shuffling function but I'm having issue with dealing the card. How can I deal the entire deck equally based on the number_of_people value given in html, for example if the number_of_people = 3 :
Person 1 : S-Q, D-J, D-K, C-7, S-J....
Person 2 : H-6, D-X, D-A, H-2, S-6....
Person 3 : D-Q, H-5, D-8, S-2, S-8....
also if user insert more than 52 number_of_people it will still deal and display but the 53rd and above player will have an empty hand e.g :
Person 53 :
Person 54 :
Person 55 :
Below is my code :
HTML :
<div class="position-ref full-height">
<div class="content">
<div class="title m-b-md">
Let's Play
</div>
<div>
<input id="number_of_people" type="number" max="99" placeholder="No. of People"></input>
<button onclick="shuffleCards()">Shuffle</button>
</div>
<div class="results">
</div>
</div>
Javascript :
// Create a function to distribute card
function shuffleCards() {
// Get input value
var number_of_people = document.getElementById("number_of_people").value
// Declare card elements
const card_types = ["S", "D", "C", "H"];
const card_values = ["A", "2", "3", "4", "5", "6", "7", "8", "9", "X", "J", "Q", "K",];
// Create deck array
let deck = [];
// Validate the value inserted by user
if (number_of_people > 0 && number_of_people !== null) {
// Create a deck of cards
for (let i = 0; i < card_types.length; i++) {
for (let x = 0; x < card_values.length; x++) {
let card = { cardValue: card_values[x], cardTypes: card_types[i] };
deck.push(card);
}
}
// Shuffle the cards
for (let i = deck.length - 1; i > 0; i--) {
let j = Math.floor(Math.random() * i);
let temp = deck[i];
deck[i] = deck[j];
deck[j] = temp;
}
// Clear content
$(".results").html(``);
// Distribute the card
for (let i = 0; i < deck.length; i++) {
console.log(`${deck[i].cardTypes}-${deck[i].cardValue}`)
$(".results").append( `<p>${deck[i].cardTypes}-${deck[i].cardValue}, </p>` );
}
}
else {
$(".results").html( `<h3>Input value does not exist or value is invalid</h3>` );
return;
}
}
</script>

You can replace the "Distribute the cards" loop, with the following loop:
for (let person = 0; person < number_of_people; person++) {
$(".results").append(
$("<p>").append(
`Person ${person+1}: `,
deck.splice(-Math.ceil(deck.length / (number_of_people - person))).map(card =>
`${card.cardTypes}-${card.cardValue}`
).join(", ")
)
);
}
This actually extracts the right amount of cards from the end of the deck in one go, and displays them on a single line. Since the deck of cards is shuffled, it doesn't matter from where in the deck you pull the cards, so you might as well do it like this.
A remark about your code:
if (number_of_people > 0 && number_of_people !== null) {
If the first of these two conditions is true, then the second is always true as well, so there is no need to have that second condition. Moreover, the .value property of an input element is never null, but potentially an empty string.
You should really convert the input from string to a number. For instance with the unary plus:
var number_of_people = +document.getElementById("number_of_people").value;

Related

How to render elements based on a given value in React JS?

I want to render some stars based on a specific value, and this is what I have done so far
const Rating = ({ value }) => {
const renderStars = () => {
let stars = []; // This array should contain all stars either full, half or empty star
for (let i = 0; i < value; i++) {
if (value % 1 !== 0) {
// If the value has decimal number
} else {
// If the value has NO decimal number
}
}
return stars?.map((star) => star); // Mapping the stars array
};
return <div className="rating">{renderStars()}</div>;
};
export default Rating;
Now I have 3 icons: a full star, a half star, and an empty star. Let's say the rating value is 3.5, so what I want is to push to the stars array 3 full stars 1 half star and 1 empty star so that will be 5 stars in total. And then I can map through the array and render all the stars.
You can loop through up until your value as you're currently doing, where for each iteration you push a full star, and then after the loop is complete, check if value is a decimal to determine if you should push an additional half star:
const STAR_COUNT = 5;
const Rating = ({ value }) => {
const stars = Array.from({length: STAR_COUNT}, () => <EmptyStar />);
let i;
for (i = 0; i < value; i++) { // this will loop Math.floor(value) times
stars[i] = <FullStar />;
}
if (value % 1 != 0) // if value is a decimal, add a half star
stars[i-1] = <HalfStar />;
return <div className="rating">{stars}</div>;
};
I would also suggest wrapping this component in a call to React.memo() so that the for loop logic only runs when your value prop changes, and not what the parent rerenders.
Another, perhaps more concise way, is to use some array methods to help, such as .fill() to populate an array firstly with empty stars, then replace those empty stars up to a given index based on your value, and finally add a half star if required:
const STAR_COUNT = 5;
const Rating = ({ value }) => {
const stars = Array(STAR_COUNT).fill(<EmptyStar />).fill(<FullStar />, 0, Math.floor(value));
if (value % 1 != 0) // if value is a decimal, add a half star
stars[Math.floor(value)] = <HalfStar />;
return <div className="rating">{stars}</div>;
};
Try this in your code
let rating = 3.5;
let ratingCount = 0
for(let i=1; i<=5; i++){
if(i<=rating){
console.log("full")
ratingCount++
}
}
if(rating-Math.floor(rating) !== 0){
console.log("Half")
ratingCount++
}
for(let i=ratingCount ; i<5; i++){
console.log("empty")
}

How to remove items from a list after chosen by randomNumber

So I'm making an app for a computer science class and basically, the premise is that you work at a pizza place and you have to select the toppings that a customer wants, which are randomly selected. Currently, I have the toppings in a list that will pick them with randomNumber() but I can't figure out how to remove the topping after it is chosen, to avoid repeats.
var toppings = ["pepperoni", "mushrooms", "pineapple", "peppers", "sausage", "sardines",
"bacon"];
function newCustomer() {
showElement("customerPic");
for (var i = 0; i < 3; i++) {
toppings[(randomNumber(0, 6))];
console.log(("I would like " + toppings[(randomNumber(0,6))]) + " on my pizza,
please");
}
}
To me the easiest way to do this seems to be by creating a new array that contains the strings in your original toppings array, but in a randomized order - you can treat that array as a stack and continue to pop the randomized elements off it until none remain. See the code comments for more details:
// Your original data
var toppings = [
"pepperoni",
"mushrooms",
"pineapple",
"peppers",
"sausage",
"sardines",
"bacon"
];
// A new array that contains same strings as `toppings`, but their order's randomized
const shuffledToppings = [...toppings].sort(() => Math.random() - 0.5);
// `pop` is an Array.prototype function that removes the and returns the last item in the array - this means `shuffledToppings` is shrinks by 1 each time this function is called
function newCustomer() {
console.log(`I'd like a pizza with ${shuffledToppings.pop()}`);
}
// Call `newCustomer` function until all strings have been popped off `shuffledToppings` (i.e.< it is empty).
while (shuffledToppings.length > 0) {
newCustomer();
}
Reference: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/pop
Basically, you need to remove an element from the original array on every iteration and then get a random number with a max value equals to the size of filtered array.
Try this code (obviously it can be improved, eg copying original array ecc):
function removeItemOnce(arr, value) {
var index = arr.indexOf(value);
if (index > -1) {
arr.splice(index, 1);
}
return arr;
}
function newCustomer() {
showElement("customerPic");
for (var i = 0; i < 3; i++) {
let ix = randomNumber(0, toppings.length);
let v = toppings[ix];
toppings = removeItemOnce(toppings,v)
console.log("I would like " + v + " on my pizza, please");
}
}
More info about array item removing: How can I remove a specific item from an array?

jQuery: Cycle through elements to create combo variations

Premise: An eCommerce system with variations.
Example HTML markup for use in this question.
<div class = "variationType" data-variation-type = "size">
<h3>Colour</h3>
<div class = "variation" data-variation-type = "size"> small </div>
<div class = "variation" data-variation-type = "size"> large </div>
</div>
<div class = "variationType" data-variation-type = "colour">
<h3>Colour</h3>
<div class = "variation" data-variation-type = "colour"> red </div>
<div class = "variation" data-variation-type = "colour"> blue </div>
</div>
<div class = "variationType" data-variation-type = "material">
<h3>Material</h3>
<div class = "variation" data-variation-type = "material"> stone </div>
<div class = "variation" data-variation-type = "material"> wood </div>
</div>
What I need to do is cycle through each of the above variation types and variation names to create a list of all possible variation combos (at least one variation from each variation type). This is stupid easy if there are only two variation types, but I'd need this to work with 3+ as well.
My thinking is that I need to somehow implement a pathing algorithm to go through each variation type and create the unique list, but I don't know how to do this.
In order to get the total amount of possible variations, I am doing the following.
// figure out how many variations there needs to be
var totalPathsToTake = 0;
var totalPathsTaken = 0;
jQuery('.variationType').each(function(i) {
var variationType = jQuery(this).attr("data-variation-type");
var totalVariationsInType = jQuery('.variation[data-variation-type="' + variationType + '"]').length;
if(totalPathsToTake == 0){
totalPathsToTake = totalPathsToTake + totalVariationsInType;
} else {
totalPathsToTake = totalPathsToTake * totalVariationsInType;
}
});
console.log("total variations " + totalPathsToTake)
So the above code will respond with 8, which is correct.
The problem is, now what? How would I go about creating these variations? Any help or advice is insanly appreciated!
From what I understand, what you want is all the permutations of div.variations.
One way to do it is to realize that as we permute one variation type we are always reusing the permutations of the variation types that follow it. This lends itself to a recursive implementation like this:
// make an array of variation types, and each entry is the list of possible values
const all = $('.variationType').map((i, el) => $('.variation', el)).toArray();
// recursive function, return all permutations of values for a array of variation types
function permute_variations(arr) {
// base case of no variation types
if (arr.length < 1)
return [];
// base case of a single variation type
if (arr.length === 1)
return arr[0].toArray();
// recurse by getting the permutations of the following variation types
const inner_arr = permute_variations(arr.slice(1));
// now permute all values for this type with the permutations that we got
return arr[0].map((i, v0) => inner_arr.map(e => [v0].concat(e))).toArray();
}
const result = permute_variations(all);
console.log(`Number of permutations: ${result.length}`);
console.log(result);
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="variationType" data-variation-type="size">
<h3>Colour</h3>
<div class="variation" data-variation-type="size"> small </div>
<div class="variation" data-variation-type="size"> large </div>
</div>
<div class="variationType" data-variation-type="colour">
<h3>Colour</h3>
<div class="variation" data-variation-type="colour"> red </div>
<div class="variation" data-variation-type="colour"> blue </div>
</div>
<div class="variationType" data-variation-type="material">
<h3>Material</h3>
<div class="variation" data-variation-type="material"> stone </div>
<div class="variation" data-variation-type="material"> wood </div>
</div>
The result is an array of triples of div.variation elements and you can process it as you like.
Note: be careful of the difference between the Array map() method and the jQuery map() method, as you can see they call the lambda function with the index and element parameters in opposite order.
I'm not a native English speaker
so I can't explain it well
but I'll try my best
that would be appreciated if there's any suggestion
First, I simplify the problem to find combinations of two array
var arr1 = ["0","1"]
var arr2 = ["0","1"]
and we all know that the results would be like:
(first char comes from arr1)
(last char comes from arr2)
00
01
10
11
Then I change the values of the second array to
var Second = ["0","1","2"]
the results are:
00
01
02
10
11
12
after this, I add another array
var Third = ["0","1"]
the results are:
000
001
010
011
020
021
100
101
110
111
120
121
I found there's a logic to determine how many times would a single num repeat and whole array values repeat
We can calculate the combinations simply by multiple each array's length
(if array's length is greater than 0)
a single num would repeat combinations / previous array's length product times
and whole array values would repeat combinations / all previous array's length product(including self)
when combinations is 4 in case 1, last char repeat 1 time since there's no previous array
first char repeat 4 / First.length = 2 times
when combinations is 12 in case 3, the last array of result repeat 12/First.length = 6 times
first array repeat 12/(First.length * Second.length * Third.length) = 1 times
so here it is, hope this helps
var Result = []
var Final = []
var Combinations = 1
var First = ["0", "1", "2"]
var Empty = []
var Second = ["a", "b", "c", "d"]
var Third = ["+", "-"]
// assume there would be some empty array
var allList = [First, Second, Empty, Third].filter(n => n.length>0).reverse() // remove empty array and reverse
allList.forEach(arr => Combinations = arr.length > 0 ? Combinations * arr.length : Combinations) // calculate combinations
$("body").append("Combinations : " + Combinations + "<br>")
var Items = 1
var totalRepeatTimes = 1
var elementRepeatTimes = 1
allList.forEach((arr ,index) => {
Items *= arr.length;
// array repeat times
totalRepeatTimes = Combinations/Items;
// each char repeat times
elementRepeatTimes = index > 0 ? elementRepeatTimes * allList[index - 1].length : elementRepeatTimes;
// add result array to Final
Final.push(RepeatArray(arr, elementRepeatTimes, totalRepeatTimes))
})
Result = Array(Combinations).fill("."); // prepare an array fill with empty string
Final.reverse().forEach(arr => { Result = Join(Result, arr) }) // Join all result array
Result.forEach((result, index)=> $("body").append((index+1) + " : " + result + "<br>") )
function RepeatArray(arr, elementRepeatTimes, totalRepeatTimes) {
arr = RepeatElement(arr, elementRepeatTimes);
arr = RepeatTotal(arr, totalRepeatTimes);
return arr;
}
function RepeatElement(arr, elementRepeatTimes) {
var newArr = [];
arr.forEach(element => {
for (var i = 0; i < elementRepeatTimes; i++) {
newArr.push(element)
}
})
return newArr;
}
function RepeatTotal(arr, totalRepeatTimes) {
var newArr = [];
for (var i = 0; i < totalRepeatTimes; i++) {
newArr = newArr.concat(arr)
}
return newArr;
}
function Join(arr1, arr2) {
var newArr = [];
arr1.forEach((element, index) => {
newArr.push(arr1[index].toString() + arr2[index].toString())
})
return newArr;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>

How to get the last N objects before a certain object in a Javascript array?

I'm trying to implement the endless loading of items in Javascript. Like the effect you get when you scroll through your messages in your favorite messaging application. I have a big array like this (+1000 objects):
var array = [
{ id : 1, text: "First"},
{ id : 2, text: "Second"},
{ id : 3, text: "Third"},
{ id : 4, text: "Forth"},
{ id : 5, text: "Fifth"},
{ id : 6, text: "Sixth"},
{ id : 7, text: "Seventh"},
...
];
Now I want to load only 10 items at a time. For example I'm showing only the items with the id of 30 to 39. Now the user wants to see the items before 30. What is the best way to select last 10 items before that object with the id of 30? As mentioned before, the array's size is big so performance does matter here.
EDIT
The example above is just one case. I should be able to filter my array 10 items at a time as many times as needed.
What I'm trying to achieve is loading a big array but not all at once. I want to load 10 items at a time. I'm keeping track of the first object in my filtered array (e.g 30) and then I want to get the last 10 objects before that particular object.
EDIT 2
This is my View:
<div ng-repeat="message in messages" class="message-wrapper">
// Show content of message
</div>
Now initially i'm showing the last 10 items in messages
$scope.init = function(){
var messages = Database.AllMessages(); // This function returns all my messages
$scope.messages = messages.length > 10 ? messages.slice(-10) : messages;
}
Now let's say the items returned by this function are the items with the Id of 30 to 39. The user scrolls up and wants to see the messages prior to 30. So how can i filter the whole array returned by AllMessages() to get 10 last items before the 30 message?
Thanks in advance for any insights.
You want to query your data source as efficient as possible. Make sure the array is sorted by id first:
array.sort(function(a, b) {
if (a.id === b.id) return 0;
if (a.id > b.id) return 1;
return -1;
});
Then, binary search can be performed to find the index of the element you're looking for:
var search = function(arr, val) {
if (arr.length === 0) {
return -1;
}
var max = arr.length - 1, min = 0;
while (max !== min) {
var index = Math.floor((max + min) / 2);
if (arr[index].id === val) {
return index;
}
else if (arr[index].id < val) {
min = index;
}
else {
max = index;
}
}
return arr[index].id === val ? index : -1;
}
// find index of element with desired id.
var index = search(array, 30);
Once we know the index, we simply have to select the elements before/after the index:
var rangeMin = index - 10; // Inclusive. 10 is the maximum number of elements you want to render.
var rangeMax = index; // Not inclusive.
if (rangeMin < 0) { rangeMin = 0; }
if (rangeMax > array.length) { rangeMax = array.length; }
var elementsToRender = array.slice(rangeMin, rangeMax);
elementsToRender will now contain all the elements you want to render.
Now let's say the items returned by this function are the items with the Id of 30 to 39. The user scrolls up and wants to see the messages prior to 30. So how can i filter the whole array returned by AllMessages() to get 10 last items before the 30 message?
(...) my view should show the items 20 to 39
Suppose allMessages contains all messages (very large array).
Suppose ctrl is a controller instance
Suppose ctrl.messages contains the items currently displayed.
Suppose currentIndex is 30
Suppose stepSize is 10
Then the following code will extend messages to contain items 20 to 39 and will set currentIndex to 20:
currentIndex -= stepSize; // the new first message will have index 20
var extraItems = allMessages.slice(currentIndex, currentIndex+stepSize);
Array.prototype.push.apply(extraItems, ctrl.messages); // append ctrl.messages to extraItems
ctrl.messages = extraItems;
For more information about Array.prototype.push.apply, see Mozilla (scroll down to 'Merging two arrays').
Here is small app to demonstrate it (you'll have to add logic to protect the user to cross the array boundaries):
<html>
<head>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.2/angular.min.js"></script>
<script>
var myApp = angular.module('myApp', []);
myApp.controller('MyController', function() {
var ctrl = this;
var allMessages = Database.AllMessages();
var stepSize = 10;
var currentIndex = allMessages.length - stepSize;
// show the last 10 messages
ctrl.messages = allMessages.length > 10 ? allMessages.slice(-10) : allMessages;
// show ten more messages
ctrl.showMore = function () {
currentIndex -= stepSize;
var extraItems = allMessages.slice(currentIndex, currentIndex+stepSize);
Array.prototype.push.apply(extraItems, ctrl.messages);
ctrl.messages = extraItems;
};
});
</script>
</head>
<body ng-app="myApp">
<div ng-controller="MyController as ctrl">
<table>
<tr ng-repeat="message in ctrl.messages"><td>{{message.text}}</td></tr>
</table>
<button ng-click="ctrl.showMore();">show more</button>
</div>
</body>
</html>
You can try this to get the object with id 30 without a loop using the following code:
var array = [
{ id : 1, text: "First"},
{ id : 2, text: "Second"},
{ id : 3, text: "Third"},
{ id : 4, text: "Forth"},
{ id : 5, text: "Fifth"},
{ id : 6, text: "Sixth"},
{ id : 7, text: "Seventh"}
];
var result = $.grep(array, function(e){ return e.id == 5; });
console.log(result);
What is the best way to select last 10 items before that object with the id of 30?
var index = 30;
var count = 10;
// 10 items before 30 :
array.slice(index-count, index);
I knew this thing I made could be helpful to somebody. Here's the relevant piece:
$('button.getResult').on('click', function(e) {
e.preventDefault();
var limit = $('input.getResult').val();
if (limit != '' && !isNaN(limit)) {
var dots = $('ul li');
if (dots.length > limit) {
//show the limit as group
var foundSelected = false;
var counter = 0;
for (var i = dots.length - 1; i >= 0; i--) {
dots.eq(i).addClass('group');
dots.eq(i + parseInt(limit)).removeClass('group');
counter++;
if (i == $('li.selected').index()) {
foundSelected = true;
};
if (foundSelected && counter >= limit) {
i = -1;
};
};
} else {
//show all as group
dots.addClass('group');
};
};
return false;
});
dots is basically your array and the first conditional is just checking to make sure the number of results you want is smaller than the length of the array. Then a loop is performed through the array (backwards in my case) checking for the important item. If I find it, I change the boolean to true.
Additionally, I mark each as selected as I iterate and if the selected index is outside of the limit of pagination, then I remove the selected mark (to keep the pagination). Once I've both found the important item and have marked the correct number of items past the important one, I stop the loop.
Of course, you might not be able to mark things in your case but I figure you could look at this for some inspiration.

Small Straight (Yahtzee) Algorithm

I have created a working javascript function to check an array of 5 numbers for a small straight, in a Yahtzee game I'm making. I've tested it to no end and I'm confident it works 100% of the time, but it is also probably the worst algorithm of all time in terms of being efficient. Here is what it looks like:
function calcSmstraight() {
var sum = 0;
var r = new Array();
var r2 = new Array();
var counter = 0;
var temp;
var bool = false;
var bool2 = false;
r[0] = document.getElementById('setKeep1').value;
r[1] = document.getElementById('setKeep2').value;
r[2] = document.getElementById('setKeep3').value;
r[3] = document.getElementById('setKeep4').value;
r[4] = document.getElementById('setKeep5').value;
// Move non-duplicates to new array
r2[0] = r[0];
for(var i=0; i<r.length; i++) {
for(var j=0; j<r2.length; j++) {
if(r[i] == r2[j]) {
bool2 = true; // Already in new list
}
}
// Add to new list if not already in it
if(!bool2) {
r2.push(r[i]);
}
bool2 = false;
}
// Make sure list has at least 4 different numbers
if(r2.length >= 4) {
// Sort dice from least to greatest
while(counter < r2.length) {
if(r2[counter] > r2[counter+1]) {
temp = r2[counter];
r2[counter] = r2[counter+1];
r2[counter+1] = temp;
counter = 0;
} else {
counter++;
}
}
// Check if the dice are in order
if(((r2[0] == (r2[1]-1)) && (r2[1] == (r2[2]-1)) && (r2[2] == (r2[3]-1)))
|| ((r2[1] == (r2[2]-1)) && (r2[2] == (r2[3]-1)) && (r2[3] == (r2[4]-1)))) {
bool = true;
}
}
if(bool) {
// If small straight give 30 points
sum = 30;
}
return sum;
}
My strategy is to:
1) Remove duplicates by adding numbers to a new array as they occur
2) Make sure the new array is at least 4 in length (4 different numbers)
3) Sort the array from least to greatest
4) Check if the first 4 OR last 4 (if 5 in length) numbers are in order
My question:
Does anyone know a way that I can improve this method? It seems ridiculously terrible to me but I can't think of a better way to do this and it at least works.
Given that you're implementing a Yahtzee game you presumably need to test for other patterns beyond just small straights, so it would be better to create the array of values before calling the function so that you can use them in all tests, rather than getting the values from the DOM elements inside the small straight test.
Anyway, here's the first way that came to my mind to test for a small straight within an array representing the values of five six-sided dice:
// assume r is an array with the values from the dice
r.sort();
if (/1234|2345|3456/.test(r.join("").replace(/(.)\1/,"$1") {
// is a small straight
}
Note that you can sort an array of numbers using this code:
r2.sort(function(a,b){return a-b;});
...but in your case the values in the array are strings because they came from the .value attribute of DOM elements, so a default string sort will work with r2.sort(). Either way you don't need your own sort routine, because JavaScript provides one.
EDIT: If you assume that you can just put the five values as a string as above you can implement tests for all possible combinations as a big if/else like this:
r.sort();
r = r.join("");
if (/(.)\1{4}/.test(r)) {
alert("Five of a Kind");
} else if (/(.)\1{3}/.test(r)) {
alert("Four of a Kind");
} else if (/(.)\1{2}(.)\2|(.)\3(.)\4{2}/.test(r)) {
alert("Full House");
} else if (/(.)\1{2}/.test(r)) {
alert("Three of a Kind");
} else if (/1234|2345|3456/.test( r.replace(/(.)\1/,"$1") ) {
alert("Small Straight");
} // etc.
Demo: http://jsfiddle.net/4Qzfw/
Why don't you just have a six-element array of booleans indicating whether a number is present, then check 1-4, 2-5, and 3-6 for being all true? In pseudocode:
numFlags = array(6);
foreach(dice)
numFlags[die.value-1] = true;
if(numFlags[0] && numFlags[1] && numFlags[2] && numFlags[3]) return true
//Repeat for 1-4 and 2-5
return false
This wouldn't be a useful algorithm if you were using million-sided dice, but for six-siders there are only three possible small straights to check for, so it's simple and straightforward.
I do not play Yahtzee, but I do play cards, and it would appear the algorithm might be similar. This routine, written in ActionScript (my JavaScript is a bit rusty) has been compiled but not tested. It should accept 5 cards for input, and return a message for either straights greater than 3 cards or pairs or higher.
private function checkCards(card1:int,card2:int,card3:int,card4:int,card5:int):String
{
// Assumes that the 5 cards have a value between 0-12 (Ace-King)
//The key to the routine is using the card values as pointers into an array of possible card values.
var aryCardValues:Array = new Array(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
aryCardValues[card1] += 1;
aryCardValues[card1] += 1;
aryCardValues[card1] += 1;
aryCardValues[card1] += 1;
aryCardValues[card1] += 1;
var aryCardNames:Array = new Array("Ace", "2", "3", "4", "5", "6", "7", "8", "9", "10", "Jack", "Queen", "King");
var strOutMessage:String;
var intCardCount:int = 0;
var strSeperator:String;
var strHighCard:String;
for (var i:int = 0;i < aryCardValues.length;i++)
{
//Check for runs of three of a kind or greater.
if (aryCardValues[i] >= 2)
{
strOutMessage = strOutMessage + strSeperator + i + "-" + aryCardNames[i] + "s";
strSeperator = " & ";
}
//Check for values in a straight.
if (aryCardValues[i] > 0)
{
intCardCount++;
if (intCardCount > 3)strHighCard = aryCardNames[i];
}
else
{
if (intCardCount < 3)intCardCount = 0;
}
}
if (intCardCount > 3) strOutMessage = intCardCount + " run " + strHighCard + " High."
return strOutMessage;
}
It may not be as concise as the regular expressions used above, but it might be more readable and easily modified. One change that could be made is to pass in an array of cards rather than discrete variables for each card.

Categories

Resources