I wonder how many people were tricked into getting in by this header 🙂

Last week, some students asked xiaobian. Looking at the sample code of Xiaobian, I felt that I could write it. If I didn’t look at it, I might write it.

In fact, this is very normal, at the beginning of learning to write code, are to follow the routine of others to write down, see the routine is not enough, it is difficult to form their own routine, this is the same as doing math problems, do a problem like all the questions, this possibility is very small, through a lot of practice to explore their own routine.

Just about the New Year, each company will engage in some lottery activities, xiaobian today to talk about, if you want to write a simple lottery program, xiaobian is how to write.

Analyze requirements

Let’s get our heads together. What’s the goal?

The goal is to write a lottery program, so what is the core of the lottery program?

Of course, how to tell if someone has won. So how do you tell if someone wins?

Is it possible to operate by random functions?

The winning ways

Step by step, let’s start with a random function to determine whether we win or not. Could the code be written as follows:

Def lottery(): flag = random.randint(0, 9) if flag < 2: return True else: return FalseCopy the code

First, we get a random positive integer between 0 and 9 (whether random is really random or not is not discussed here, we can consider it random in a narrow sense). If the winning rate is 20%, we can consider the numbers less than 2 as winning, and the rest as not winning. Then return True if you win, False if you don’t.

Let’s add an entry test function to see if the above code works and if the winning rate is maintained at around 20%.

If __name__ == '__main__': # lottery a = 0 # lottery b = 0 for I in range(1000000) : if (lottery()): a += 1 else: B += 1 print(', a, ', b)Copy the code

Execution Result:

Total winning: 200145, not winning: 799,855Copy the code

The above test was looped 1 million times and took about 2-3 seconds to execute, which is pretty fast. As you can see, the winning result is really close to 20% or so.

Dynamic winning rate

Does it end there? Of course not. This is just the beginning.

If at this time the boss said, you this probability can not be adjusted ah, need to let the winning rate can be adjusted dynamically, the activity at the beginning of the winning rate to be high, as time goes by, the winning rate to come down.

What do you do now? You’re dumbstruck.

Since the winning rate is to be adjustable, we can’t fix the winning rate in the program. The winning rate needs to have a place to store it and pull it out every time we do randomization.

An easy way to do this is to put the winning rate in a database or cache service, depending on the actual business scenario. Generally, the technology selection is based on the estimated size of the access pressure. If the pressure is not too great, it is ok to put it in the database. If the concurrency is high, it is recommended to put it in the cache.

Mysql > select * from Mysql; select * from Mysql; select * from Mysql;

Very simple design of a table, there are two meaningful fields, one used as the numerator of the winning rate, one used as the denominator of the winning rate. The denominator is best set to 100, 1000, 10000, this calculation of the winning rate will be better calculation.

def get_lottery_rate(): conn = pymysql.connect(host='localhost', user='root', password='password', database='test', charset='utf8mb4') try: sql = 'SELECT fenzi, fenmu FROM rate' cursor = conn.cursor() cursor.execute(sql) result = cursor.fetchone() return result except Exception as  ex: print(ex) finally: conn.close()Copy the code

Running this method results in the following:

(10, 100)Copy the code

As you can see, we’ve got a tuple of the numerator and denominator that we pulled out of the database.

Let’s change the method of the previous lottery to get the winning percentage from the database. The modified code is as follows:

def lottery():
    rate = get_lottery_rate()
    flag = random.randint(1, rate[1])
    if flag < rate[0]:
        return True
    else:
        return FalseCopy the code

Run the above test method again, pay attention to here, because we are getting data from the database, each method execution will be added to the establishment and destruction of database links, it is recommended to change the number of cycles to less than 1000, otherwise the execution time will be a little too long.

After changing the number of cycles to 1000, the result is as follows:

Total wins: 92, no wins: 908Copy the code

So at this point, we can modify the data in the database in real time operation of the winning rate. Of course, the above slow problem we can use database connection pool technology to optimize.

Increase the award

Is that the end? No, no, no. Let’s add demand.

Now, we can only know every time in the end not to win the prize, only a prize, but now want to become 3 awards, such as: first prize, second prize, third prize how to do?

This is a bit of a big change to the previous lucky draw method. First, we will add the configuration of the other two prizes in the database:

The denominators of the three awards had better be the same, otherwise the subsequent calculation will increase the complexity.

Modify the method we used to get the configuration:

def get_lottery_rate(): conn = pymysql.connect(host='localhost', port = 3306, user='root', password='password', database='test', charset='utf8mb4') try: sql = 'SELECT * FROM rate order by id asc ' cursor = conn.cursor() cursor.execute(sql) result = cursor.fetchall() return  result except Exception as ex: print(ex) finally: conn.close()Copy the code

The result of the test call is as follows:

(1, 10, 100), (2, 5, 100), (3, 1, 100)Copy the code

First, what we need to do is to incorporate this configuration into our previous winning method, without further ado, directly into the code:

Def lottery(): config = get_lottery_rate() flag = random.randint(1, config[0][2]) if flag <= config[0][1]: return 1 elif flag > config[0][1] and flag <= (config[1][1] + config[0][1]): return 2 elif flag > (config[1][1] + config[0][1]) and flag <= (config[2][1] + config[1][1]): return 3 else: return 0Copy the code

Then modify our test code:

Def main(): a = 0 b = 0 c = 0 d = 0 e = 0 for I in range(1000): If (result == 1): a += 1 elif (result == 2): a += 1 elif (result == 2): a += 1 elif (result == 2): Elif (result == 3): c += 1 else: d += 1 print(' a ', 'b ',' c ', 'd')Copy the code

Call our test method:

if __name__ == '__main__':
    main()Copy the code

The result is as follows:

Add membership judgment

Now most of the websites are membership system, such as silver member, gold member, diamond member. If different member levels need different winning rates, this is a very normal thing. Xiaobian now clearly remember that a large Internet company code in the annotation “poor forced VIP (the kind of activity sent)”.

We assume that the diamond member’s winning rate is 100% of the overall winning rate, the gold member’s winning rate is 50% of the overall winning rate and the silver member’s winning rate is 20% of the overall winning rate.

The simplest way to achieve this is to directly set the judgment of the winning rate of members in the outermost layer. I don’t know what you think.

Small make up here to give their own solutions:

1. Silver Member 2. Def vip_lottery(level): rate = random. Randint (1, 10) # if level == 3: Elif level == 2: if rate <= 5: Return Lottery () else: Elif level == 1: if rate <= 2: return lottery() else: return 0 # return 0Copy the code

We added a new test to add member filtering test method:

Def test_VIP (): print(' please enter your current membership level: 1. Lottery (int(level)) if (result == 1): Elif (result == 2): print(result == 3): print(result == 3) else: print(result == 3): print(result == 2)Copy the code

Call this method in our entry function:

if __name__ == '__main__':
    test_vip()Copy the code

The final test results are as follows:

Xiaobian character is ok, can directly in the third prize.

So, here, is not a simple lottery program even if completed? In fact, it can be added, if each award has a number of limits, and the number of limits can be adjusted at any time, etc., I will not list them here.

The overall code is a little long, small make up will not be posted, uploaded to the code warehouse interested students to visit it.

Note: The code used in this article is for demonstration purposes only, not for production use, and can cause serious performance problems in the event of heavy traffic.

The sample code

Example code -Github

Example code -Gitee