fork download
  1. from collections import deque
  2. import math
  3. import random
  4. import time
  5.  
  6.  
  7. def play(gameState, memo={}):
  8. start_time = time.process_time()
  9. turn = gameState.currentTurn
  10. maxT = gameState.maxTurn
  11.  
  12. INF = 10 ** 9
  13. WIN = 100000
  14. PLYLIM = 44
  15.  
  16. # Quy ước lưới 20x9 có vùng đệm 1 ô xung quanh -> STRIDE = 22, SIZE = 242
  17. W = 20
  18. H = 9
  19. STRIDE = 22
  20. SIZE = 242
  21.  
  22. OFFS = (23, 22, 1, 21, -21, -1, -22, -23)
  23. DIRN = {21: 1, 22: 2, 23: 3, 1: 4, -21: 5, -22: 6, -23: 7, -1: 8}
  24.  
  25. BT = ((False, False, True), (True, False, False), (False, True, False))
  26. PRED = (1, 2, 0)
  27. PREY = (2, 0, 1)
  28. LO = (1, 11)
  29.  
  30. # Mở rộng bảng trọng số chạy đua lên 24 bước cho chiều dài map 20x9
  31. RT = (
  32. 0, 920, 520, 290, 170, 100, 65, 45, 32, 24,
  33. 18, 14, 10, 8, 6, 4, 3, 2, 1, 0, 0, 0, 0, 0, 0
  34. )
  35. UNSTOP_RT = (
  36. 0, 1650, 1050, 680, 440, 290, 195, 135, 95, 68,
  37. 48, 34, 24, 17, 12, 8, 5, 3, 1, 0, 0, 0, 0, 0, 0
  38. )
  39.  
  40. PASS_ON = True
  41. PASS_SLEEP = 3.4
  42. PASS_ROOT = 10
  43. PASS_IN = 8
  44. ELIM1 = 65
  45. ELIM2 = 0
  46. PASSM = (-1, 0, -1, -1, 0)
  47.  
  48. # Xác định hướng xuất phát (trái hay phải khi xoay 180 độ)
  49. ally_list = list(gameState.ally)
  50. left_side = (sum(p.x for p in ally_list) <= 10 * max(1, len(ally_list)))
  51.  
  52. restarted = ('tabs' not in memo) and turn > 1
  53. if restarted:
  54. memo['pc'] = 3
  55.  
  56. tabs = memo.get('tabs')
  57. if tabs is None or memo.get('left_side') != left_side:
  58. memo['left_side'] = left_side
  59.  
  60. # Đặt cứng 2 khối tường đen (7x3 ô) và dải 5 cờ mục tiêu của map 20x9
  61. if left_side:
  62. WALL_SET = frozenset(
  63. y * STRIDE + x for x in range(13, 20) for y in (1, 2, 3, 7, 8, 9)
  64. )
  65. GOAL0 = frozenset(y * STRIDE + 20 for y in range(3, 8))
  66. GOAL1 = frozenset(y * STRIDE + 12 for y in range(3, 8))
  67. else:
  68. WALL_SET = frozenset(
  69. y * STRIDE + x for x in range(2, 9) for y in (1, 2, 3, 7, 8, 9)
  70. )
  71. GOAL0 = frozenset(y * STRIDE + 1 for y in range(3, 8))
  72. GOAL1 = frozenset(y * STRIDE + 9 for y in range(3, 8))
  73.  
  74. GOAL = (GOAL0, GOAL1)
  75. cells = [
  76. y * STRIDE + x
  77. for y in range(1, H + 1)
  78. for x in range(1, W + 1)
  79. if (y * STRIDE + x) not in WALL_SET
  80. ]
  81. valid_set = set(cells)
  82.  
  83. nb0_set = {g + off for g in GOAL0 for off in OFFS if (g + off) in valid_set and (g + off) not in GOAL0}
  84. nb1_set = {g + off for g in GOAL1 for off in OFFS if (g + off) in valid_set and (g + off) not in GOAL1}
  85. NB = (tuple(nb0_set), tuple(nb1_set))
  86. DEF_SQ = (GOAL0 | nb0_set, GOAL1 | nb1_set)
  87.  
  88. # BFS tính khoảng cách ngắn nhất vòng qua tường tới dải 5 cờ (D0, D1)
  89. MAX_D = 40
  90. D0 = [MAX_D] * SIZE
  91. dq = deque(GOAL0)
  92. for g in GOAL0:
  93. D0[g] = 0
  94. while dq:
  95. u = dq.popleft()
  96. du = D0[u] + 1
  97. for off in OFFS:
  98. v = u + off
  99. if v in valid_set and du < D0[v]:
  100. D0[v] = du
  101. dq.append(v)
  102.  
  103. D1 = [MAX_D] * SIZE
  104. dq = deque(GOAL1)
  105. for g in GOAL1:
  106. D1[g] = 0
  107. while dq:
  108. u = dq.popleft()
  109. du = D1[u] + 1
  110. for off in OFFS:
  111. v = u + off
  112. if v in valid_set and du < D1[v]:
  113. D1[v] = du
  114. dq.append(v)
  115.  
  116. # BFS tính khoảng cách săn đuổi né tường giữa mọi cặp ô hợp lệ (DT, MDT)
  117. DT = [[MAX_D] * SIZE for _ in range(SIZE)]
  118. MDT = [[MAX_D * 2] * SIZE for _ in range(SIZE)]
  119. for src in cells:
  120. row = DT[src]
  121. mrow = MDT[src]
  122. row[src] = 0
  123. mrow[src] = 0
  124. dq = deque([src])
  125. while dq:
  126. u = dq.popleft()
  127. du = row[u] + 1
  128. for off in OFFS:
  129. v = u + off
  130. if v in valid_set and du < row[v]:
  131. row[v] = du
  132. mrow[v] = du * 2
  133. dq.append(v)
  134.  
  135. max_d0 = max((D0[a] for a in cells if D0[a] < MAX_D), default=1)
  136. max_d1 = max((D1[a] for a in cells if D1[a] < MAX_D), default=1)
  137. ADV0 = [0] * SIZE
  138. ADV1 = [0] * SIZE
  139. CENTER = [0] * SIZE
  140. for a in cells:
  141. x = a % STRIDE
  142. y = a // STRIDE
  143. ADV0[a] = max(0, max_d0 - D0[a])
  144. ADV1[a] = max(0, max_d1 - D1[a])
  145. cx = abs(x - 10.5)
  146. cy = abs(y - 5.0)
  147. CENTER[a] = max(0, int(4 - max(cx / 2.0, cy)))
  148.  
  149. MTAB0 = [() for _ in range(SIZE)]
  150. MTAB1 = [() for _ in range(SIZE)]
  151. for a in cells:
  152. m0 = []
  153. m1 = []
  154. for off in OFFS:
  155. q = a + off
  156. if q in valid_set:
  157. h_ix = a * SIZE + q
  158. fw0_b = (D0[a] - D0[q]) * 2
  159. fw1_b = (D1[a] - D1[q]) * 2
  160. m0.append((q, fw0_b, h_ix, 1 if q in nb0_set else 0))
  161. m1.append((q, fw1_b, h_ix, 1 if q in nb1_set else 0))
  162. m0.sort(key=lambda item: item[1], reverse=True)
  163. m1.sort(key=lambda item: item[1], reverse=True)
  164. MTAB0[a] = tuple(m0)
  165. MTAB1[a] = tuple(m1)
  166. MTAB = (tuple(MTAB0), tuple(MTAB1))
  167.  
  168. rz = random.Random(20260402)
  169. Z = tuple(tuple(rz.getrandbits(52) for _ in range(SIZE)) for _ in range(20))
  170. ZS = rz.getrandbits(52)
  171. PASSK = rz.getrandbits(52)
  172. tabs = (WALL_SET, GOAL, NB, DEF_SQ, DT, MDT, ADV0, ADV1, D0, D1, CENTER, MTAB, Z, ZS, PASSK)
  173. memo['tabs'] = tabs
  174.  
  175. WALL_SET, GOAL, NB, DEF_SQ, DT, MDT, ADV0, ADV1, D0, D1, CENTER, MTAB, Z, ZS, PASSK = tabs
  176.  
  177. used = memo.get('used', 0.0)
  178. left = max(1, (maxT - turn) // 2 + 1)
  179. if turn <= 1:
  180. budget = 0.82
  181. else:
  182. budget = min(0.81, max(0.04, (155.0 - used) / min(left, 150)))
  183. deadline = start_time + budget
  184.  
  185. # Dựng bàn cờ 20x9: ngoài biên và ô tường đen đều là -1
  186. board = [-1] * SIZE
  187. for yy in range(1, H + 1):
  188. base_y = yy * STRIDE
  189. for xx in range(1, W + 1):
  190. pos = base_y + xx
  191. if pos not in WALL_SET:
  192. board[pos] = 0
  193.  
  194. tp = [0] * 20
  195. ps = [-1] * 20
  196. TI = {'R': 0, 'P': 1, 'S': 2}
  197. cnt = [0, 0]
  198. for p in ally_list:
  199. c = p.pid
  200. tp[c] = TI[p.Type]
  201. pos = p.y * STRIDE + p.x
  202. ps[c] = pos
  203. board[pos] = c
  204. cnt[0] += 1
  205. for p in gameState.opponent:
  206. c = 10 + p.pid
  207. tp[c] = TI[p.Type]
  208. pos = p.y * STRIDE + p.x
  209. ps[c] = pos
  210. board[pos] = c
  211. cnt[1] += 1
  212.  
  213. tt = memo.get('tt')
  214. if tt is None or len(tt) > 120000 or turn <= 1:
  215. tt = {}
  216. memo['tt'] = tt
  217.  
  218. HIST_SIZE = SIZE * SIZE
  219. HIST = memo.get('hist')
  220. if HIST is None or len(HIST) != HIST_SIZE or turn <= 1:
  221. HIST = [0] * HIST_SIZE
  222. memo['hist'] = HIST
  223. else:
  224. for i in range(HIST_SIZE):
  225. if HIST[i]:
  226. HIST[i] >>= 1
  227.  
  228. KILLER = [None] * 64
  229. nodes = [0]
  230. abort = [False]
  231.  
  232. total = cnt[0] + cnt[1]
  233. if memo.get('prev_total') != total:
  234. memo['prev_total'] = total
  235. memo['capt_turn'] = turn
  236. memo['cfg'] = {}
  237. stag = (turn - memo.get('capt_turn', turn)) // 2
  238. ahead = cnt[0] > cnt[1]
  239. behind = cnt[0] < cnt[1]
  240.  
  241. K = 5 + min(8, turn // 25)
  242. if not behind and stag > 16:
  243. K += min(7, (stag - 16) // 6)
  244. if behind:
  245. HW = 3
  246. elif stag > 16:
  247. HW = 11
  248. else:
  249. HW = 6
  250. if ahead and stag > 26:
  251. DP = (0, 220, 120, 55)
  252. else:
  253. DP = (0, 330, 175, 80)
  254.  
  255. roles = {}
  256. e_types_alive = [0, 0, 0]
  257. e_near_home = []
  258. e_near_away = [0, 0, 0]
  259. for c in range(11, 20):
  260. q = ps[c]
  261. if q >= 0:
  262. u = tp[c]
  263. e_types_alive[u] += 1
  264. if D1[q] <= 4:
  265. e_near_home.append((D1[q], q, u))
  266. if D0[q] <= 2:
  267. e_near_away[u] += 1
  268. e_near_home.sort()
  269.  
  270. def_assigned = set()
  271. for d_h, q_h, u_h in e_near_home:
  272. need_t = PRED[u_h]
  273. best_c = 0
  274. best_d = 99
  275. for c in range(1, 10):
  276. p = ps[c]
  277. if p >= 0 and tp[c] == need_t and c not in def_assigned:
  278. d_c = D1[p]
  279. if d_c < best_d:
  280. best_d = d_c
  281. best_c = c
  282. if best_c:
  283. roles[best_c] = 'DEFENDER'
  284. def_assigned.add(best_c)
  285.  
  286. if not def_assigned:
  287. best_c = 0
  288. best_d = 99
  289. for c in range(1, 10):
  290. p = ps[c]
  291. if p >= 0 and e_types_alive[PREY[tp[c]]] > 0:
  292. d_c = D1[p]
  293. if d_c < best_d:
  294. best_d = d_c
  295. best_c = c
  296. if best_c and best_d <= 3:
  297. roles[best_c] = 'DEFENDER'
  298. def_assigned.add(best_c)
  299.  
  300. runner_cands = []
  301. for c in range(1, 10):
  302. p = ps[c]
  303. if p >= 0 and c not in def_assigned:
  304. t = tp[c]
  305. imm = 1 if e_types_alive[PRED[t]] == 0 else 0
  306. brk = 1 if e_near_away[PREY[t]] > 0 else 0
  307. runner_cands.append((D0[p] - 2 * imm - brk, -ADV0[p], c))
  308. runner_cands.sort()
  309. for idx_r in range(min(2, len(runner_cands))):
  310. roles[runner_cands[idx_r][2]] = 'RUNNER'
  311. for c in range(1, 10):
  312. if ps[c] >= 0 and c not in roles:
  313. roles[c] = 'HUNTER'
  314. memo['roles'] = roles
  315.  
  316. def wins_now(s):
  317. lo = LO[s]
  318. hi = lo + 8
  319. for g in GOAL[s]:
  320. v0 = board[g]
  321. if v0 == 0:
  322. for off in OFFS:
  323. v = board[g + off]
  324. if lo <= v <= hi:
  325. return True
  326. else:
  327. t = tp[v0]
  328. for off in OFFS:
  329. v = board[g + off]
  330. if lo <= v <= hi and BT[tp[v]][t]:
  331. return True
  332. return False
  333.  
  334. def gen(s, mode):
  335. res = []
  336. lo = LO[s]
  337. elo = LO[1 - s]
  338. ehi = elo + 8
  339. mtab = MTAB[s]
  340. gset = GOAL[s]
  341. egset = GOAL[1 - s]
  342. for c in range(lo, lo + 9):
  343. p = ps[c]
  344. if p < 0:
  345. continue
  346. t = tp[c]
  347. bt = BT[t]
  348. for q, fw_b, h_ix, is_nb in mtab[p]:
  349. v = board[q]
  350. if v == 0:
  351. if mode == 0:
  352. h = HIST[h_ix]
  353. res.append((fw_b + (h if h < 72 else 72), c, p, q, 0))
  354. elif mode == 2 and is_nb:
  355. for off in OFFS:
  356. gq = q + off
  357. if gq in gset:
  358. vg = board[gq]
  359. if vg == 0 or (elo <= vg <= ehi and bt[tp[vg]]):
  360. res.append((820 + fw_b, c, p, q, 0))
  361. break
  362. elif elo <= v <= ehi:
  363. ut = tp[v]
  364. if bt[ut]:
  365. res.append((1050 + fw_b + (90 if q in egset or D1[q] <= 2 else 0), c, p, q, v))
  366. return res
  367.  
  368. def evaluate_raw(s):
  369. A_p = []
  370. A_t = []
  371. B_p = []
  372. B_t = []
  373. cA0 = cA1 = cA2 = 0
  374. cB0 = cB1 = cB2 = 0
  375. for c in range(1, 10):
  376. p = ps[c]
  377. if p >= 0:
  378. t = tp[c]
  379. A_p.append(p)
  380. A_t.append(t)
  381. if t == 0:
  382. cA0 += 1
  383. elif t == 1:
  384. cA1 += 1
  385. else:
  386. cA2 += 1
  387. for c in range(11, 20):
  388. p = ps[c]
  389. if p >= 0:
  390. t = tp[c]
  391. B_p.append(p)
  392. B_t.append(t)
  393. if t == 0:
  394. cB0 += 1
  395. elif t == 1:
  396. cB1 += 1
  397. else:
  398. cB2 += 1
  399.  
  400. na = len(A_p)
  401. nb = len(B_p)
  402. if na == 0:
  403. return -WIN + 100 if s == 0 else WIN - 100
  404. if nb == 0:
  405. return WIN - 100 if s == 0 else -WIN + 100
  406.  
  407. cA = (cA0, cA1, cA2)
  408. cB = (cB0, cB1, cB2)
  409.  
  410. v = 1050 * (na - nb) + 3200 * (na - nb) // (na + nb)
  411.  
  412. for t in (0, 1, 2):
  413. pred = PRED[t]
  414. prey = PREY[t]
  415. ca = cA[t]
  416. cb = cB[t]
  417. if ca:
  418. if cB[pred] == 0:
  419. v += ca * (500 if cB[t] == 0 else 360)
  420. elif cB[pred] == 1 and cA[prey] > 0:
  421. v += ca * ELIM1
  422. elif ELIM2 and cB[pred] == 2 and cA[prey] >= 2:
  423. v += ca * ELIM2
  424. v += ca * (80 * cB[prey] if cB[prey] else -50)
  425. if cb:
  426. if cA[pred] == 0:
  427. v -= cb * (500 if cA[t] == 0 else 360)
  428. elif cA[pred] == 1 and cB[prey] > 0:
  429. v -= cb * ELIM1
  430. elif ELIM2 and cA[pred] == 2 and cB[prey] >= 2:
  431. v -= cb * ELIM2
  432. v -= cb * (80 * cA[prey] if cA[prey] else -50)
  433.  
  434. far_d = 40
  435. ha = [far_d] * na
  436. pa = [far_d] * na
  437. ma = [far_d * 2] * na
  438. inta = [99] * na
  439. hb = [far_d] * nb
  440. pb = [far_d] * nb
  441. mb = [far_d * 2] * nb
  442. intb = [99] * nb
  443.  
  444. for i in range(na):
  445. p = A_p[i]
  446. t = A_t[i]
  447. d0p = D0[p]
  448. row = DT[p]
  449. mrow = MDT[p]
  450. bt = BT[t]
  451. for j in range(nb):
  452. q = B_p[j]
  453. u = B_t[j]
  454. d0q = D0[q]
  455. d1q = D1[q]
  456. if u == t:
  457. if d0q <= d0p and d0q < inta[i]:
  458. inta[i] = d0q
  459. if D1[p] <= d1q and D1[p] < intb[j]:
  460. intb[j] = D1[p]
  461. continue
  462. d = row[q]
  463. md = mrow[q]
  464. if bt[u]:
  465. if d < pa[i]:
  466. pa[i] = d
  467. if md < ma[i]:
  468. ma[i] = md
  469. if d < hb[j]:
  470. hb[j] = d
  471. if D1[p] <= d1q + 1 and D1[p] < intb[j]:
  472. intb[j] = D1[p]
  473. else:
  474. if d < ha[i]:
  475. ha[i] = d
  476. if d < pb[j]:
  477. pb[j] = d
  478. if md < mb[j]:
  479. mb[j] = md
  480. if d0q <= d0p + 1 and d0q < inta[i]:
  481. inta[i] = d0q
  482.  
  483. adv0 = 0
  484. thr0 = 0
  485. dg0 = 0
  486. hunt0 = 0
  487. hang0 = 0
  488. away_guard_b = [0, 0, 0]
  489. for j in range(nb):
  490. if D0[B_p[j]] <= 2:
  491. away_guard_b[B_t[j]] = 1
  492.  
  493. max_unstop = len(UNSTOP_RT) - 1
  494. max_rt = len(RT) - 1
  495.  
  496. for i in range(na):
  497. p = A_p[i]
  498. t = A_t[i]
  499. ap = ADV0[p]
  500. if cB[PRED[t]] == 0:
  501. ap += ap >> 1
  502. if away_guard_b[PREY[t]]:
  503. ap += max(0, 14 - D0[p]) * 3
  504. adv0 += ap
  505.  
  506. mp = pa[i]
  507. if mp < far_d:
  508. hunt0 += HW * max(0, 16 - mp) + max(0, 32 - ma[i])
  509. else:
  510. hunt0 += CENTER[p]
  511.  
  512. mh = ha[i]
  513. if mh <= 3:
  514. pt = PREY[t]
  515. row = DT[p]
  516. prot = False
  517. for k in range(na):
  518. if A_t[k] == pt and row[A_p[k]] <= 1:
  519. prot = True
  520. break
  521. if not prot:
  522. if mh <= 1:
  523. dg0 += DP[1] + (160 if s == 1 else 0)
  524. hang0 += 1
  525. else:
  526. dg0 += DP[mh]
  527. elif mh <= 2:
  528. hunt0 += 25
  529.  
  530. d = D0[p]
  531. if inta[i] == 99:
  532. if d <= max_unstop:
  533. tv = UNSTOP_RT[d]
  534. if tv > thr0:
  535. thr0 = tv
  536. elif d <= max_rt:
  537. tv = RT[d]
  538. if mh <= 2 or inta[i] <= d:
  539. tv //= 3
  540. if tv > thr0:
  541. thr0 = tv
  542.  
  543. if hang0 >= 2:
  544. dg0 += 380 * (hang0 - 1)
  545.  
  546. adv1 = 0
  547. thr1 = 0
  548. dg1 = 0
  549. hunt1 = 0
  550. hang1 = 0
  551. home_guard_a = [0, 0, 0]
  552. for i in range(na):
  553. if D1[A_p[i]] <= 2:
  554. home_guard_a[A_t[i]] = 1
  555.  
  556. for j in range(nb):
  557. q = B_p[j]
  558. u = B_t[j]
  559. aq = ADV1[q]
  560. if cA[PRED[u]] == 0:
  561. aq += aq >> 1
  562. if home_guard_a[PREY[u]]:
  563. aq += max(0, 14 - D1[q]) * 3
  564. adv1 += aq
  565.  
  566. mp = pb[j]
  567. if mp < far_d:
  568. hunt1 += HW * max(0, 16 - mp) + max(0, 32 - mb[j])
  569. else:
  570. hunt1 += CENTER[q]
  571.  
  572. mh = hb[j]
  573. if mh <= 3:
  574. pt = PREY[u]
  575. row = DT[q]
  576. prot = False
  577. for k in range(nb):
  578. if B_t[k] == pt and row[B_p[k]] <= 1:
  579. prot = True
  580. break
  581. if not prot:
  582. if mh <= 1:
  583. dg1 += DP[1] + (160 if s == 0 else 0)
  584. hang1 += 1
  585. else:
  586. dg1 += DP[mh]
  587. elif mh <= 2:
  588. hunt1 += 25
  589.  
  590. d = D1[q]
  591. if intb[j] == 99:
  592. if d <= max_unstop:
  593. tv = UNSTOP_RT[d]
  594. if tv > thr1:
  595. thr1 = tv
  596. elif d <= max_rt:
  597. tv = RT[d]
  598. if mh <= 2 or intb[j] <= d:
  599. tv //= 3
  600. if tv > thr1:
  601. thr1 = tv
  602.  
  603. if hang1 >= 2:
  604. dg1 += 380 * (hang1 - 1)
  605.  
  606. v += K * (adv0 - adv1) + (thr0 - thr1) - (dg0 - dg1) + (hunt0 - hunt1)
  607.  
  608. has_useful_def = False
  609. for i in range(na):
  610. if D1[A_p[i]] <= 2 and cB[PREY[A_t[i]]] > 0:
  611. has_useful_def = True
  612. break
  613.  
  614. near_cnt = 0
  615. for j in range(nb):
  616. d = D1[B_p[j]]
  617. if d <= 2:
  618. v -= 520 * (3 - d)
  619. near_cnt += 1
  620. if intb[j] == 99:
  621. v -= 450 * (3 - d)
  622. elif d == 3:
  623. v -= 110
  624. if intb[j] == 99:
  625. v -= 220
  626. elif d == 4:
  627. v -= 35
  628.  
  629. if near_cnt >= 2:
  630. v -= 420 * (near_cnt - 1)
  631. if near_cnt >= 1 and not has_useful_def:
  632. v -= 420 * near_cnt
  633. if has_useful_def:
  634. v += 135 + 105 * near_cnt
  635.  
  636. return v if s == 0 else -v
  637.  
  638. evc = {}
  639.  
  640. def evaluate(s, h):
  641. r = evc.get(h)
  642. if r is None:
  643. r = evaluate_raw(s)
  644. evc[h] = r
  645. return r
  646.  
  647. def qsearch(s, alpha, beta, ply, qd, h):
  648. nodes[0] += 1
  649. if (nodes[0] & 63) == 0 and (time.process_time() > deadline or time.process_time() - start_time > 0.85):
  650. abort[0] = True
  651. if abort[0]:
  652. return 0
  653. if wins_now(s):
  654. return WIN - ply
  655. o = 1 - s
  656. in_chk = wins_now(o)
  657. if in_chk:
  658. if qd >= 4:
  659. return -WIN + ply + 1
  660. all_m = gen(s, 0)
  661. def_sq = DEF_SQ[o]
  662. evasions = [m for m in all_m if m[3] in def_sq]
  663. if not evasions:
  664. return -WIN + ply + 1
  665. evasions.sort(reverse=True)
  666. best = -WIN + ply + 1
  667. for m in evasions:
  668. c = m[1]
  669. p = m[2]
  670. q = m[3]
  671. cap = m[4]
  672. board[p] = 0
  673. board[q] = c
  674. ps[c] = q
  675. h2 = h ^ Z[c][p] ^ Z[c][q] ^ ZS
  676. if cap:
  677. ps[cap] = -1
  678. cnt[o] -= 1
  679. h2 ^= Z[cap][q]
  680. still_w = wins_now(o)
  681. if not still_w:
  682. if cap and cnt[o] == 0:
  683. val = WIN - ply
  684. else:
  685. val = -qsearch(o, -beta, -alpha, ply + 1, qd + 1, h2)
  686. else:
  687. val = -WIN + ply + 1
  688. if cap:
  689. cnt[o] += 1
  690. ps[cap] = q
  691. board[q] = cap
  692. board[p] = c
  693. ps[c] = p
  694. if abort[0]:
  695. return 0
  696. if val > best:
  697. best = val
  698. if val > alpha:
  699. alpha = val
  700. if alpha >= beta:
  701. break
  702. return best
  703.  
  704. stand = evaluate(s, h)
  705. if stand >= beta:
  706. return stand
  707. if stand > alpha:
  708. alpha = stand
  709. if qd >= 6:
  710. return stand
  711. moves = gen(s, 2 if qd == 0 else 1)
  712. if not moves:
  713. return stand
  714. moves.sort(reverse=True)
  715. for m in moves:
  716. c = m[1]
  717. p = m[2]
  718. q = m[3]
  719. cap = m[4]
  720. board[p] = 0
  721. board[q] = c
  722. ps[c] = q
  723. h2 = h ^ Z[c][p] ^ Z[c][q] ^ ZS
  724. if cap:
  725. ps[cap] = -1
  726. cnt[o] -= 1
  727. h2 ^= Z[cap][q]
  728. if cap and cnt[o] == 0:
  729. val = WIN - ply
  730. else:
  731. val = -qsearch(o, -beta, -alpha, ply + 1, qd + 1, h2)
  732. if cap:
  733. cnt[o] += 1
  734. ps[cap] = q
  735. board[q] = cap
  736. board[p] = c
  737. ps[c] = p
  738. if abort[0]:
  739. return 0
  740. if val > stand:
  741. stand = val
  742. if val > alpha:
  743. alpha = val
  744. if alpha >= beta:
  745. break
  746. return stand
  747.  
  748. def search(s, depth, alpha, beta, ply, h, pp=0):
  749. nodes[0] += 1
  750. if (nodes[0] & 63) == 0 and (time.process_time() > deadline or time.process_time() - start_time > 0.85):
  751. abort[0] = True
  752. if abort[0]:
  753. return 0
  754. if wins_now(s):
  755. return WIN - ply
  756. o = 1 - s
  757. in_chk = wins_now(o)
  758. if depth <= 0:
  759. if in_chk and ply < PLYLIM:
  760. depth = 1
  761. else:
  762. return qsearch(s, alpha, beta, ply, 0, h)
  763. a0 = alpha
  764. ttm = None
  765. hk = (h ^ PASSK) if pp else h
  766. e = tt.get(hk)
  767. if e is not None:
  768. ed, ef, ev, em = e
  769. if ev > WIN - 1000:
  770. ev -= ply
  771. elif ev < -WIN + 1000:
  772. ev += ply
  773. ttm = em
  774. if ed >= depth:
  775. if ef == 0:
  776. return ev
  777. if ef == 1:
  778. if ev >= beta:
  779. return ev
  780. elif ev <= alpha:
  781. return ev
  782. moves = gen(s, 0)
  783. if not moves:
  784. return -WIN + ply + 1 if in_chk else evaluate(s, h)
  785. if in_chk:
  786. def_sq = DEF_SQ[o]
  787. moves = [m for m in moves if m[3] in def_sq]
  788. if not moves:
  789. return -WIN + ply + 1
  790.  
  791. moves.sort(reverse=True)
  792. km = KILLER[ply] if ply < 64 else None
  793. if km is not None or ttm is not None:
  794. for i in range(len(moves)):
  795. m = moves[i]
  796. if ttm is not None and m[1] == ttm[0] and m[2] == ttm[1] and m[3] == ttm[2]:
  797. if i:
  798. moves.insert(0, moves.pop(i))
  799. break
  800. if km is not None:
  801. for i in range(1, len(moves)):
  802. m = moves[i]
  803. if m[1] == km[0] and m[2] == km[1] and m[3] == km[2]:
  804. moves.insert(1 if ttm is not None else 0, moves.pop(i))
  805. break
  806.  
  807. best = -WIN + ply + 1 if in_chk else -INF
  808. bm = None
  809. idx = 0
  810. nb_set = DEF_SQ[s]
  811. for m in moves:
  812. c = m[1]
  813. p = m[2]
  814. q = m[3]
  815. cap = m[4]
  816. board[p] = 0
  817. board[q] = c
  818. ps[c] = q
  819. h2 = h ^ Z[c][p] ^ Z[c][q] ^ ZS
  820. if cap:
  821. ps[cap] = -1
  822. cnt[o] -= 1
  823. h2 ^= Z[cap][q]
  824. if in_chk and wins_now(o):
  825. val = -WIN + ply + 1
  826. elif cap and cnt[o] == 0:
  827. val = WIN - ply
  828. else:
  829. if idx == 0:
  830. val = -search(o, depth - 1, -beta, -alpha, ply + 1, h2)
  831. else:
  832. red = 1 if (idx >= 4 and depth >= 3 and not cap and not in_chk and q not in nb_set) else 0
  833. if idx >= 12 and depth >= 5 and red:
  834. red = 2
  835. val = -search(o, depth - 1 - red, -alpha - 1, -alpha, ply + 1, h2)
  836. if val > alpha and not abort[0]:
  837. val = -search(o, depth - 1, -beta, -alpha, ply + 1, h2)
  838. if cap:
  839. cnt[o] += 1
  840. ps[cap] = q
  841. board[q] = cap
  842. board[p] = c
  843. ps[c] = p
  844. if abort[0]:
  845. return 0
  846. if val > best:
  847. best = val
  848. bm = (c, p, q)
  849. if val > alpha:
  850. alpha = val
  851. if alpha >= beta:
  852. if not cap:
  853. HIST[p * SIZE + q] += depth * depth
  854. if ply < 64:
  855. KILLER[ply] = bm
  856. break
  857. idx += 1
  858.  
  859. if PASS_ON and not pp and not in_chk and alpha < beta and ply < 40:
  860. val = -search(o, depth - 1, -beta - PASS_IN, -alpha - PASS_IN, ply + 1, h ^ ZS, 1) - PASS_IN
  861. if abort[0]:
  862. return 0
  863. if val > best:
  864. best = val
  865. bm = None
  866. if val > alpha:
  867. alpha = val
  868.  
  869. sv = best
  870. if sv > WIN - 1000:
  871. sv += ply
  872. elif sv < -WIN + 1000:
  873. sv -= ply
  874. if best <= a0:
  875. fl = 2
  876. elif best >= beta:
  877. fl = 1
  878. else:
  879. fl = 0
  880. tt[hk] = (depth, fl, sv, bm)
  881. return best
  882.  
  883. def decide():
  884. root = gen(0, 0)
  885. if not root:
  886. return (0, 0)
  887.  
  888. gset0 = GOAL[0]
  889. for m in root:
  890. if m[3] in gset0 or (m[4] and cnt[1] == 1):
  891. return (m[1], DIRN[m[3] - m[2]])
  892.  
  893. if wins_now(1):
  894. safe = []
  895. for m in root:
  896. c0 = m[1]
  897. p0 = m[2]
  898. q0 = m[3]
  899. cap0 = m[4]
  900. board[p0] = 0
  901. board[q0] = c0
  902. ps[c0] = q0
  903. if cap0:
  904. ps[cap0] = -1
  905. cnt[1] -= 1
  906. if not wins_now(1):
  907. safe.append(m)
  908. if cap0:
  909. cnt[1] += 1
  910. ps[cap0] = q0
  911. board[q0] = cap0
  912. board[p0] = c0
  913. ps[c0] = p0
  914. if safe:
  915. root = safe
  916.  
  917. if len(root) == 1:
  918. return (root[0][1], DIRN[root[0][3] - root[0][2]])
  919.  
  920. h0 = 0
  921. for c in range(1, 20):
  922. if ps[c] >= 0:
  923. h0 ^= Z[c][ps[c]]
  924.  
  925. seen = memo.setdefault('seen', {})
  926. cfg = memo.setdefault('cfg', {})
  927. pen_unit = 130 + 2 * min(turn, 200)
  928. cfg_unit = (45 + 4 * stag) * (0.25 if behind else 1.0)
  929.  
  930. order = []
  931. for m in root:
  932. c = m[1]
  933. p = m[2]
  934. q = m[3]
  935. cap = m[4]
  936. t = tp[c]
  937. pred_t = PRED[t]
  938. prey_t = PREY[t]
  939. role = roles.get(c, 'HUNTER')
  940. tb = m[0] * 10
  941. if cap:
  942. tb += 5000
  943.  
  944. min_pred_p = 99
  945. min_pred_q = 99
  946. min_prey_q = 99
  947. row_p = DT[p]
  948. row_q = DT[q]
  949. for ec in range(11, 20):
  950. ep = ps[ec]
  951. if ep >= 0 and ec != cap:
  952. et = tp[ec]
  953. if et == pred_t:
  954. if row_p[ep] < min_pred_p:
  955. min_pred_p = row_p[ep]
  956. if row_q[ep] < min_pred_q:
  957. min_pred_q = row_q[ep]
  958. elif et == prey_t:
  959. if row_q[ep] < min_prey_q:
  960. min_prey_q = row_q[ep]
  961. if min_pred_p == 1 and min_pred_q > 1:
  962. tb += 350
  963. if min_pred_q == 1:
  964. tb -= 600
  965. if role == 'RUNNER':
  966. tb += (D0[p] - D0[q]) * 45 + (ADV0[q] - ADV0[p]) * 20
  967. elif role == 'DEFENDER':
  968. tb += (D1[p] - D1[q]) * 35
  969. else:
  970. tb += max(0, 18 - min_prey_q) * 25
  971. order.append((tb, m))
  972. order.sort(reverse=True)
  973. order = [x[1] for x in order]
  974.  
  975. pens = {}
  976. for m in order:
  977. c = m[1]
  978. p = m[2]
  979. q = m[3]
  980. cap = m[4]
  981. board[p] = 0
  982. board[q] = c
  983. ps[c] = q
  984. if cap:
  985. ps[cap] = -1
  986. key = tuple(ps)
  987. ck = tuple(ps[1:10])
  988. if cap:
  989. ps[cap] = q
  990. board[q] = cap
  991. board[p] = c
  992. ps[c] = p
  993. pens[(c, p, q)] = min(750, int(pen_unit * seen.get(key, 0) + cfg_unit * cfg.get(ck, 0)))
  994.  
  995. can_pass = (
  996. PASS_ON and turn > 1 and memo.get('pc', 0) < 2 and (155.0 - used) > 15
  997. and not wins_now(1) and not wins_now(0)
  998. )
  999.  
  1000. best_move = order[0]
  1001. for depth in range(1, 42):
  1002. best_adj = -INF
  1003. cur_best = None
  1004. done = 0
  1005. vals = []
  1006. for m in order:
  1007. if time.process_time() - start_time > 0.85:
  1008. abort[0] = True
  1009. break
  1010. c = m[1]
  1011. p = m[2]
  1012. q = m[3]
  1013. cap = m[4]
  1014. pen = pens[(c, p, q)]
  1015. araw = best_adj + pen if best_adj > -INF else -INF
  1016. board[p] = 0
  1017. board[q] = c
  1018. ps[c] = q
  1019. h2 = h0 ^ Z[c][p] ^ Z[c][q] ^ ZS
  1020. if cap:
  1021. ps[cap] = -1
  1022. cnt[1] -= 1
  1023. h2 ^= Z[cap][q]
  1024. val = -search(1, depth - 1, -INF, -araw if araw > -INF else INF, 1, h2)
  1025. if cap:
  1026. cnt[1] += 1
  1027. ps[cap] = q
  1028. board[q] = cap
  1029. board[p] = c
  1030. ps[c] = p
  1031. if abort[0]:
  1032. break
  1033. done += 1
  1034. adj = val - pen if val < WIN - 1000 else val
  1035. vals.append((adj, m))
  1036. if adj > best_adj:
  1037. best_adj = adj
  1038. cur_best = m
  1039.  
  1040. if can_pass and cur_best is not None and not abort[0]:
  1041. araw = best_adj + PASS_ROOT if best_adj > -INF else -INF
  1042. val = -search(1, depth - 1, -INF, -araw if araw > -INF else INF, 1, h0 ^ ZS, 1)
  1043. if not abort[0]:
  1044. adj = val - PASS_ROOT if val < WIN - 1000 else val
  1045. vals.append((adj, PASSM))
  1046. if adj > best_adj:
  1047. best_adj = adj
  1048. cur_best = PASSM
  1049.  
  1050. if cur_best is not None and (not abort[0] or done >= 1):
  1051. best_move = cur_best
  1052. if not abort[0]:
  1053. vals.sort(key=lambda z: z[0], reverse=True)
  1054. order = [t_item[1] for t_item in vals if t_item[1] is not PASSM]
  1055. elif cur_best is not PASSM:
  1056. order.remove(cur_best)
  1057. order.insert(0, cur_best)
  1058. if abort[0]:
  1059. break
  1060. if best_adj > WIN - 1000 or best_adj < -WIN + 1000:
  1061. break
  1062. if time.process_time() > deadline or time.process_time() - start_time > 0.85:
  1063. break
  1064.  
  1065. if best_move is PASSM:
  1066. memo['pc'] = memo.get('pc', 0) + 1
  1067. memo['used'] = used + (time.process_time() - start_time)
  1068. time.sleep(PASS_SLEEP)
  1069. return (0, 0)
  1070.  
  1071. memo['pc'] = 0
  1072. c = best_move[1]
  1073. p = best_move[2]
  1074. q = best_move[3]
  1075. cap = best_move[4]
  1076. board[p] = 0
  1077. board[q] = c
  1078. ps[c] = q
  1079. if cap:
  1080. ps[cap] = -1
  1081. key = tuple(ps)
  1082. seen[key] = seen.get(key, 0) + 1
  1083. ck = tuple(ps[1:10])
  1084. cfg[ck] = cfg.get(ck, 0) + 1
  1085. return (c, DIRN[q - p])
  1086.  
  1087. try:
  1088. res = decide()
  1089. except Exception:
  1090. res = (0, 0)
  1091. bestk = -INF
  1092. for p in gameState.ally:
  1093. for d in range(1, 9):
  1094. dx, dy = ((-1, 1), (0, 1), (1, 1), (1, 0), (1, -1), (0, -1), (-1, -1), (-1, 0))[d - 1]
  1095. nx = p.x + dx
  1096. ny = p.y + dy
  1097. if nx < 1 or nx > W or ny < 1 or ny > H or (ny * STRIDE + nx) in WALL_SET:
  1098. continue
  1099. ok = True
  1100. for a in gameState.ally:
  1101. if a.x == nx and a.y == ny:
  1102. ok = False
  1103. for e in gameState.opponent:
  1104. if e.x == nx and e.y == ny:
  1105. if not ((p.Type == 'R' and e.Type == 'S') or (p.Type == 'S' and e.Type == 'P') or (p.Type == 'P' and e.Type == 'R')):
  1106. ok = False
  1107. if ok and ADV0[ny * STRIDE + nx] > bestk:
  1108. bestk = ADV0[ny * STRIDE + nx]
  1109. res = (p.pid, d)
  1110.  
  1111. memo['used'] = used + (time.process_time() - start_time)
  1112. return res
Success #stdin #stdout 0.07s 14408KB
stdin
Standard input is empty
stdout
Standard output is empty