Hasen
Hasen

Reputation: 12314

Javascript can this poker straight detection function be optimised?

Looking to optimise my code to get even more speed. Currently the code detects any poker hand and takes ~350ms to do 32000 iterations. The function to detect straights, however seems to be taking the biggest individual chunk of time at about 160ms so looking if any way to optimise it further.

The whole code was originally written in php since that is what I'm most familiar with but despite php 7's speed boost it still seems to be slower than javascript. What I found when translating to javascript though is that many of php's built in functions are not present in javascript which caused unforeseen slowdowns. It is still faster overall than the original php code though but I'm looking to see if it can be optimised more. Perhaps the answer is no, but I thought I'd check anyway.

I have written the functions range and arrays_equal since these are either missing from javascript or don't quite work properly.

function straight(handval) {
  if (arrays_equal(handval.slice(0, 4),[2, 3, 4, 5]) && handval[handval.length-1] == 14) {//if is Ace 2345
    return [4,14];
  }
  else {//if normal straight
    for (let i = handval.length - 5; i >= 0; i--) {
     let subhand = handval.slice(i, i + 5);
     if (arrays_equal(subhand, range(subhand[0], subhand[subhand.length-1]))) {
      return [4,subhand[4]];
     }
   } return [0]
  }
}

function arrays_equal(a,b) { return !!a && !!b && !(a<b || b<a); }

function range(start, end) {
    let arr = [];
    for (let i = start; i <= end; i++) {
        arr.push(i);
    }
    return arr;
}

Handval comes in as a simple array of 5-7 elements of numbers from 2-14 representing the cards So for example it could be [6,8,4,11,13,2] or [8,4,13,8,10].

EDIT: The function is called and sorted at the same time with this code:

straight(handval.slice(0).sort(sortNumber));

function sortNumber(a,b) { return a - b; }

Upvotes: 0

Views: 291

Answers (1)

Jonas Wilms
Jonas Wilms

Reputation: 138267

You could just go from right to left and count the number of sequential numbers:

 function straight(handval) {
   if([2, 3, 4, 5].every((el, i) => handval[i] === el) && handval[handval.length-1] === 14)
     return [4, 14];

   let count = 1;
   for(let i = handval.length - 1; i >= 1; i -= 1) {
     if(handval[i] === handval[i - 1] + 1) {
       count += 1;
       if(count === 5) return [ 4, handval[i + 3] ];
     } else {
       count = 1;
     }
   }

  return [0];
}

That is way faster as it:

1) does not create intermediate arrays on every iteration, which you did with range and slice

2) does not compare arrays as strings, which requires a typecast and a string comparison, which is way slower than comparing two numbers against each other

3) It does not check all 3 ranges on its own (1 - 5, 2 - 6, 3 - 7), but does all that in one run, so it only iterates 5 positions instead of 3 x 5.

Upvotes: 1

Related Questions