Patrick
Patrick

Reputation: 5592

Javascript regular expressions problem

I am creating a small Yahtzee game and i have run into some regex problems. I need to verify certain criteria to see if they are met. The fields one to six is very straight forward the problem comes after that. Like trying to create a regex that matches the ladder. The Straight should contain one of the following characters 1-5. It must contain one of each to pass but i can't figure out how to check for it. I was thinking /1{1}2{1}3{1}4{1}5{1}/g; but that only matches if they come in order. How can i check if they don't come in the correct order?

Upvotes: 0

Views: 367

Answers (6)

Henrik N
Henrik N

Reputation: 16294

A regexp is likely not the best solution for this problem, but for fun:

/^(?=.*1)(?=.*2)(?=.*3)(?=.*4)(?=.*5).{5}$/.test("12354")

That matches every string that contains exactly five characters, being the numbers 1-5, with one of each.

(?=.*1) is a positive lookahead, essentially saying "to the very right of here, there should be whatever or nothing followed by 1".

Lookaheads don't "consume" any part of the regexp, so each number check starts off the beginning of the string.

Then there's .{5} to actually consume the five characters, to make sure there's the right number of them.

Upvotes: 1

user187291
user187291

Reputation: 53960

Although this definitely can be solved with regular expressions, I find it quite interesting and educative to provide a "pure" solution, based on simple arithmetic. It goes like this:

function yahtzee(comb) {

    if(comb.length != 5) return null;

    var map = [0, 0, 0, 0, 0, 0];
    for(var i = 0; i < comb.length; i++) {
        var digit = comb.charCodeAt(i) - 48;
        if(digit < 1 || digit > 6) return null;
        map[digit - 1]++;
    }

    var sum = 0, p = 0, seq = 0;
    for(var i = 0; i < map.length; i++) {
        if(map[i] == 2) sum += 20;
        if(map[i] >= 3) sum += map[i];

        p = map[i] ? p + 1 : 0;
        if(p > seq) seq = p;
    }

    if(sum == 5)  return "Yahtzee";
    if(sum == 23) return "Full House";
    if(sum == 3)  return "Three-Of-A-Kind";
    if(sum == 4)  return "Four-Of-A-Kind";

    if(seq == 5) return "Large Straight";
    if(seq == 4) return "Small Straight";

    return "Chance";
}

for reference, Yahtzee rules

Upvotes: 2

kennytm
kennytm

Reputation: 523774

With regex:

return /^([1-5])(?!\1)([1-5])(?!\1|\2)([1-5])(?!\1|\2|\3)([1-5])(?!\1|\2|\3|\4)[1-5]$/.test("15243");

(Not that it's recommended...)

Upvotes: 1

F&#225;bio Batista
F&#225;bio Batista

Reputation: 25290

"12543".split('').sort().join('') == '12345'

Upvotes: 1

TomR
TomR

Reputation: 31

For simplicity and easiness, I'd go with indexOf.

string.indexOf(searchstring, start)

Loop 1 to 5 like Max but just check indexOf i, break out for any false.

This also will help for the small straight, which is only 4 out of 5 in order(12345 or 23456). Edit: Woops. 1234, 2345, 3456. Sorry.

You could even have a generic function to check for straights of an arbitrary length, passing in the maximum loop index as well as the string to check.

Upvotes: 1

Max Shawabkeh
Max Shawabkeh

Reputation: 38683

If I understood you right, you want to check if a string contains the numbers from 1 to 5 in random order. If that is correct, then you can use:

var s = '25143';
var valid = s.match(/^[1-5]{5}$/);
for (var i=1; i<=5; i++) {
  if (!s.match(i.toString())) valid = false;
}

Or:

var s = '25143';
var valid = s.split('').sort().join('').match(/^12345$/);

Upvotes: 3

Related Questions