├── README.md └── run.py /README.md: -------------------------------------------------------------------------------- 1 | # Snowsant Calculator 2 | 3 | 一个基于 Python 的策略求解器,用于最大化《雪雉的小店》(明日方舟 2023 年夏活经营类小游戏)的期望收益。 4 | 5 | > 本来懒得写的,因为没多少技术含量,但不相信所谓「终极策略」中提到的全激进进货策略,最后还是花了半天写完了。 6 | 7 | ### 在线计算 8 | 9 | - [自行维护的在线计算器](https://ark.c-4.cc/snowsant-calculator/):不太稳定,更新比较及时 10 | - [由一图流维护的在线计算器](https://yituliu.site/tools/snowsant):比较稳定,更新会稍慢一点 11 | 12 | ### 使用方法 13 | 14 | ```bash 15 | python3 run.py 16 | pypy3 run.py # 推荐用法 17 | ``` 18 | -------------------------------------------------------------------------------- /run.py: -------------------------------------------------------------------------------- 1 | class Colors: 2 | RESET = "\033[0m" 3 | BLACK = "\033[30m" 4 | RED = "\033[31m" 5 | GREEN = "\033[32m" 6 | YELLOW = "\033[33m" 7 | BLUE = "\033[34m" 8 | MAGENTA = "\033[35m" 9 | CYAN = "\033[36m" 10 | WHITE = "\033[37m" 11 | BOLD = "\033[1m" 12 | UNDERLINE = "\033[4m" 13 | GREY = "\033[90m" 14 | 15 | 16 | HELLO = r""" 17 | _____ _ 18 | / ____| | | 19 | | (___ _ __ _____ _____ __ _ _ __ | |_ 20 | \___ \| '_ \ / _ \ \ /\ / / __|/ _` | '_ \| __| 21 | ____) | | | | (_) \ V V /\__ \ (_| | | | | |_ 22 | |_____/|_| |_|\___/ \_/\_/ |___/\__,_|_| |_|\__| 23 | _____ _ _ _ 24 | / ____| | | | | | | 25 | | | __ _| | ___ _ _| | __ _| |_ ___ _ __ 26 | | | / _` | |/ __| | | | |/ _` | __/ _ \| '__| 27 | | |___| (_| | | (__| |_| | | (_| | || (_) | | 28 | \_____\__,_|_|\___|\__,_|_|\__,_|\__\___/|_| 29 | 30 | """ 31 | 32 | ALERT = r""" 33 | ============================================================= 34 | | | 35 | | 如果遇到一启动就 Connection closed 的情况,可以稍后重试 | 36 | | | 37 | =============================================================""" 38 | 39 | # print(Colors.RED + ALERT + Colors.RESET) 40 | print(Colors.CYAN + HELLO + Colors.RESET) 41 | 42 | 43 | def input_int(prompt, valid=None): 44 | while True: 45 | try: 46 | value = int(input(prompt)) 47 | if isinstance(valid, (range, list)): 48 | valid = tuple(valid) 49 | if isinstance(valid, tuple): 50 | assert value in valid, f"[!] 输入的值不在合法范围内:{valid}" 51 | if isinstance(valid, int): 52 | assert value % valid == 0, f"[!] 输入的值需要是 {valid} 的倍数。" 53 | return value 54 | except AssertionError as e: 55 | print(Colors.RED + str(e) + Colors.RESET) 56 | except Exception: 57 | print(Colors.RED + "[!] 输入有误,请重新输入。" + Colors.RESET) 58 | 59 | 60 | def input_ints(prompt, nums, sum_to): 61 | while True: 62 | try: 63 | values = tuple(map(int, input(prompt).strip().split(" "))) 64 | assert len(values) == nums, f"[!] 输入的数目不对,请重新输入。" 65 | assert sum(values) == sum_to, f"[!] 进货总数量与顾客数量不符,请重新输入。" 66 | return values 67 | except AssertionError as e: 68 | print(Colors.RED + str(e) + Colors.RESET) 69 | except Exception: 70 | print(Colors.RED + "[!] 输入有误,请重新输入。" + Colors.RESET) 71 | 72 | 73 | good_stage = input_int("[*] 今日经营的商品是哪个阶段的商品?(1-4) ", range(1, 5)) 74 | 75 | if good_stage == 1: 76 | buy_drink = [20, 28, 38] 77 | buy_snack = [10, 20, 32] 78 | buy_token = [50, 100, 200] 79 | sell_base_drink = 50 80 | sell_base_snack = 40 81 | sell_base_token = 1000 82 | 83 | elif good_stage == 2: 84 | buy_drink = [30, 42, 57] 85 | buy_snack = [15, 30, 48] 86 | buy_token = [50, 100, 200] 87 | sell_base_drink = 100 88 | sell_base_snack = 80 89 | sell_base_token = 1000 90 | 91 | elif good_stage == 3: 92 | buy_drink = [40, 56, 76] 93 | buy_snack = [20, 40, 64] 94 | buy_token = [50, 100, 200] 95 | sell_base_drink = 200 96 | sell_base_snack = 160 97 | sell_base_token = 1000 98 | 99 | elif good_stage == 4: 100 | buy_drink = [50, 70, 95] 101 | buy_snack = [25, 50, 80] 102 | buy_token = [50, 100, 200] 103 | sell_base_drink = 250 104 | sell_base_snack = 200 105 | sell_base_token = 1000 106 | 107 | customer_drink = input_int("[*] 今日的饮品爱好者有多少?", 90) 108 | customer_snack = input_int("[*] 今日的餐点爱好者有多少?", 90) 109 | customer_token = input_int("[*] 今日的纪念品爱好者有多少?", 10) 110 | customer = [customer_drink, customer_snack, customer_token] 111 | buy_prices = [buy_drink, buy_snack, buy_token] 112 | stock_drink = customer_drink 113 | stock_snack = customer_snack 114 | stock_token = customer_token 115 | 116 | remain_me = input_int("[*] 雪雉商店的纪念品库存有多少(不知道的话填 0 即可)?") 117 | remain_rival = input_int("[*] 时光商店的纪念品库存有多少(不知道的话填 0 即可)?") 118 | remain_strategy = input_int("[*] 是否允许用更少的当日收入换取更多的未来期望收入?需要更久的计算时间。0 为否,1 为是 (0/1) ", (0, 1)) 119 | if remain_strategy: 120 | print(Colors.RED + "[!] 请注意,后续的期望收益包括纪念品库存未来可能的收益。" + Colors.RESET) 121 | 122 | # aaa = (30, 30, 30) 123 | # aab = (36, 36, 18) 124 | # abb = (36, 27, 27) 125 | # abc = (40, 30, 20) 126 | # aa = (5, 5) 127 | # ab = (6, 4) 128 | 129 | sell_drink = list(range(sell_base_drink - 5, sell_base_drink + 6, 1)) 130 | sell_snack = list(range(sell_base_snack - 5, sell_base_snack + 6, 1)) 131 | sell_token = list(range(sell_base_token - 50, sell_base_token + 51, 10)) 132 | sell = [sell_drink, sell_snack, sell_token] 133 | 134 | # ============================================================ 135 | 136 | 137 | from itertools import product 138 | 139 | 140 | def average_with_weight(pairs): 141 | return sum([x[0] * x[-1] for x in pairs]) / sum([x[-1] for x in pairs]) 142 | 143 | 144 | # ============================================================ 145 | 146 | 147 | import datetime 148 | 149 | end_time = datetime.datetime(2024, 9, 1, 4, 0) 150 | now_time = datetime.datetime.now() 151 | countdown = (end_time - now_time).days + 1 152 | 153 | 154 | future_token_sell_cache = {} 155 | 156 | 157 | def future_token_sell(day, stock): 158 | if day == 0: 159 | return 0 160 | if (day, stock) in future_token_sell_cache: 161 | return future_token_sell_cache[(day, stock)] 162 | unit = min(stock_token // 10 + (countdown - day), 14) 163 | my_stock, rival_stock = stock 164 | __value = [] 165 | for rival_price in range(11): 166 | __best_action = -1e9 167 | for my_price in range(11): 168 | if my_price > rival_price: 169 | ratio = (4, 6) 170 | elif my_price == rival_price: 171 | ratio = (5, 5) 172 | elif my_price < rival_price: 173 | ratio = (6, 4) 174 | my_sold = min(my_stock, unit * ratio[0]) 175 | rival_sold = min(rival_stock, unit * ratio[1]) 176 | my_income = sell_token[my_price] * my_sold 177 | rival_income = sell_token[rival_price] * rival_sold 178 | my_income += 5000 if my_income >= rival_income else 2000 179 | __best_action = max( 180 | __best_action, 181 | future_token_value( 182 | day - 1, (my_stock - my_sold, rival_stock - rival_sold) 183 | ) 184 | + my_income, 185 | ) 186 | __value.append(__best_action) 187 | __value = sum(__value) / len(__value) 188 | 189 | future_token_sell_cache[(day, stock)] = __value 190 | return __value 191 | 192 | 193 | future_token_value_cache = {} 194 | 195 | 196 | def future_token_value(day, stock): 197 | if day == 0: 198 | return 0 199 | if (day, stock) in future_token_value_cache: 200 | return future_token_value_cache[(day, stock)] 201 | unit = min(stock_token // 10 + (countdown - day), 14) 202 | my_stock, rival_stock = stock 203 | __value = [] 204 | for rival_strategy in range(3): 205 | __best_action = -1e9 206 | for my_strategy in range(3): 207 | if my_strategy > rival_strategy: 208 | ratio = (6, 4) 209 | elif my_strategy == rival_strategy: 210 | ratio = (5, 5) 211 | elif my_strategy < rival_strategy: 212 | ratio = (4, 6) 213 | __best_action = max( 214 | __best_action, 215 | future_token_sell( 216 | day, (my_stock + unit * ratio[0], rival_stock + unit * ratio[1]) 217 | ) 218 | - buy_token[my_strategy] * unit * ratio[0], 219 | ) 220 | __value.append(__best_action) 221 | __value = sum(__value) / len(__value) 222 | 223 | future_token_value_cache[(day, stock)] = __value 224 | return __value 225 | 226 | 227 | def future_value_exp(day, stock): 228 | if stock[0] == 0: 229 | return 0 230 | return future_token_value(day, stock) - future_token_value(day, (0, stock[1])) 231 | 232 | 233 | # ============================================================ 234 | 235 | 236 | from functools import lru_cache 237 | 238 | sell_result_cache = {} 239 | 240 | 241 | def sell_result(bid, me) -> int: 242 | if (bid, me) in sell_result_cache: 243 | return sell_result_cache[(bid, me)] 244 | ranks = [sum([1 for y in bid if y < x]) for x in bid] 245 | sorted_ranks = sorted(ranks) 246 | if sorted_ranks == [0, 0, 0]: 247 | ret = 30 248 | elif sorted_ranks == [0, 0, 2]: 249 | ret = [36, None, 18][ranks[bid.index(me)]] 250 | elif sorted_ranks == [0, 1, 1]: 251 | ret = [36, 27][ranks[bid.index(me)]] 252 | elif sorted_ranks == [0, 1, 2]: 253 | ret = [40, 30, 20][ranks[bid.index(me)]] 254 | elif sorted_ranks == [0, 0]: 255 | ret = 5 256 | elif sorted_ranks == [0, 1]: 257 | ret = [6, 4][ranks[bid.index(me)]] 258 | else: 259 | raise NotImplementedError 260 | sell_result_cache[(bid, me)] = ret 261 | return ret 262 | 263 | 264 | @lru_cache(maxsize=None) 265 | def sell_conflict_checker(statement, info) -> bool: 266 | if len(info) == 0: 267 | return True 268 | if len(info) == 1: 269 | return info == statement 270 | if len(info) == 2: 271 | if info == (None, None): 272 | return True 273 | elif None not in info: 274 | return info == statement 275 | elif info[0] == None: 276 | return info[1] == statement[1] and info[1] >= statement[0] 277 | elif info[1] == None: 278 | return info[0] == statement[0] and info[0] >= statement[1] 279 | else: 280 | raise NotImplementedError 281 | return False 282 | 283 | 284 | sell_action_cache = {} 285 | 286 | 287 | def sell_action(gid, num, rival_num, info): 288 | num += remain_me * (gid == 2) 289 | 290 | if (gid, num, rival_num, info) in sell_action_cache: 291 | return sell_action_cache[(gid, num, rival_num, info)] 292 | 293 | # print(num, rival_num, info, gid) 294 | statements = [ 295 | statement 296 | for statement in product(range(11), repeat=[2, 2, 1][gid]) 297 | if sell_conflict_checker(statement, info) 298 | ] 299 | 300 | best_income, best_choice = -1e9, None 301 | for c in range(11): 302 | incomes = [] 303 | sameprice = None 304 | for statement in statements: 305 | customer_base = customer[gid] // [90, 90, 10][gid] 306 | customer_num = customer_base * sell_result(statement + (c,), c) 307 | my_sold = min(customer_num, num) 308 | income = my_sold * sell[gid][c] 309 | income_rank = 0 310 | for _c, _n in zip(statement, rival_num): 311 | _n += remain_rival * (gid == 2) 312 | rival_customer_num = customer_base * sell_result(statement + (c,), _c) 313 | rival_sold = min(rival_customer_num, _n) 314 | rival_income = rival_sold * sell[gid][_c] 315 | if rival_income > income: 316 | income_rank += 1 317 | # print(c, statement + (c,), sell_result(statement + (c,), c), sell[gid][c], income, income_rank) 318 | if income_rank == 0: 319 | income += 5000 320 | elif income_rank == 1: 321 | income += 2000 322 | else: 323 | income += 1000 324 | if remain_strategy and gid == 2: 325 | income += future_value_exp( 326 | countdown - 1, (num - my_sold, rival_num[0] - rival_sold) 327 | ) 328 | incomes.append(income) 329 | if len(info) == 2 and None in info and statement[0] == statement[1]: 330 | sameprice = income 331 | if sameprice is not None: 332 | exp_income = (sum(incomes) - 0.5 * sameprice) / (len(incomes) - 0.5) 333 | else: 334 | exp_income = sum(incomes) / len(incomes) 335 | # print(c, incomes, sameprice, exp_income) 336 | if exp_income > best_income: 337 | best_income, best_choice = exp_income, (c,) 338 | 339 | # print(gid, info, best_income, best_choice, statements) 340 | sell_action_cache[(gid, num, rival_num, info)] = (best_income, best_choice) 341 | return best_income, best_choice 342 | 343 | 344 | sell_stage_cache = {} 345 | 346 | 347 | def sell_stage(clues, gid, nums, rival_nums, info): 348 | if gid == 3: 349 | return -clues, -1, None 350 | if (clues, gid, nums[gid:], rival_nums[gid:], info) in sell_stage_cache: 351 | return sell_stage_cache[(clues, gid, nums[gid:], rival_nums[gid:], info)] 352 | 353 | best_income, best_choice = sell_action(gid, nums[gid], rival_nums[gid], info) 354 | best_income += sell_stage(clues, gid + 1, nums, rival_nums, ())[0] 355 | 356 | if clues: 357 | if info == (): 358 | if gid != 2: 359 | pry_income = average_with_weight( 360 | [ 361 | sell_stage(clues - 1, gid, nums, rival_nums, (i, None)) 362 | for i in range(11) 363 | ] 364 | + [ 365 | sell_stage(clues - 1, gid, nums, rival_nums, (None, i)) 366 | for i in range(11) 367 | ] 368 | ) 369 | if pry_income > best_income: 370 | best_income, best_choice = pry_income, -1 371 | else: 372 | pry_income = average_with_weight( 373 | [ 374 | sell_stage(clues - 1, gid, nums, rival_nums, (i,)) 375 | for i in range(11) 376 | ] 377 | ) 378 | if pry_income > best_income: 379 | best_income, best_choice = pry_income, -1 380 | elif None in info: 381 | __idx = 1 - info.index(None) 382 | pry_income = average_with_weight( 383 | [ 384 | sell_stage( 385 | clues - 1, 386 | gid, 387 | nums, 388 | rival_nums, 389 | (i, info[1]) if __idx == 1 else (info[0], i), 390 | ) 391 | for i in range(info[__idx] + 1) 392 | ] 393 | ) 394 | if pry_income > best_income: 395 | best_income, best_choice = pry_income, -1 396 | 397 | statements = [ 398 | statement 399 | for statement in product(range(11), repeat=[2, 2, 1][gid]) 400 | if sell_conflict_checker(statement, info) 401 | ] 402 | 403 | statements_num = len(statements) 404 | if len(info) == 2 and None in info: 405 | statements_num -= 0.5 406 | 407 | sell_stage_cache[(clues, gid, nums[gid:], rival_nums[gid:], info)] = ( 408 | best_income, 409 | best_choice, 410 | statements_num, 411 | ) 412 | return best_income, best_choice, statements_num 413 | 414 | 415 | # ============================================================ 416 | 417 | 418 | buy_result_cache = {} 419 | 420 | 421 | def buy_result(bid, me): 422 | if (bid, me) in buy_result_cache: 423 | return buy_result_cache[(bid, me)] 424 | ranks = [sum([1 for y in bid if y > x]) for x in bid] 425 | sorted_ranks = sorted(ranks) 426 | if sorted_ranks == [0, 0, 0]: 427 | ret = 30 428 | elif sorted_ranks == [0, 0, 2]: 429 | ret = [36, None, 18][ranks[bid.index(me)]] 430 | elif sorted_ranks == [0, 1, 1]: 431 | ret = [36, 27][ranks[bid.index(me)]] 432 | elif sorted_ranks == [0, 1, 2]: 433 | ret = [40, 30, 20][ranks[bid.index(me)]] 434 | elif sorted_ranks == [0, 0]: 435 | ret = 5 436 | elif sorted_ranks == [0, 1]: 437 | ret = [6, 4][ranks[bid.index(me)]] 438 | else: 439 | raise NotImplementedError 440 | buy_result_cache[(bid, me)] = ret 441 | return ret 442 | 443 | 444 | def buy_conflict_checker(statement, info): 445 | if len(info) == 0 or statement == info: 446 | return True 447 | if len(info) == 1: 448 | return info[0] == statement[0] 449 | return False 450 | 451 | 452 | def buy_action(clues, infos): 453 | statements = [ 454 | statement 455 | for statement in product(range(3), repeat=5) 456 | if buy_conflict_checker(statement[0:2], infos[0]) 457 | and buy_conflict_checker(statement[2:4], infos[1]) 458 | and buy_conflict_checker(statement[4:5], infos[2]) 459 | ] 460 | 461 | if len(statements) == 0: 462 | print(clues, infos) 463 | 464 | best_income, best_choice = -1e9, None 465 | for c in product(range(3), repeat=3): 466 | incomes = [] 467 | for statement in statements: 468 | drink_nums = stock_drink // 90 * buy_result(statement[0:2] + (c[0],), c[0]) 469 | snack_nums = stock_snack // 90 * buy_result(statement[2:4] + (c[1],), c[1]) 470 | token_nums = stock_token // 10 * buy_result(statement[4:5] + (c[2],), c[2]) 471 | costs = ( 472 | drink_nums * buy_drink[c[0]] 473 | + snack_nums * buy_snack[c[1]] 474 | + token_nums * buy_token[c[2]] 475 | ) 476 | nums = (drink_nums, snack_nums, token_nums) 477 | __sd = stock_drink // 90 478 | __ss = stock_snack // 90 479 | __st = stock_token // 10 480 | rival_nums = ( 481 | ( 482 | __sd * buy_result(statement[0:2] + (c[0],), statement[0]), 483 | __sd * buy_result(statement[0:2] + (c[0],), statement[1]), 484 | ), 485 | ( 486 | __ss * buy_result(statement[2:4] + (c[1],), statement[2]), 487 | __ss * buy_result(statement[2:4] + (c[1],), statement[3]), 488 | ), 489 | (__st * buy_result(statement[4:5] + (c[2],), statement[4]),), 490 | ) 491 | sell_income = sell_stage(clues, 0, nums, rival_nums, ())[0] 492 | incomes.append(sell_income - costs) 493 | exp_income = sum(incomes) / len(incomes) 494 | if exp_income > best_income: 495 | best_income, best_choice = exp_income, c 496 | return best_income, best_choice 497 | 498 | 499 | buy_stage_cache = {} 500 | 501 | 502 | def buy_stage(clues, infos): 503 | if (clues, infos) in buy_stage_cache: 504 | return buy_stage_cache[(clues, infos)] 505 | 506 | best_income, best_choice = buy_action(clues, infos) 507 | 508 | if clues: 509 | if len(infos[0]) < 2: 510 | pry_income = average_with_weight( 511 | [ 512 | buy_stage(clues - 1, (infos[0] + (i,), infos[1], infos[2])) 513 | for i in range(3) 514 | ] 515 | ) 516 | if pry_income > best_income: 517 | best_income, best_choice = pry_income, 0 518 | 519 | if len(infos[1]) < 2: 520 | pry_income = average_with_weight( 521 | [ 522 | buy_stage(clues - 1, (infos[0], infos[1] + (i,), infos[2])) 523 | for i in range(3) 524 | ] 525 | ) 526 | if pry_income > best_income: 527 | best_income, best_choice = pry_income, 1 528 | 529 | if len(infos[2]) < 1: 530 | pry_income = average_with_weight( 531 | [ 532 | buy_stage(clues - 1, (infos[0], infos[1], infos[2] + (i,))) 533 | for i in range(3) 534 | ] 535 | ) 536 | if pry_income > best_income: 537 | best_income, best_choice = pry_income, 2 538 | 539 | statements = [ 540 | statement 541 | for statement in product(range(3), repeat=5) 542 | if buy_conflict_checker(statement[0:2], infos[0]) 543 | and buy_conflict_checker(statement[2:4], infos[1]) 544 | and buy_conflict_checker(statement[4:5], infos[2]) 545 | ] 546 | 547 | buy_stage_cache[(clues, infos)] = (best_income, best_choice, len(statements)) 548 | return (best_income, best_choice, len(statements)) 549 | 550 | 551 | # ============================================================ 552 | 553 | import sys 554 | 555 | 556 | def action_confirm(): 557 | input(Colors.GREY + "行动结束后按下回车键……" + Colors.RESET) 558 | sys.stdout.write("\033[F") 559 | sys.stdout.write("\033[K") 560 | 561 | 562 | clues = input_int("[*] 请输入可打探的次数:", (4, 5, 6)) 563 | infos = ((), (), ()) 564 | print("请稍等,正在计算中……") 565 | while True: 566 | ret = buy_stage(clues, infos) 567 | print(Colors.GREEN + f"[+] 当前期望收益为:{ret[0]}" + Colors.RESET) 568 | if isinstance(ret[1], int): 569 | goods = ["饮品", "餐点", "纪念品"][ret[1]] 570 | print(Colors.YELLOW + f"[A] 请打探 {goods} 的信息(从上往下选择第一个未打探过的商店)" + Colors.RESET) 571 | action_confirm() 572 | choice = input_int("[*] 请问该商店的进货策略是?1 保守,2 稳健,3 激进 (1-3) ", range(1, 4)) 573 | infos = list(infos) 574 | infos[ret[1]] = infos[ret[1]] + (choice - 1,) 575 | infos = tuple(infos) 576 | clues -= 1 577 | else: 578 | strategy = [["保守", "稳健", "激进"][ret[1][i]] for i in range(3)] 579 | print(Colors.YELLOW + "[A] 进货策略已确定:" + ",".join(strategy) + Colors.RESET) 580 | action_confirm() 581 | break 582 | 583 | print("[+] 请告知每种商品的进货数量,店与店之间用空格隔开。") 584 | print("[+] 注意,商店的次序需要是特定的顺序,而不是进货数量排行榜上的顺序。") 585 | 586 | drink = input_ints("[*] 饮品进货数量(按顺序三个数分别是 雪雉商店、鸡尾酒商店、时光商店,中间用空格隔开):", 3, customer_drink) 587 | snack = input_ints("[*] 餐点进货数量(按顺序三个数分别是 雪雉商店、冰淇淋商店、时光商店,中间用空格隔开):", 3, customer_snack) 588 | token = input_ints("[*] 纪念品进货数量(按顺序两个数分别是 雪雉商店、时光商店,中间用空格隔开):", 2, customer_token) 589 | 590 | nums = (drink[0], snack[0], token[0]) 591 | rival_nums = (drink[1:], snack[1:], token[1:]) 592 | 593 | cost = sum([nums[i] * buy_prices[i][ret[1][i]] for i in range(3)]) 594 | income = 0 595 | 596 | print("饮品售卖阶段。") 597 | info = () 598 | while True: 599 | ret = sell_stage(clues, 0, nums, rival_nums, info) 600 | print(Colors.GREEN + f"[+] 当前期望收益为:{ret[0] - cost + income}" + Colors.RESET) 601 | if isinstance(ret[1], int): 602 | print(Colors.YELLOW + f"[A] 请进行一次消息打探。" + Colors.RESET) 603 | action_confirm() 604 | rival = input_int("[*] 请问打探到了哪个商店的信息?1 为鸡尾酒商店,2 为时光商店 (1-2) ", (1, 2)) 605 | price = input_int("[*] 请问他们给出的售价是?", sell_drink) 606 | price_idx = list(sell_drink).index(price) 607 | if info == (): 608 | info = (None, None) 609 | info = list(info) 610 | info[rival - 1] = price_idx 611 | info = tuple(info) 612 | clues -= 1 613 | else: 614 | price = sell_drink[ret[1][0]] 615 | print(Colors.YELLOW + f"[A] 饮品售卖策略已确定。请设定价格为:{price}" + Colors.RESET) 616 | action_confirm() 617 | break 618 | income += input_int("[*] 请输入饮品售卖收益(包括激励奖励):") 619 | 620 | 621 | print("餐品售卖阶段。") 622 | info = () 623 | while True: 624 | ret = sell_stage(clues, 1, nums, rival_nums, info) 625 | print(Colors.GREEN + f"[+] 当前期望收益为:{ret[0] - cost + income}" + Colors.RESET) 626 | if isinstance(ret[1], int): 627 | print(Colors.YELLOW + f"[A] 请进行一次消息打探。" + Colors.RESET) 628 | action_confirm() 629 | rival = input_int("[*] 请问打探到了哪个商店的信息?1 为冰淇淋商店,2 为时光商店 (1-2) ", (1, 2)) 630 | price = input_int("[*] 请问他们给出的售价是?", sell_snack) 631 | price_idx = list(sell_snack).index(price) 632 | if info == (): 633 | info = (None, None) 634 | info = list(info) 635 | info[rival - 1] = price_idx 636 | info = tuple(info) 637 | clues -= 1 638 | else: 639 | price = sell_snack[ret[1][0]] 640 | print(Colors.YELLOW + f"[A] 餐品售卖策略已确定。请设定价格为:{price}" + Colors.RESET) 641 | action_confirm() 642 | break 643 | income += input_int("[*] 请输入餐点售卖收益(包括激励奖励):") 644 | 645 | 646 | print("纪念品售卖阶段。") 647 | info = () 648 | while True: 649 | ret = sell_stage(clues, 2, nums, rival_nums, info) 650 | print(Colors.GREEN + f"[+] 当前期望收益为:{ret[0] - cost + income}" + Colors.RESET) 651 | if isinstance(ret[1], int): 652 | print(Colors.YELLOW + f"[A] 请进行一次消息打探。" + Colors.RESET) 653 | action_confirm() 654 | price = input_int("[*] 请问时光商店给出的售价是?", sell_token) 655 | price_idx = list(sell_token).index(price) 656 | info = (price_idx,) 657 | clues -= 1 658 | else: 659 | price = sell_token[ret[1][0]] 660 | print(Colors.YELLOW + f"[A] 纪念品售卖策略已确定。请设定价格为:{price}" + Colors.RESET) 661 | action_confirm() 662 | break 663 | income += input_int("[*] 请输入纪念品售卖收益(包括激励奖励):") 664 | 665 | sold_token_me = input_int("[*] 请输入雪雉商店的纪念品售卖数量:") 666 | sold_token_rival = input_int("[*] 请输入时光商店的纪念品售卖数量:") 667 | new_remain_me = remain_me + nums[-1] - sold_token_me 668 | new_remain_rival = remain_rival + rival_nums[-1][-1] - sold_token_rival 669 | print(Colors.GREEN + f"[+] 雪雉商店的纪念品库存为:{new_remain_me}" + Colors.RESET) 670 | print(Colors.GREEN + f"[+] 时光商店的纪念品库存为:{new_remain_rival}" + Colors.RESET) 671 | if new_remain_rival < 0: 672 | print(Colors.RED + f"[!] 貌似时光商店之前是有库存的!没关系,他们现在大概率没库存了 =v=" + Colors.RESET) 673 | print("请记录好以上信息。") 674 | 675 | print("最后……") 676 | 677 | print(Colors.GREEN + f"[+] 实际收益为:{income - cost}" + Colors.RESET) 678 | if new_remain_me: 679 | future_value = future_value_exp(countdown - 1, (new_remain_me, new_remain_rival)) 680 | print(Colors.GREEN + f"[+] 库存的未来期望收益为:{future_value}" + Colors.RESET) 681 | 682 | print("结束了!") 683 | action_confirm() 684 | --------------------------------------------------------------------------------