Writing in the front
This month, I took over two major demands, one of which is competition games, and the other is the game of grabbing red envelopes. Both involve a certain amount of interaction between people, and the game is relatively interesting, which can be reflected from the data that users will enjoy it more.
This article starts with the background, design, and implementation of the first requirement. Grabbing red envelopes will be discussed in the next article.
Demand background
For a while, there was a popular little game called Sunshine Pig Farm, where pigs are synthesized and then withdrawn, often advertised on short video platforms. The essence is that the user will raise pigs every day, to a certain level can be withdrawn.
The product thinks that each user interacts with the pig farm independently, and there is no interaction between users. It wants to hold a pig raising contest to improve the interaction between users, and stimulate users to raise pigs through the PvP competition mechanism, so as to improve the data of users to the product, such as UV, DAU and so on…
The final effect is that users will enter the pig farm and start a round of pig raising competition, randomly match several opponents, rank according to the number of pigs raised within a specified period of time, and finally distribute certain rewards according to the rank.
Demand analysis
First, the process of a pig competition is that users go online, and the system automatically matches them with N opponents randomly to form a team. In the valid time of the competition, the number of pigs raised by each player should be recorded, so that users can check the number of opponents in real time and confirm their own ranking. Therefore, a competition mainly includes the inherent information of the competition, the information of the team members, the information of the number of pigs raised by the players and other core information. Of course, there will also be some ancillary information, such as the avatar nicknames of all the opponents, the region level and so on to make the experience more realistic for the user.
So what kind of data do you need to run a race like this?
Inherent information about a race includes a start time and an end time, and there will be one team for each race, one to one, unless the same people play multiple rounds. Each team includes the number of members, the basic information of each member and the core real-time information of how many times pigs are raised. The reward information corresponding to each ranking is also included in the settlement.
Perhaps all of this is fine, but the reader should be as curious about how to match up as I was when I first got the requirements. I can’t help but think about how we match in a game like LOL, where we match equal opponents based on our own win percentage and level, which ensures the game experience and maintains balance. So the pig game is the same, the user’s ability to raise pigs is also divided into three sixty-nine, we need to match the opponent of the corresponding level according to the user’s current level. As for how to determine a user’s current rank, this requires you to set up some rules in advance to categorize the user, which will be embedded in advance before the contest is launched. For example, those who raise pigs 100 times A day are A, and those who raise pigs 100 ~ 200 times A day are B… After this partition, we also need to prepare A reverse index, which is the user (UID) of class A and class B, so that we can first determine which class we are, and then according to the rules of random to fetch the UID from the bucket of other levels, so that the team is successful.
Technology selection
Knowing the process and defining the data structure allows us to make a general technical selection.
First of all, considering that the competition itself is a time-limited game, which is equivalent to a certain amount of expiration, the best way to store data is to use Redis first. And this real-time PvP race, the query and write volume is very large.
Considering that when the settlement has arrived at the settlement time, the user can get it, but the Redis expired, isn’t the data gone? There is no need to worry about this. First, you can set the time limit for the reward and inform the user of the rules. Secondly, we can persist the results in the form of unwarehousing when the competition is settled.
For the matching part mentioned above, it mainly involves some offline data, which is related to the user’s historical behavior, such as the number of times the user raises pigs and their hierarchy. According to current business rules, users’ behaviors in the game will be recorded and stored in MySQL, ES, etc., and even further asynchronously extract data to the big data side. BI students can calculate user behavior offline through big data analysis platform, and reintegrate a data according to business indicators. For example, the business code will record the user’s pig raising behavior to ES every time, and then synchronize it to Hive. BI can directly conduct statistics on the user’s data of the past whole day from the Hive table, and finally divide several levels of ABCD according to the rules, and can also establish reverse index. So, this whole thing forms a closed loop. (Of course, I have a superficial understanding of this circle, and I obviously feel that the part about big data is more general and unprofessional.)
The specific implementation
Given the cost of implementation, the effect of a one-phase implementation is a one-way race, where users are randomly matched against N opponents, but are not their opponents themselves. Think about the difference, right?
If it is bidirectional, then each race is common information to n members, then the relationship between races and teams and members is one-to-one and one-to-many. However, if it is one-way, it can be understood that the competition and members are also one-to-one, because the opponents do not care who regards “me” as the opponent. Only the leading character of the competition can care, and only the list of matched opponents can be recorded when creating the competition. In terms of technical implementation, one-way is also simpler. It only needs to store the competition information and the opponent information in the team in a Redis Key. If it is two-way, it requires that the contest information and the team ID are stored in a key. In fact, the team ID corresponds to the player information of N in a key, so each member needs to keep a corresponding contest information key.
For opponent matching, BI students can store the UIDs of users of each level in Redis in advance, with structures such as A-UIDList, B-UIDList… When matching an opponent, it may be possible for everyone to access the same Redis key, so this can also cause hot key problems. At the same time, the set of UIDs for each level is very large, and we only randomly pick a few of them for each match. This is bound to require us to break up the UID set into multiple buckets, which can solve both hot keys and big keys. For example, the 10W UIDs of grade A are divided into 1000 buckets, and only 100 UIDs can be stored in each bucket.
As for the most core number of pigs how real-time statistics? Since it is a one-way competition, my cycle may be 48h of yesterday and today, and my opponent’s may be 48h of today and tomorrow. Therefore, it is necessary to store the number of pigs raised by users according to the minimum time granularity. The smallest here refers to the maximum granularity to meet the business requirements. For example, the number of times a user raises pigs per hour is recorded under the same Redis key. The key structure can be: prefix+uid+date+hour. In this way, when the information of The Times of raising pigs of all members of each competition is counted, all Redis in accordance with the start time of the competition and the current time can be queried in batches for aggregation. Of course the hourly granularity is small enough, and the day-level granularity is sufficient for our needs.
Other details, such as rewards, users’ nicknames and avatas, can be stored in the appropriate place, and can be saved if there is a ready-made interface call.
A two-way race
If you think about it, what if you want to do it both ways?
First of all, the matching scheme to the opponent remains the same. The main changes are the storage of the contest information and the recording of the number of pigs raised.
Since competition, teams and members can no longer be regarded as a one-to-one relationship, it is necessary to sort out the relationship according to the DB design method. Each team ID is associated with a team ID, each team ID is associated with n UIDs, each UID is associated with a race ID, and the same team’s UID is associated with the same race ID, of course.
From a player’s point of view, you will first store your current race ID in Redis, and then Redis will have a key with the race ID, which contains all the UIDs of the players (simplified team IDs here).
Since the team members share the same race, each person can modify his/her own number of times for each feeding. It is completely possible to record the number of pigs raised in the key information of race ID. Link means that after the user raises a pig, he/she first checks his/her race ID, then checks the race information, and then gives his/her number of times +1. The other members will immediately see the number go up.
Seems easier, right?
The problem is not that, but that there may be concurrency when you create A contest, where A picks B and C, and B picks D and E, which may be at the same time. Therefore, the overall interactive flow of the game needs to be changed. Instead of creating contests by each individual, the system should create and assign competitions uniformly, allowing the system to “serially” create teams, assign people, and resolve concurrency. Come to think of it, why does a match wait a while when we start a game of LOL?
The robot
Pig competition allows parallel ranking, if everyone with a good to discuss the same, do not raise pigs, can take the first, is not very good, not at all volume. So we want to give it a push, better mobilize users’ enthusiasm for raising pigs.
The product says the robot can not be very dull, the number of unchanged, also have to be like a real person, after a while raise a pig, 23333. And the robot also has to have difficulty points, just like the LOL man-machine mode ordinary, ordinary, doomsday, other web game different levels of BOSS.
How do you implement this mock behavior?
First of all, the robot, which simulates the real person, can fully express the real behavior of the “past tense” on the robot. Just as BI counts the number of pig raising and divides it into hours, the business code can aggregate it when calculating the number of pig raising by the robot. In this way of thinking, I believe that the difficulty of the points can be achieved.