Last time, I created a step-up gacha. This time, we will add control processing to the step-up gacha and modify it so that it can be used more practically.
** The following sources have been modified and implemented **
Gacha written in python-Practice 2 / Basics of step-up gacha-
As this renovation, the following control processing will be added to the step-up gacha.
--Repeat
Last time The step-up gacha I made was designed to end when it progressed to the final step.
In the actual game, there is a gacha that allows you to draw the last step repeatedly after the last step.
To achieve that, we need to add control for repetition
.
This time, let's think about how to make the following three types of step-up gacha.
--step_up_N: Basic step-up (finished at the final step) --step_up_S1: Repeat step-up (return to step 1 after the final step) --step_up_S2: Step-up final repeat (repeat the final step forever)
To define ** repeating steps ** for gacha drawing settings (gacha_lottery) Create a table called Gacha Type Setting (gacha_type).
gacha_type
id | kind | rotation_step_no |
---|---|---|
step_up_N | step_up | 0 |
step_up_S1 | step_up | 1 |
step_up_S2 | step_up | 4 |
The rotation_step_no
item indicates the step to transition to after the final step.
In the case of 0
, it is defined as ending at the final step.
Replace the item gacha_type
in the gacha drawing setting (gacha_lottery) with thegacha type setting ID (gacha_type_id)
set above.
gacha_lottery
id | gacha_type_id | step_no | item_type | times | rarity | omake_times | omake_rarity | cost |
---|---|---|---|---|---|---|---|---|
step_up_N_1 | step_up_N | 1 | 0 | 1 | 0 | 0 | 0 | 10 |
step_up_N_2 | step_up_N | 2 | 0 | 2 | 0 | 1 | 3 | 30 |
step_up_N_3 | step_up_N | 3 | 0 | 3 | 0 | 2 | 3 | 50 |
step_up_N_4 | step_up_N | 4 | 0 | 4 | 0 | 1 | 4 | 50 |
step_up_S1_1 | step_up_S1 | 1 | 0 | 1 | 0 | 0 | 0 | 10 |
step_up_S1_2 | step_up_S1 | 2 | 0 | 2 | 0 | 1 | 3 | 30 |
step_up_S1_3 | step_up_S1 | 3 | 0 | 1 | 0 | 2 | 3 | 30 |
step_up_S1_4 | step_up_S1 | 4 | 0 | 4 | 0 | 1 | 4 | 50 |
step_up_S2_1 | step_up_S2 | 1 | 0 | 1 | 0 | 0 | 0 | 10 |
step_up_S2_2 | step_up_S2 | 2 | 0 | 2 | 0 | 1 | 3 | 30 |
step_up_S2_3 | step_up_S2 | 3 | 0 | 4 | 0 | 1 | 5 | 50 |
step_up_S2_4 | step_up_S2 | 4 | 0 | 4 | 0 | 1 | 3 | 50 |
Similarly, replace the item gacha_type
in the gacha period setting (gacha) with thegacha type setting ID (gacha_type_id)
so that the gacha drawing method setting (gacha_lottery) and the gacha type setting (gacha_type) are linked. I will.
gacha
id | start_time | end_time | gacha_group | gacha_type_id |
---|---|---|---|---|
10 | 2020-05-01 00:00:00 | 2020-05-31 23:59:59 | A | step_up_N |
11 | 2020-06-01 00:00:00 | 2020-06-30 23:59:59 | C | step_up_N |
12 | 2020-05-01 00:00:00 | 2020-07-31 23:59:59 | A | step_up_S1 |
13 | 2020-05-01 00:00:00 | 2020-05-31 23:59:59 | A | step_up_S2 |
14 | 2020-06-01 00:00:00 | 2020-06-30 23:59:59 | C | step_up_S2 |
Depending on the operation, you may want to return to the initial state at a certain timing. Therefore, add the reset definition to the gacha type setting (gacha_type).
Depending on the reset definition added this time, it will be set to be automatically reset depending on the period.
reset_type There are two * reset_type * to define.
--daily: Return to the initial state (step 1) at the first access every day --monthly: Return to the initial state (step 1) at the first access every month
For monthly, it's not very practical, but it's set up to understand the difference
gacha_type
id | kind | rotation_step_no | reset_type |
---|---|---|---|
step_up_N | step_up | 0 | daily |
step_up_S1 | step_up | 1 | monthly |
step_up_S2 | step_up | 4 |
This time, set gacha_type according to the gacha period setting (gacha). ** step_up_S2 ** has no reset setting because reset_type is empty.
The implementation specifications are summarized below.
-** When 0
is set in rotation_step_no **
--Increment (+1) the ** step_no ** of the user gacha step information and update (Gacha end state)
-** When rotation_step_no ** is set to something other than 0
--Update ** step_no ** of user gacha step information with ** rotation_step_no **
-** When daily
is set in reset_type **
--If ** updated_time ** of user gacha step information is the date of the previous day, update with step_no = 1
-** When monthly
is set in reset_type **
--If ** updated_time ** of user gacha step information is the date of the previous month, update with step_no = 1
If you want to change the structure / data or reset the history, please re-execute this process.
gacha_db.py
# -*- coding: utf-8 -*-
import sqlite3
import random
def get_items():
items = {
5101: {"rarity": 5, "item_name": "UR_Brave", "item_type": 1, "hp": 1200},
4201: {"rarity": 4, "item_name": "SSR_Warrior", "item_type": 2, "hp": 1000},
4301: {"rarity": 4, "item_name": "SSR_Wizard", "item_type": 3, "hp": 800},
4401: {"rarity": 4, "item_name": "SSR_Priest", "item_type": 4, "hp": 800},
3201: {"rarity": 3, "item_name": "SR_Warrior", "item_type": 2, "hp": 600},
3301: {"rarity": 3, "item_name": "SR_Wizard", "item_type": 3, "hp": 500},
3401: {"rarity": 3, "item_name": "SR_Priest", "item_type": 4, "hp": 500},
2201: {"rarity": 2, "item_name": "R_Warrior", "item_type": 2, "hp": 400},
2301: {"rarity": 2, "item_name": "R_Wizard", "item_type": 3, "hp": 300},
2401: {"rarity": 2, "item_name": "R_Priest", "item_type": 4, "hp": 300},
3199: {"rarity": 3, "item_name": "SR_Brave", "item_type": 1, "hp": 600},
4101: {"rarity": 4, "item_name": "SSR_Brave", "item_type": 1, "hp": 1000},
5201: {"rarity": 5, "item_name": "UR_Warrior", "item_type": 2, "hp": 1300},
5301: {"rarity": 5, "item_name": "UR_Wizard", "item_type": 3, "hp": 1000},
}
return convert_values(items)
def get_gacha_items():
items = {
1: {"gacha_group": "A", "weight": 3, "item_id": 5101},
2: {"gacha_group": "A", "weight": 9, "item_id": 4201},
3: {"gacha_group": "A", "weight": 9, "item_id": 4301},
4: {"gacha_group": "A", "weight": 9, "item_id": 4401},
5: {"gacha_group": "A", "weight": 20, "item_id": 3201},
6: {"gacha_group": "A", "weight": 20, "item_id": 3301},
7: {"gacha_group": "A", "weight": 20, "item_id": 3401},
8: {"gacha_group": "A", "weight": 40, "item_id": 2201},
9: {"gacha_group": "A", "weight": 40, "item_id": 2301},
10: {"gacha_group": "A", "weight": 40, "item_id": 2401},
11: {"gacha_group": "B", "weight": 15, "item_id": 4201},
12: {"gacha_group": "B", "weight": 30, "item_id": 3201},
13: {"gacha_group": "B", "weight": 55, "item_id": 2201},
14: {"gacha_group": "C", "weight": 1, "item_id": 5101},
15: {"gacha_group": "C", "weight": 1, "item_id": 5201},
16: {"gacha_group": "C", "weight": 1, "item_id": 5301},
17: {"gacha_group": "C", "weight": 9, "item_id": 4101},
18: {"gacha_group": "C", "weight": 6, "item_id": 4201},
19: {"gacha_group": "C", "weight": 6, "item_id": 4301},
20: {"gacha_group": "C", "weight": 6, "item_id": 4401},
21: {"gacha_group": "C", "weight": 20, "item_id": 3201},
22: {"gacha_group": "C", "weight": 20, "item_id": 3301},
23: {"gacha_group": "C", "weight": 20, "item_id": 3401},
24: {"gacha_group": "C", "weight": 40, "item_id": 2201},
25: {"gacha_group": "C", "weight": 40, "item_id": 2301},
26: {"gacha_group": "C", "weight": 40, "item_id": 2401},
}
return convert_values(items)
def get_gacha():
items = {
10: {"start_time": "2020-05-01 00:00:00", "end_time": "2020-05-31 23:59:59", "gacha_group": "A",
"gacha_type_id": "step_up_N"},
11: {"start_time": "2020-06-01 00:00:00", "end_time": "2020-06-30 23:59:59", "gacha_group": "C",
"gacha_type_id": "step_up_N"},
12: {"start_time": "2020-05-01 00:00:00", "end_time": "2020-07-31 23:59:59", "gacha_group": "A",
"gacha_type_id": "step_up_S1"},
13: {"start_time": "2020-05-01 00:00:00", "end_time": "2020-05-31 23:59:59", "gacha_group": "A",
"gacha_type_id": "step_up_S2"},
14: {"start_time": "2020-06-01 00:00:00", "end_time": "2020-06-30 23:59:59", "gacha_group": "C",
"gacha_type_id": "step_up_S2"},
}
return convert_values(items)
def get_gacha_type():
items = {
"step_up_N": {"rotation_step_no": 0, "kind": "step_up", "reset_type": "daily"},
"step_up_S1": {"rotation_step_no": 1, "kind": "step_up", "reset_type": "monthly"},
"step_up_S2": {"rotation_step_no": 4, "kind": "step_up", "reset_type": None},
}
return convert_values(items)
def get_gacha_lottery():
items = {
"normal_1": {"gacha_type_id": "normal", "step_no": 0, "item_type": 0, "times": 1, "rarity": 0, "omake_times": 0, "omake_rarity": 0, "cost":10},
"normal_11": {"gacha_type_id": "normal", "step_no": 0, "item_type": 0, "times": 10, "rarity": 0, "omake_times": 1, "omake_rarity": 3, "cost":100},
"fighter": {"gacha_type_id": "fighter", "step_no": 0, "item_type": 0, "times": 2, "rarity": 0, "omake_times": 0, "omake_rarity": 0, "cost":30},
"omake_2": {"gacha_type_id": "omake_2", "step_no": 0, "item_type": 0, "times": 9, "rarity": 2, "omake_times": 2, "omake_rarity": 3, "cost":150},
"omake_fighter": {"gacha_type_id": "omake_fighter", "step_no": 0, "item_type": 2, "times": 5, "rarity": 0, "omake_times": 1, "omake_rarity": 3, "cost":100},
"step_up_N_1": {"gacha_type_id": "step_up_N", "step_no": 1, "item_type": 0, "times": 1, "rarity": 0, "omake_times": 0,
"omake_rarity": 0, "cost": 10},
"step_up_N_2": {"gacha_type_id": "step_up_N", "step_no": 2, "item_type": 0, "times": 2, "rarity": 0, "omake_times": 1,
"omake_rarity": 3, "cost": 30},
"step_up_N_3": {"gacha_type_id": "step_up_N", "step_no": 3, "item_type": 0, "times": 3, "rarity": 0, "omake_times": 2,
"omake_rarity": 3, "cost": 50},
"step_up_N_4": {"gacha_type_id": "step_up_N", "step_no": 4, "item_type": 0, "times": 4, "rarity": 0, "omake_times": 1,
"omake_rarity": 4, "cost": 50},
"step_up_S1_1": {"gacha_type_id": "step_up_S1", "step_no": 1, "item_type": 0, "times": 1, "rarity": 0,
"omake_times": 0, "omake_rarity": 0, "cost": 10},
"step_up_S1_2": {"gacha_type_id": "step_up_S1", "step_no": 2, "item_type": 0, "times": 2, "rarity": 0,
"omake_times": 1, "omake_rarity": 3, "cost": 30},
"step_up_S1_3": {"gacha_type_id": "step_up_S1", "step_no": 3, "item_type": 0, "times": 1, "rarity": 0,
"omake_times": 2, "omake_rarity": 3, "cost": 30},
"step_up_S1_4": {"gacha_type_id": "step_up_S1", "step_no": 4, "item_type": 0, "times": 3, "rarity": 0,
"omake_times": 2, "omake_rarity": 4, "cost": 50},
"step_up_S2_1": {"gacha_type_id": "step_up_S2", "step_no": 1, "item_type": 0, "times": 1, "rarity": 0,
"omake_times": 0, "omake_rarity": 0, "cost": 10},
"step_up_S2_2": {"gacha_type_id": "step_up_S2", "step_no": 2, "item_type": 0, "times": 2, "rarity": 0,
"omake_times": 1, "omake_rarity": 3, "cost": 30},
"step_up_S2_3": {"gacha_type_id": "step_up_S2", "step_no": 3, "item_type": 0, "times": 4, "rarity": 0,
"omake_times": 1, "omake_rarity": 5, "cost": 50},
"step_up_S2_4": {"gacha_type_id": "step_up_S2", "step_no": 4, "item_type": 0, "times": 4, "rarity": 0,
"omake_times": 1, "omake_rarity": 3, "cost": 50},
}
return convert_values(items)
def get_users():
items = {
"u001": {"nick_name": "taro"},
"u002": {"nick_name": "hana"},
}
return convert_values(items)
def convert_values(items: dict):
values = []
keys = []
for id,info in items.items():
if len(keys) == 0 :
keys = list(info.keys())
keys.insert(0,'id')
value = list(info.values())
value.insert(0,id)
values.append(tuple(value))
return keys,values
def print_rows(rows, keys: list):
for row in rows:
result = []
for key in keys:
result.append(str(row[key]))
print(",".join(result))
def main():
con = sqlite3.connect("data.db")
con.row_factory = sqlite3.Row
cursor = con.cursor()
cursor.execute("DROP TABLE IF EXISTS gacha")
#Refurbishment
cursor.execute(
"""CREATE TABLE gacha
(id INTEGER PRIMARY KEY AUTOINCREMENT
,start_time DATETIME
,end_time DATETIME
,gacha_group VARCHAR(32)
,gacha_type_id VARCHAR(32)
)
"""
)
cursor.execute("DROP TABLE IF EXISTS gacha_items")
cursor.execute(
"""CREATE TABLE gacha_items
(id INTEGER PRIMARY KEY AUTOINCREMENT
,gacha_group VARCHAR(32)
,weight INTEGER
,item_id INTEGER
)
"""
)
#add to
cursor.execute("DROP TABLE IF EXISTS gacha_type")
cursor.execute(
"""CREATE TABLE gacha_type
(id VARCHAR(32) PRIMARY KEY
,kind VARCHAR(32)
,rotation_step_no INTEGER
,reset_type VARCHAR(32)
)
"""
)
#Refurbishment
cursor.execute("DROP TABLE IF EXISTS gacha_lottery")
cursor.execute(
"""CREATE TABLE gacha_lottery
(id VARCHAR(32) PRIMARY KEY
,gacha_type_id VARCHAR(32)
,step_no INTEGER
,item_type INTEGER
,times INTEGER
,rarity INTEGER
,omake_times INTEGER
,omake_rarity INTEGER
,cost INTEGER
)
"""
)
cursor.execute("DROP TABLE IF EXISTS items")
cursor.execute(
"""CREATE TABLE items
(id INTEGER PRIMARY KEY AUTOINCREMENT
,rarity INTEGER
,item_name VARCHAR(64)
,item_type INTEGER
,hp INTEGER
)
"""
)
cursor.execute("DROP TABLE IF EXISTS users")
cursor.execute(
"""CREATE TABLE users
(id VARCHAR(16) PRIMARY KEY
,nick_name VARCHAR(64)
)
"""
)
#Refurbishment
cursor.execute("DROP TABLE IF EXISTS gacha_user_step")
cursor.execute(
"""CREATE TABLE gacha_user_step
(user_id VARCHAR(16)
,gacha_id INTEGER
,gacha_type_id VARCHAR(32)
,step_no INTEGER DEFAULT 2
,updated_time DATETIME
,PRIMARY KEY(user_id,gacha_id,gacha_type_id)
)
"""
)
keys, values = get_items()
sql = "insert into {0}({1}) values({2})".format('items', ','.join(keys), ','.join(['?'] * len(keys)))
cursor.executemany(sql,values)
select_sql = "SELECT * FROM items ORDER BY id"
result = cursor.execute(select_sql)
print("===items===")
print_rows(result, keys)
keys, values = get_gacha_items()
sql = "insert into {0}({1}) values({2})".format('gacha_items', ','.join(keys), ','.join(['?'] * len(keys)))
cursor.executemany(sql,values)
select_sql = "SELECT * FROM gacha_items ORDER BY id"
result = cursor.execute(select_sql)
print("===gacha_items===")
print_rows(result, keys)
keys, values = get_gacha()
sql = "insert into {0}({1}) values({2})".format('gacha', ','.join(keys), ','.join(['?'] * len(keys)))
cursor.executemany(sql,values)
select_sql = "SELECT * FROM gacha ORDER BY id"
result = cursor.execute(select_sql)
print("===gacha===")
print_rows(result, keys)
keys, values = get_gacha_type()
sql = "insert into {0}({1}) values({2})".format('gacha_type', ','.join(keys), ','.join(['?'] * len(keys)))
cursor.executemany(sql,values)
select_sql = "SELECT * FROM gacha_type ORDER BY id"
result = cursor.execute(select_sql)
print("===gach_type===")
print_rows(result, keys)
keys, values = get_gacha_lottery()
sql = "insert into {0}({1}) values({2})".format('gacha_lottery', ','.join(keys), ','.join(['?'] * len(keys)))
cursor.executemany(sql,values)
select_sql = "SELECT * FROM gacha_lottery ORDER BY id"
result = cursor.execute(select_sql)
print("===gacha_lottery===")
print_rows(result, keys)
keys, values = get_users()
sql = "insert into {0}({1}) values({2})".format('users', ','.join(keys), ','.join(['?'] * len(keys)))
cursor.executemany(sql,values)
select_sql = "SELECT * FROM users ORDER BY id"
result = cursor.execute(select_sql)
print("===users===")
print_rows(result, keys)
con.commit()
con.close()
if __name__ == '__main__':
main()
gacha.py
import random
import sqlite3
from datetime import datetime
from typing import Dict, List, Tuple, Optional
def convert_row2dict(row) -> Dict:
if row is None:
return {}
return {key: row[key] for key in row.keys()}
def gacha(lots, times: int=1) -> List:
return random.choices(tuple(lots), weights=lots.values(), k=times)
def get_rarity_name(rarity: int) -> str:
rarity_names = {5: "UR", 4: "SSR", 3: "SR", 2: "R", 1: "N"}
return rarity_names[rarity]
#Executable gacha information list
def get_gacha_list(cursor, now_time: int) -> Dict:
select_sql = "SELECT * FROM gacha ORDER BY id"
rows = cursor.execute(select_sql)
results = {}
for row in rows:
start_time = int(datetime.strptime(row["start_time"], '%Y-%m-%d %H:%M:%S').timestamp())
end_time = int(datetime.strptime(row["end_time"], '%Y-%m-%d %H:%M:%S').timestamp())
#Narrow down the target gacha information within the range of the date and time
if start_time <= now_time <= end_time:
results[row["id"]] = convert_row2dict(row)
return results
#Executable gacha information list (gacha_(Including lottery information)
def get_available_gacha_info_list(cursor, now_time: int, user_id:str) -> Dict:
gacha_list = get_gacha_list(cursor, now_time)
for gacha_id, info in gacha_list.items():
lottery_info_list = get_gacha_lottery_by_type(cursor, info["gacha_type_id"])
gacha_user = get_gacha_user_step(cursor, user_id, gacha_id, info["gacha_type_id"])
set_list = []
for lottery_info in lottery_info_list:
if lottery_info["step_no"] > 0:
now_step_no = 1
if len(gacha_user) > 0:
now_step_no = gacha_user["step_no"] + 1
if now_step_no == lottery_info["step_no"]:
set_list.append(lottery_info)
else:
set_list.append(lottery_info)
gacha_list[gacha_id]["gacha_lottery_list"] = set_list
return gacha_list
def get_gacha(cursor, gacha_id: int, now_time: int) -> Dict:
select_sql = "SELECT * FROM gacha WHERE id = ? ORDER BY id"
cursor.execute(select_sql, (gacha_id,))
row = cursor.fetchone()
start_time = int(datetime.strptime(row["start_time"], '%Y-%m-%d %H:%M:%S').timestamp())
end_time = int(datetime.strptime(row["end_time"], '%Y-%m-%d %H:%M:%S').timestamp())
#Narrow down the target gacha information within the range of the date and time
if start_time <= now_time <= end_time:
return convert_row2dict(row)
return {}
def get_gacha_type(cursor, gacha_type_id: str) -> Dict:
select_sql = "SELECT * FROM gacha_type WHERE id = ? ORDER BY id"
cursor.execute(select_sql, (gacha_type_id,))
return convert_row2dict(cursor.fetchone())
def get_gacha_lottery(cursor, gacha_lottery_id: str) -> Dict:
select_sql = "SELECT * FROM gacha_lottery WHERE id = ? ORDER BY id"
cursor.execute(select_sql, (gacha_lottery_id,))
return convert_row2dict(cursor.fetchone())
def get_gacha_lottery_by_type(cursor, gacha_type_id: str) -> List:
select_sql = "SELECT * FROM gacha_lottery WHERE gacha_type_id = ? ORDER BY id"
rows = cursor.execute(select_sql, (gacha_type_id,))
return [
convert_row2dict(row)
for row in rows
]
def get_items_all(cursor) -> Dict:
select_sql = "SELECT * FROM items ORDER BY id"
rows = cursor.execute(select_sql)
return {
row["id"]: convert_row2dict(row)
for row in rows
}
def get_gacha_items(cursor, gacha_group: str) -> Dict:
select_sql = "SELECT * FROM gacha_items WHERE gacha_group = ? ORDER BY id"
rows = cursor.execute(select_sql, (gacha_group,))
return {
row["id"]: convert_row2dict(row)
for row in rows
}
def get_gacha_items_all(cursor) -> Dict:
select_sql = "SELECT * FROM gacha_items ORDER BY id"
rows = cursor.execute(select_sql)
return {
row["id"]: convert_row2dict(row)
for row in rows
}
def get_gacha_info(cursor, gacha_id: int, gacha_lottery_id: str, now_time: int, user_id: str) -> Tuple[Optional[Dict], Optional[Dict]]:
gacha = get_gacha(cursor, gacha_id, now_time)
gacha_lottery = get_gacha_lottery(cursor, gacha_lottery_id)
if len(gacha) == 0:
print("===Gacha that cannot be executed_id:%s===" % (gacha_id))
return None, None
if len(gacha_lottery) == 0:
print("===Gacha that does not exist_lottery_id:%s===" % (gacha_lottery_id))
return None, None
if gacha["gacha_type_id"] != gacha_lottery["gacha_type_id"]:
print("===gacha_type_id is different:%s,%s===" % (gacha["gacha_type_id"],gacha_lottery["gacha_type_id"]))
return None, None
# step_up Gacha check
if gacha_lottery["step_no"] > 0:
# user_Reset step
reset_gacha_user_step(cursor, user_id, gacha_id, gacha["gacha_type_id"], now_time)
max_step_no = get_max_step_no(cursor, gacha["gacha_type_id"])
gacha_user = get_gacha_user_step(cursor, user_id, gacha_id, gacha["gacha_type_id"])
step_no = 1
if len(gacha_user) > 0:
step_no = gacha_user["step_no"]
if max_step_no < step_no:
print("===Up to the maximum step has been executed (maximum step):%s, the step you are going to perform:%s)===" %(max_step_no,gacha_lottery["step_no"]))
return None, None
if gacha_lottery["step_no"] != step_no:
print("===Different from the steps that can be performed (current step:%s, the step you are going to perform:%s)===" %(step_no, gacha_lottery["step_no"]))
return None, None
return gacha, gacha_lottery
def get_gacha_user_step(cursor, user_id: str, gacha_id: int, gacha_type_id: str) -> Dict:
select_sql = "SELECT * FROM gacha_user_step WHERE user_id = ? AND gacha_id = ? AND gacha_type_id = ?"
cursor.execute(select_sql, (user_id,gacha_id,gacha_type_id))
row = cursor.fetchone()
return convert_row2dict(row)
def get_max_step_no(cursor, gacha_type_id: str) -> Dict:
select_sql = "SELECT MAX(step_no) AS max_step_no FROM gacha_lottery WHERE gacha_type_id = ?"
cursor.execute(select_sql, (gacha_type_id,))
row = cursor.fetchone()
row_dict = convert_row2dict(row)
return row_dict["max_step_no"]
def insert_gacha_user_step(cursor, step_no: int, user_id: str, gacha_id: int, gacha_type_id: str, update_time: int) -> None:
dt = datetime.fromtimestamp(update_time)
keys = ("user_id", "gacha_id", "gacha_type_id", "updated_time", "step_no")
sql = "insert into {0}({1}) values({2})".format('gacha_user_step', ','.join(keys), ','.join(['?'] * len(keys)))
cursor.execute(sql, (user_id, gacha_id, gacha_type_id, dt, step_no))
def update_gacha_user_step(cursor, step_no: int, user_id: str, gacha_id: int, gacha_type_id: str, update_time: int) -> None:
dt = datetime.fromtimestamp(update_time)
sql = "UPDATE gacha_user_step SET step_no = ?, updated_time = ? WHERE user_id = ? AND gacha_id = ? AND gacha_type_id = ?"
cursor.execute(sql, (step_no, dt, user_id, gacha_id, gacha_type_id))
def next_gacha_user_step(cursor, user_id: str, gacha_id: int, gacha_type_id: str, update_time: int) -> None:
row = get_gacha_user_step(cursor, user_id, gacha_id, gacha_type_id)
if len(row) == 0:
insert_gacha_user_step(
cursor,
rotation_gacha_user_step(cursor, gacha_type_id, 1),
user_id, gacha_id, gacha_type_id, update_time
)
else:
update_gacha_user_step(
cursor,
rotation_gacha_user_step(cursor, gacha_type_id, row["step_no"]),
user_id, gacha_id, gacha_type_id, update_time
)
#Next step number with repeat judgment added
def rotation_gacha_user_step(cursor, gacha_type_id: str, step_no: int) -> int:
if step_no == get_max_step_no(cursor, gacha_type_id):
row = get_gacha_type(cursor, gacha_type_id)
if row["rotation_step_no"] > 0:
print("check:{0},{1},{2}".format(gacha_type_id, step_no,row["rotation_step_no"]))
return row["rotation_step_no"]
else:
print("check:{0},{1},{2}".format(gacha_type_id, step_no,step_no + 1))
return step_no + 1
else:
print("check:{0},{1},{2}".format(gacha_type_id, step_no, step_no + 1))
return step_no + 1
#Reset process
def reset_gacha_user_step(cursor, user_id: str, gacha_id: int, gacha_type_id: str, now_time: int) -> None:
user_step = get_gacha_user_step(cursor, user_id, gacha_id, gacha_type_id)
if len(user_step) == 0:
return
dt = datetime.fromtimestamp(now_time)
gacha_type = get_gacha_type(cursor, gacha_type_id)
if gacha_type["reset_type"] == "daily":
if dt.day != datetime.strptime(user_step["updated_time"], '%Y-%m-%d %H:%M:%S').day:
update_gacha_user_step(cursor,1,user_id, gacha_id, gacha_type_id, now_time)
elif gacha_type["reset_type"] == "monthly":
if dt.month != datetime.strptime(user_step["updated_time"], '%Y-%m-%d %H:%M:%S').month:
update_gacha_user_step(cursor,1,user_id, gacha_id, gacha_type_id, now_time)
def set_gacha(cursor, now_time: int, user_id:str):
cursor = cursor
now_time = now_time
user_id = user_id
items = get_items_all(cursor)
#Extract the lottery target list
def get_lots(gacha_group: str, lottery_info: dict) -> Tuple[Dict,Dict]:
gacha_items = get_gacha_items(cursor, gacha_group)
dic_gacha_items = {}
for gacha_item_id, gacha_item in gacha_items.items():
gacha_item["item_info"] = items[gacha_item["item_id"]]
dic_gacha_items[gacha_item_id] = gacha_item
lots = {}
omake_lots = {}
for id, info in dic_gacha_items.items():
if lottery_info["item_type"] and lottery_info["item_type"] != info["item_info"]["item_type"]:
continue
if not(lottery_info["rarity"]) or lottery_info["rarity"] <= info["item_info"]["rarity"]:
lots[id] = info["weight"]
if lottery_info["omake_times"]:
if not(lottery_info["omake_rarity"]) or lottery_info["omake_rarity"] <= info["item_info"]["rarity"]:
omake_lots[id] = info["weight"]
return lots, omake_lots
#Gacha execution
def exec(exec_gacha_id: int, exec_gacha_lottery_id: str) -> List:
gacha_info, gacha_lottery_info = get_gacha_info(cursor, exec_gacha_id, exec_gacha_lottery_id, now_time, user_id)
if gacha_info is None or gacha_lottery_info is None:
return []
print("==%s==:gacha_group:%s" % (gacha_lottery_info["id"], gacha_info["gacha_group"]))
lots, omake_lots = get_lots(gacha_info["gacha_group"], gacha_lottery_info)
ids = gacha(lots, gacha_lottery_info["times"])
if len(omake_lots) > 0:
ids.extend(gacha(omake_lots, gacha_lottery_info["omake_times"]))
#In the case of step-up gacha, update the number of executions
if len(ids) > 0 and gacha_lottery_info["step_no"] > 0:
next_gacha_user_step(cursor, user_id, exec_gacha_id, gacha_info["gacha_type_id"], now_time)
return ids
return exec
def test_step(cursor, user_id, now_time, gacha_id, gacha_type_id, step_no_list):
print("[TEST:{0}]".format(gacha_type_id))
#Feasible gacha_lottery
available_list = get_available_gacha_info_list(cursor,now_time,user_id)
for available_gacha_id,available in available_list.items():
print(available_gacha_id,available)
func_gacha = set_gacha(cursor, now_time, user_id)
items = get_items_all(cursor)
gacha_items = get_gacha_items_all(cursor)
#Step-up gacha
for step_no in step_no_list:
gacha_lottery_id = "{0}_{1}".format(gacha_type_id,str(step_no))
ids = func_gacha(gacha_id,gacha_lottery_id)
if len(ids) > 0:
for id in ids:
item_info = items[gacha_items[id]["item_id"]]
print("ID:%d, %s, %s" % (id, get_rarity_name(item_info["rarity"]), item_info["item_name"]))
def main():
con = sqlite3.connect("data.db")
con.row_factory = sqlite3.Row
cursor = con.cursor()
#Actually, the user ID will be obtained from the authentication information.
user_id = "u001"
#Specify the gacha execution date and time to check the operation
now_time = int(datetime.strptime("2020-05-01 00:00:00", '%Y-%m-%d %H:%M:%S').timestamp())
# step_up_N test
test_step(cursor, user_id, now_time, 10, "step_up_N", [1,2,3,4,1,])
print("\n [Confirm that it can be reset and executed by advancing the date]")
now_time = int(datetime.strptime("2020-05-02 00:00:00", '%Y-%m-%d %H:%M:%S').timestamp())
test_step(cursor, user_id, now_time, 10, "step_up_N", [1,2,3,4,])
# step_up_S1 test
print("\n [Confirm to return to step 1]")
test_step(cursor, user_id, now_time, 12, "step_up_S1", [1,2,3,4,1,2,])
print("\n [Confirmation that the date will be advanced and reset: The previous month was completed up to step2]")
now_time = int(datetime.strptime("2020-06-01 00:00:00", '%Y-%m-%d %H:%M:%S').timestamp())
test_step(cursor, user_id, now_time, 12, "step_up_S1", [1,2,3,4,])
# step_up_S2 test
print("\n [Confirm that it can be executed repeatedly in step 4]")
test_step(cursor, user_id, now_time, 14, "step_up_S2", [1,2,3,4,4,])
con.commit()
con.close()
if __name__ == '__main__':
main()
[TEST:step_up_N]
10 {'id': 10, 'start_time': '2020-05-01 00:00:00', 'end_time': '2020-05-31 23:59:59', 'gacha_group': 'A', 'gacha_type_id': 'step_up_N', 'gacha_lottery_list': []}
12 {'id': 12, 'start_time': '2020-05-01 00:00:00', 'end_time': '2020-07-31 23:59:59', 'gacha_group': 'A', 'gacha_type_id': 'step_up_S1', 'gacha_lottery_list': [{'id': 'step_up_S1_2', 'gacha_type_id': 'step_up_S1', 'step_no': 2, 'item_type': 0, 'times': 1, 'rarity': 0, 'omake_times': 1, 'omake_rarity': 3, 'cost': 20}]}
13 {'id': 13, 'start_time': '2020-05-01 00:00:00', 'end_time': '2020-05-31 23:59:59', 'gacha_group': 'A', 'gacha_type_id': 'step_up_S2', 'gacha_lottery_list': [{'id': 'step_up_S2_1', 'gacha_type_id': 'step_up_S2', 'step_no': 1, 'item_type': 0, 'times': 1, 'rarity': 0, 'omake_times': 0, 'omake_rarity': 0, 'cost': 10}]}
==step_up_N_1==:gacha_group:A
check:step_up_N,1,2
ID:9, R, R_Wizard
==step_up_N_2==:gacha_group:A
check:step_up_N,2,3
ID:10, R, R_Priest
ID:9, R, R_Wizard
ID:4, SSR, SSR_Priest
==step_up_N_3==:gacha_group:A
check:step_up_N,3,4
ID:9, R, R_Wizard
ID:10, R, R_Priest
ID:9, R, R_Wizard
ID:7, SR, SR_Priest
ID:5, SR, SR_Warrior
==step_up_N_4==:gacha_group:A
check:step_up_N,4,5
ID:9, R, R_Wizard
ID:9, R, R_Wizard
ID:10, R, R_Priest
ID:5, SR, SR_Warrior
ID:1, UR, UR_Brave
===Up to the maximum step has been executed (maximum step):4, the step you are going to perform:1)===
[Confirmation that it will be reset and executable by advancing the date]
[TEST:step_up_N]
10 {'id': 10, 'start_time': '2020-05-01 00:00:00', 'end_time': '2020-05-31 23:59:59', 'gacha_group': 'A', 'gacha_type_id': 'step_up_N', 'gacha_lottery_list': []}
12 {'id': 12, 'start_time': '2020-05-01 00:00:00', 'end_time': '2020-07-31 23:59:59', 'gacha_group': 'A', 'gacha_type_id': 'step_up_S1', 'gacha_lottery_list': [{'id': 'step_up_S1_2', 'gacha_type_id': 'step_up_S1', 'step_no': 2, 'item_type': 0, 'times': 1, 'rarity': 0, 'omake_times': 1, 'omake_rarity': 3, 'cost': 20}]}
13 {'id': 13, 'start_time': '2020-05-01 00:00:00', 'end_time': '2020-05-31 23:59:59', 'gacha_group': 'A', 'gacha_type_id': 'step_up_S2', 'gacha_lottery_list': [{'id': 'step_up_S2_1', 'gacha_type_id': 'step_up_S2', 'step_no': 1, 'item_type': 0, 'times': 1, 'rarity': 0, 'omake_times': 0, 'omake_rarity': 0, 'cost': 10}]}
==step_up_N_1==:gacha_group:A
check:step_up_N,1,2
ID:7, SR, SR_Priest
==step_up_N_2==:gacha_group:A
check:step_up_N,2,3
ID:10, R, R_Priest
ID:5, SR, SR_Warrior
ID:6, SR, SR_Wizard
==step_up_N_3==:gacha_group:A
check:step_up_N,3,4
ID:10, R, R_Priest
ID:8, R, R_Warrior
ID:5, SR, SR_Warrior
ID:4, SSR, SSR_Priest
ID:7, SR, SR_Priest
==step_up_N_4==:gacha_group:A
check:step_up_N,4,5
ID:9, R, R_Wizard
ID:8, R, R_Warrior
ID:7, SR, SR_Priest
ID:5, SR, SR_Warrior
ID:3, SSR, SSR_Wizard
[Confirm to return to step 1]
[TEST:step_up_S1]
10 {'id': 10, 'start_time': '2020-05-01 00:00:00', 'end_time': '2020-05-31 23:59:59', 'gacha_group': 'A', 'gacha_type_id': 'step_up_N', 'gacha_lottery_list': []}
12 {'id': 12, 'start_time': '2020-05-01 00:00:00', 'end_time': '2020-07-31 23:59:59', 'gacha_group': 'A', 'gacha_type_id': 'step_up_S1', 'gacha_lottery_list': [{'id': 'step_up_S1_2', 'gacha_type_id': 'step_up_S1', 'step_no': 2, 'item_type': 0, 'times': 1, 'rarity': 0, 'omake_times': 1, 'omake_rarity': 3, 'cost': 20}]}
13 {'id': 13, 'start_time': '2020-05-01 00:00:00', 'end_time': '2020-05-31 23:59:59', 'gacha_group': 'A', 'gacha_type_id': 'step_up_S2', 'gacha_lottery_list': [{'id': 'step_up_S2_1', 'gacha_type_id': 'step_up_S2', 'step_no': 1, 'item_type': 0, 'times': 1, 'rarity': 0, 'omake_times': 0, 'omake_rarity': 0, 'cost': 10}]}
==step_up_S1_1==:gacha_group:A
check:step_up_S1,1,2
ID:10, R, R_Priest
==step_up_S1_2==:gacha_group:A
check:step_up_S1,2,3
ID:5, SR, SR_Warrior
ID:7, SR, SR_Priest
==step_up_S1_3==:gacha_group:A
check:step_up_S1,3,4
ID:7, SR, SR_Priest
ID:7, SR, SR_Priest
ID:7, SR, SR_Priest
==step_up_S1_4==:gacha_group:A
check:step_up_S1,4,1
ID:2, SSR, SSR_Warrior
ID:10, R, R_Priest
ID:7, SR, SR_Priest
ID:3, SSR, SSR_Wizard
ID:1, UR, UR_Brave
==step_up_S1_1==:gacha_group:A
check:step_up_S1,1,2
ID:9, R, R_Wizard
==step_up_S1_2==:gacha_group:A
check:step_up_S1,2,3
ID:10, R, R_Priest
ID:6, SR, SR_Wizard
[Confirmation that the date will be advanced and reset: The previous month was completed up to step 2]
[TEST:step_up_S1]
11 {'id': 11, 'start_time': '2020-06-01 00:00:00', 'end_time': '2020-06-30 23:59:59', 'gacha_group': 'C', 'gacha_type_id': 'step_up_N', 'gacha_lottery_list': [{'id': 'step_up_N_1', 'gacha_type_id': 'step_up_N', 'step_no': 1, 'item_type': 0, 'times': 1, 'rarity': 0, 'omake_times': 0, 'omake_rarity': 0, 'cost': 10}]}
12 {'id': 12, 'start_time': '2020-05-01 00:00:00', 'end_time': '2020-07-31 23:59:59', 'gacha_group': 'A', 'gacha_type_id': 'step_up_S1', 'gacha_lottery_list': [{'id': 'step_up_S1_4', 'gacha_type_id': 'step_up_S1', 'step_no': 4, 'item_type': 0, 'times': 3, 'rarity': 0, 'omake_times': 2, 'omake_rarity': 4, 'cost': 50}]}
14 {'id': 14, 'start_time': '2020-06-01 00:00:00', 'end_time': '2020-06-30 23:59:59', 'gacha_group': 'C', 'gacha_type_id': 'step_up_S2', 'gacha_lottery_list': []}
==step_up_S1_1==:gacha_group:A
check:step_up_S1,1,2
ID:10, R, R_Priest
==step_up_S1_2==:gacha_group:A
check:step_up_S1,2,3
ID:5, SR, SR_Warrior
ID:4, SSR, SSR_Priest
==step_up_S1_3==:gacha_group:A
check:step_up_S1,3,4
ID:8, R, R_Warrior
ID:5, SR, SR_Warrior
ID:6, SR, SR_Wizard
==step_up_S1_4==:gacha_group:A
check:step_up_S1,4,1
ID:6, SR, SR_Wizard
ID:5, SR, SR_Warrior
ID:7, SR, SR_Priest
ID:2, SSR, SSR_Warrior
ID:3, SSR, SSR_Wizard
[Confirm that it can be executed repeatedly in step 4]
[TEST:step_up_S2]
11 {'id': 11, 'start_time': '2020-06-01 00:00:00', 'end_time': '2020-06-30 23:59:59', 'gacha_group': 'C', 'gacha_type_id': 'step_up_N', 'gacha_lottery_list': [{'id': 'step_up_N_1', 'gacha_type_id': 'step_up_N', 'step_no': 1, 'item_type': 0, 'times': 1, 'rarity': 0, 'omake_times': 0, 'omake_rarity': 0, 'cost': 10}]}
12 {'id': 12, 'start_time': '2020-05-01 00:00:00', 'end_time': '2020-07-31 23:59:59', 'gacha_group': 'A', 'gacha_type_id': 'step_up_S1', 'gacha_lottery_list': [{'id': 'step_up_S1_2', 'gacha_type_id': 'step_up_S1', 'step_no': 2, 'item_type': 0, 'times': 1, 'rarity': 0, 'omake_times': 1, 'omake_rarity': 3, 'cost': 20}]}
14 {'id': 14, 'start_time': '2020-06-01 00:00:00', 'end_time': '2020-06-30 23:59:59', 'gacha_group': 'C', 'gacha_type_id': 'step_up_S2', 'gacha_lottery_list': []}
===Different from the steps that can be performed (current step:4, the step you are going to perform:1)===
===Different from the steps that can be performed (current step:4, the step you are going to perform:2)===
===Different from the steps that can be performed (current step:4, the step you are going to perform:3)===
==step_up_S2_4==:gacha_group:C
check:step_up_S2,4,4
ID:24, R, R_Warrior
ID:25, R, R_Wizard
ID:23, SR, SR_Priest
ID:25, R, R_Wizard
ID:23, SR, SR_Priest
==step_up_S2_4==:gacha_group:C
check:step_up_S2,4,4
ID:26, R, R_Priest
ID:25, R, R_Wizard
ID:15, UR, UR_Warrior
ID:22, SR, SR_Wizard
ID:20, SSR, SSR_Priest
Since there is no repeat setting, you can confirm that it has finished after executing the 4th time. Then, when the date changes, you can confirm that it is possible to execute from step 1 again.
Since there is a repeat setting, you can return to Step 1 after executing the 4th time and confirm that it can be executed. Then, when the month changes, you will be returned to step 1 where you can see that it is feasible.
Since there is a repeat setting, you can confirm that Step 4 can be executed repeatedly after executing the 4th time.
Added Repeat
and Reset
control processing to the logic of Last time.
It's a little harder, but it hasn't been refurbished so much.
(* It took more time to put together the test code ... *)
With the addition of this function, it is possible to control the progress of gacha by master setting
.
It is possible to create various patterns of gacha by combining the settings of the master.
In operation, it is necessary to repeat hypothesis and verification of an effective approach to users.
Efficient operation can be realized by setting the master so that the planner can do it.
Recommended Posts