# Project scene

Realize the function of a big turntable lottery, and can customize the awards in the background, the probability of winning each award, the number of awards, the maximum number of lottery draws on the day, etc.

# 1. Design ideas

Here is a simple sharing of ideas:

## 1. Probability of winning prizes

The sum of the odds of winning all prizes participating in the lottery is 1

## 2. Rules of the lottery

First of all, it is necessary to clarify how to win the lottery?

[Generally speaking, a random number] is generated , and then the random number is compared with the winning probability of the prize, and if it is less than the winning probability, the prize is won.

However, if the probability of each prize or several prizes is the same, the above method will result in a situation where the same prize is won every time the prize is drawn.

Therefore, we adopt the method of accumulating the probability of winning, as shown in the figure:
lottery rules:

• Get the list of prizes for the game, in ascending order according to the probability of winning (no sorting required)
• The probabilities in the prize list are cumulative probabilities, which need to be accumulated in the order in which they were added to the list
• Generate a 0-1 random number and compare it with the set prize probability cyclically
• If the random number is less than the probability value, the prize will be drawn

## 3. Prize distribution

Each type of prize distribution rules are different. Here, you can use the characteristics of Java polymorphism to create a factory class, and use different implementation classes to implement the winning processing logic of different types of prizes.

Here, because of the microservices to be used, the corresponding service methods are called directly through feign

# Second, the database design

## 1. Turntable game table

Store carousel lottery information

field describe
id(varchar) primary key id
name(varchar) Event name
start_time(datetime) Starting time
end_time(datetime) End Time
description(varchar) describe
day_limit(int) Limit number of times for a single person on the day 0: means no limit
single_limit(int) The total number of times for a single person is limited to 0: means no limit
state(int) Active state, 1 on 2 off

## 2. Prize Table

Store raffle prize information

field describe
id(varchar) primary key id
game_id(varchar) game id
prize_type(int) Prize Type (1 Coupon, 2 Items, 3 Points, 4 Thank You for Participating)
prize_name(varchar) Prize name
prize_id(varchar) prize id
prize_value(int) Prize value (quantity)
ratio(double) odds of winning
current_num(int) current hit
max_num(int) The maximum number of winnings is 0: means no limit

## 3. Lottery record sheet

Store lottery record information

field describe
id(varchar) primary key id
game_id(varchar) game id
user_id(datetime) userid
draw_time(varchar) Draw time
is_hit(int) Whether winning the lottery 0: not winning the lottery 1: winning the lottery
hit_prize(varchar) winning prize
is_send(int) Whether to issue 1 not issued, 2 issued 3 issued failed
send_msg(text) release result

## 1. Provide an interface

(1) Obtain the turntable game
(2) Obtain the remaining times of the user’s lottery record
(3) Participate in the turntable lottery
(4) The lottery record

## 2. Core code

lottery logic code

```// Get the list of prize information
List<Entity> prizeList = service.list();
// The probability in the prize list is the cumulative probability
// It needs to be accumulated in the order of adding to the list, for the convenience of data processing, the winning probability*100
double sum = 0 ;
List<Entity> newList = new ArrayList<>();
for (int i = 0; i < prizeList.size(); i++) {
Entity entity = prizeList.get(i);
Entity newEntity = new Entity();
BeanUtils.copyProperties(entity, newEntity);
sum = sum + (entity.getRatio() * 100 );
newEntity.setRatio(sum);
}

// Generate a random number
Random random = new Random();
Double userSelect = random.nextDouble() * 10000 ;
for (Entity prize : prizeList) {
// If the random number is less than the odds of winning, the prize will be won
if (userSelect < prize.getRatio()) {
// The maximum number of winnings (0: means no Limit the number of times)
int maxNum = prize.getMaxNum();
// Determine the current and maximum winning number of game prizes
if (maxNum != 0 && maxNum <= prize.getCurrentNum()) {
// If it exceeds the maximum winning number, it will not win
break ;
} else {
return prize;
}
}
}
List<Entity> prize = prizeList.stream().filter(item -> item.getPrizeType() == 4).collect(Collectors.toList());
if (prize.size() > 0) {
return prize.get(0);
}
return null;```

Lottery distribution: Call the corresponding service to distribute the prizes according to the type of prizes drawn; (for example, if the coupons are drawn, the service that invokes the coupons will be issued)

```int type = prize.getPrizeType();
try {
switch (type) {
// issue coupon
case  1 :
ApiResult res = couponFeign.sendCouponToUser(userId, prize.getPrizeId(), prize.getPrizeValue());
break ;
// Distributing goods
case  2 :
break ;
// Distributing points
case  3 :
ApiResult res2 = pointFeign.addPointToUser(gameId, userId, prize.getPrizeValue());
break ;
// Thank you for participating in
case  4 :
break ;
default :
break ;
}
} catch (Exception e) {
e.printStackTrace();
}```

```RLock lock = redisson.getLock( "turntable:" + gameId);
try {
// specify the timeout time
if ( lock .tryLock( 10 , TimeUnit.SECONDS)) {