I’ve been working so much that I haven’t had time to write until today. But what would be better to output? At this time saw the next table on a machine to write a group of a group of numbers on the paper, there! Why don’t you draw a prize?

Problem analysis

Lucky draw, pay attention to a random, as long as the random lottery to solve the rules no matter what can draw? So we need a function that can generate random numbers. Not only do we want random numbers, but what we want is a function that takes random integers on a closed interval. so

const random = (m, n) = > m + Math.floor(Math.random() * (n - m))
Copy the code

Did not eat the pork to still have seen the pig to run, the number is certainly to draw a little one, so there is no random number can be the same situation! So this is not going to work. Then, the method used for smoking must satisfy three conditions:

  • It has a range. It’s a closed interval
  • The starting value is definitely greater than 1
  • Random numbers must not be repeated

Problem solving

The first thing that comes to mind about random non-repetition is the use of sort to randomly shatter an array. At this time there may be other voices:

Do you want this water? Sort is used to sort things.

I don’t know. Let’s look at MDN.

arr.sort([compareFunction])

  • If compareFunction(a, b) is less than 0, then a is arranged before B;
  • If compareFunction(a, b) is equal to 0, the relative positions of a and b remain the same. Note: The ECMAScript standard does not guarantee this behavior, and not all browsers comply (e.g., Mozilla versions prior to 2003);
  • If compareFunction(a, b) is greater than 0, b will be arranged before A.
  • CompareFunction (a, b) must always return the same comparison for the same input, otherwise the sorted result will be indeterminate.

so

// arr array, num
const random = (arr:number[], num: number) = >
  arr.sort((a)= > Math.random() - 0.5).splice(0, num)

Copy the code

Specific problems will be solved in detail

First of all, we need to check the industry through Baidu famous raffle typical game rules:

A drawing game is divided into red area and blue area, the red area is composed of 33 numbers from 1-33, and the blue area is composed of 16 numbers from 1-16. You need to select six numbers in the red area and one number in the blue area to form a valid number group.

As a betting dog front end, extract several key points from this passage:

  • Red zones 1 to 33
  • Blue zones 1 to 16
  • Let’s take six red ones and one blue one

Stop it. I have a function in my head again

/ /... random

const dualColor = (a)= > {
  const reds = [1.2.33.]
  const blues = [1.2.16.]

  const red = random(reds, 6)
  const blue = random(blues, 1)

  return [red, blue]
}
Copy the code

At this time we have a look at the method, your method is wrong! Taking red as an example, the result of our function is that the first six numbers are directly scattered, while the rules of the game indicate that the numbers are not only released one by one, but also that the numbers are not stopped in the process of scattering. So this random function obviously doesn’t make sense. What else can we do? Fix it!

// The first and the rest of the number groups are sent out
function random(arr) {
  const newarr = arr.sort((a)= > Math.random() - 0.5)
  const val = newarr.shift()
  return [val, newarr]
}

function dualColor() {
  let redballs = [1.2.33.]
  let blueballs = [1.2.16.]
  let red = [], blue = []

  for (let i = 0; i < 6; i++) {
    const balls = random(redballs)
    red.push(balls[0])
    redballs = balls[1]
  }

  blue.push(random(blueballs)[0])

  return [red, blue]
}
Copy the code

Approach to optimize

Honestly, it’s killing me to write this program…

I don’t think people actually write arrays like that

If I do that in a normal random number way, I do provide a maximum and a minimum and then I’m done. The key is that it’s an array, and there’s no range or anything like that, so nobody actually writes 1 to 33. But we can do a little curve fishing

/ / 0 ~ 9
const arr = [...Array(10).keys()]
Copy the code

So the first point changes the array of two balls

  let reds: number[] = [...Array(33).keys()].map(i= > i+1)
  let blues: number[] = [...Array(16).keys()].map(i= > i+1)
Copy the code

Why +1? The number doesn’t start with zero either!

Maybe we should make random functions purer and more general, right?

We need to make the drawing more flexible, because I want everything that’s drawn. I want the random function to take an array and as many as I want and return the result.

Again, there are cases where we need to loop, so why don’t we use the magic tail recursion?

function randomVal(
  arr: number[],
  total: number,
  temp: number[] = [],
) :number[] {
  const [head, ...body] = arr
    .sort((a)= > Math.random() - 0.5)
  return! total ? temp : randomVal(body, total -1, temp.concat(head));
}
Copy the code

I think it’s too tired to write these two groups

To change! Can change! We can change it to a tuple that holds the start and end values

function dualColor() {
  const reds: [number.number] = [1.33]
  const blues: [number.number] =  [1.16]

  return [randomVal(reds, 6), randomVal(blues, 1)]}Copy the code

I’m going to make a little change to the random function

function randomVal(
  fromto: number[],
  total: number,
  temp: number[] = [],
) :number[] {
  const [head, ...body] = (temp.length
    ? fromto
    : [...Array(fromto[1]).keys()]
        .map(item= > item + 1)
        .splice(fromto[0] - 1)
  ).sort((a)= > Math.random() - 0.5);
  return! total ? temp : randomVal(body, total -1, temp.concat(head))
}
Copy the code

I seem to have missed the rules

In addition, there are three: (1) from the red zone to choose 7- 20, from the blue zone to choose 1. (2) Choose 6 from the red zone and 2–16 from the blue zone. (3) Select 7–20 from the red zone and 2–16 from the blue zone.

Although I don’t understand, but this change is no problem

// I'll arrange all of them for you!
function dualColor(red: number = 6, blue: number = 1) {
  const reds: [number.number] = [1.33]
  const blues: [number.number] =  [1.16]

  return [randomVal(reds, red), randomVal(blues, blue)]
}
Copy the code

So the final solution is

function dualColor(red: number = 6, blue: number = 1) {
  const reds: [number.number] = [1.33]
  const blues: [number.number] = [1.16]

  return [randomBall(reds, red), randomBall(blues, blue)]
}

function randomBall(
  fromto: number[],
  total: number,
  temp: number[] = [],
) :number[] {
  const [head, ...body] = (temp.length
    ? fromto
    : [...Array(fromto[1]).keys()]
        .splice(fromto[0] - 1)
        .map(item= > item + 1)
  ).sort((a)= > Math.random() - 0.5);
  return! total ? temp : randomBall(body, total -1, temp.concat(head))
}
Copy the code

Pleasing to the eye?