Skip to content
[OPEN_POKER]

扑克机器人位置范围:停止打开每个座位

JJoão Carvalho||已更新 |12 min read

你的扑克机器人不应在每个位置都采用相同的起手牌范围。在 6 人无限注德州扑克中,翻牌后按钮位最后行动,盲注位最先行动。位置差异会决定哪些牌能持续赢取筹码,哪些牌会悄悄蚕食筹码。

本篇属于2026 年 AI 扑克机器人完整构建指南,该核心指南涵盖框架、决策逻辑、胜率、测试与参赛平台。

核心要点

  • 位置范围是一个便宜的优势,因为它们可以在牌局变得昂贵之前修复翻牌前的错误。
  • 早到的座位需要紧张的开放。晚到的座位可能会更容易被抢走,因为剩下的玩家越来越少。
  • 首先将范围实现为手动代码集。仅在基线工作后添加对手建模。

为什么位置如此重要?

位置很重要,因为后来的玩家会根据更多信息做出决定。 Open Poker 自己的策略文档将早期位置、后期位置和盲注作为单独的决策上下文(操作和策略文档)。在 6 人桌游戏中,每个轨道有 6 个席位,在 10/20 结构的盲注中强制筹码 30 个。

机器人在枪口位用 KTo 开池时,身后还有五名玩家可以反击;在按钮位用同一手牌开池时,只剩两名盲注玩家尚未行动。牌相同,风险却完全不同。

这就是初学者机器人悄然失败的地方。他们建立一个单一的“hand_strength()”数字,然后在每个座位上使用它。这适用于 A 等明显的牌。它在决定大多数季节的手牌上失败了:同花连牌、弱 A、小对子和百老汇垃圾。

六个有用的座桶是什么?

使用六个存储桶:UTG、HJ、CO、BTN、SB 和 BB。 Open Poker 在“hand_start”中发送“dealer_seat”;你的机器人从“table_joined”中知道自己的座位,并且可以根据这两个数字计算相对位置(WebSocket 文档)。

POSITIONS_6MAX = ["SB", "BB", "UTG", "HJ", "CO", "BTN"]
 
 
def position_name(hero_seat, dealer_seat, active_seats):
    ordered = sorted(active_seats)
    dealer_index = ordered.index(dealer_seat)
    relative = ordered[(dealer_index + 1) % len(ordered):] + ordered[:dealer_index + 1]
 
    # relative[0] is small blind, relative[1] is big blind in a full hand.
    seat_to_position = {
        seat: POSITIONS_6MAX[i]
        for i, seat in enumerate(relative[: len(POSITIONS_6MAX)])
    }
    return seat_to_position[hero_seat]

真正的桌子可能会缺人。如果只有三个机器人就座,则向 BTN、SB 和 BB 逻辑崩溃。当只有三名玩家活跃时,不要假装有一个秘密座位。

第一个机器人应该使用什么开局范围?

初始范围应比直觉更紧。实用的新手基准可以是 UTG 12%、HJ 16%、CO 22%、BTN 35%,小盲位则保持谨慎。这些并非完美的求解器范围,但足以在翻牌后逻辑尚未成熟时堵住最严重的漏洞。

职位开放目标示例手
UTG12%77+、AJs+、KQs、AQo+
华杰16%66+、AT+、KJs+、QJs、AJo+
二氧化碳22%55+、A8s+、KTs+、QTs+、JTs、ATo+、KQo
BTN35%22+,最同花 A,百老汇,同花连牌
SB28%举起单挑打得好的牌,弃掉垃圾牌
BB以价卫基于底池赔率和手牌可玩性的跟注

确切的百分比比形状更重要。早紧。纽扣宽。百叶窗很奇怪。这种形状比另一种翻牌后启发式修复了更多的初学者机器人。

对于堆栈深度,请将这些范围与扑克机器人堆栈管理结合起来。 50bb 机器人和 250bb 机器人不应以同样的方式对待小对。

如何在 Python 中对范围进行编码?

将手牌编码为短字符串:AAAKsAQo。对有两个字母。同色牌以“s”结尾;非同花手以“o”结尾。这对于手写范围来说足够紧凑,并且易于在日志中调试。

RANK_ORDER = "23456789TJQKA"
 
 
def hand_code(cards):
    r1, s1 = cards[0][0], cards[0][1]
    r2, s2 = cards[1][0], cards[1][1]
 
    if r1 == r2:
        return r1 + r2
 
    high, low = sorted([r1, r2], key=RANK_ORDER.index, reverse=True)
    suited = "s" if s1 == s2 else "o"
    return high + low + suited
 
 
OPEN_RANGES = {
    "UTG": {"77", "88", "99", "TT", "JJ", "QQ", "KK", "AA", "AJs", "AQs", "AKs", "KQs", "AQo", "AKo"},
    "HJ": {"66", "77", "88", "99", "TT", "JJ", "QQ", "KK", "AA", "ATs", "AJs", "AQs", "AKs", "KJs", "KQs", "QJs", "AJo", "AQo", "AKo"},
    "CO": {"55", "66", "77", "88", "99", "TT", "JJ", "QQ", "KK", "AA", "A8s", "A9s", "ATs", "AJs", "AQs", "AKs", "KTs", "KJs", "KQs", "QTs", "QJs", "JTs", "ATo", "AJo", "AQo", "AKo", "KQo"},
    "BTN": {"22", "33", "44", "55", "66", "77", "88", "99", "TT", "JJ", "QQ", "KK", "AA", "A2s", "A3s", "A4s", "A5s", "A6s", "A7s", "A8s", "A9s", "ATs", "AJs", "AQs", "AKs", "K9s", "KTs", "KJs", "KQs", "Q9s", "QTs", "QJs", "J9s", "JTs", "T9s", "98s", "87s", "A9o", "ATo", "AJo", "AQo", "AKo", "KTo", "KJo", "KQo", "QJo"},
}
 
 
def should_open(position, cards):
    return hand_code(cards) in OPEN_RANGES.get(position, set())

这套逻辑看起来很粗糙,但简单正是它的优点。机器人弃掉边缘牌时,你可以打印 position=CO hand=KTo open=False,立刻看懂决策依据。

如何将范围与合法动作结合使用?

只有当前无人下注且加注属于合法动作时,机器人才应开池。Open Poker 会明确给出合法动作,包括 raise 的最小与最大金额。这里的加注金额指加注后的总额,而不是在现有下注上增加的差额,这是机器人常犯的错误(动作说明)。

def preflop_decision(msg, hole_cards, position):
    actions = {a["action"]: a for a in msg["valid_actions"]}
 
    # Free option in the big blind.
    if "check" in actions:
        return "check", None
 
    if "raise" in actions and should_open(position, hole_cards):
        return "raise", actions["raise"]["min"]
 
    # Facing a raise: use a tighter continue range for now.
    if "call" in actions and hand_code(hole_cards) in {"TT", "JJ", "QQ", "KK", "AA", "AQs", "AKs", "AKo"}:
        return "call", None
 
    return "fold", None

这个跟注范围刻意设得较紧。跟注过宽,是让一个尚可的翻牌前机器人在翻牌后迅速亏损的常见原因之一。加入蒙特卡罗胜率计算后,再根据底池赔率与对手倾向适当放宽跟注范围。

范围什么时候应该改变?

筹码深度、桌上人数或对手发生变化时,范围也应随之调整。Open Poker 的买入范围为 1,000 至 5,000 筹码,每个赛季以 5,000 筹码和固定 10/20 盲注开始(赛季文档)。因此,同一机器人可能面对 50bb、100bb 或 250bb 的不同深度。

使用三个调整:

背景调整
60bb 以下的短筹码删除投机同花连牌和小对子
深筹码超过 150bb在后面的位置添加同花连牌和对子
百叶窗松动加强抢断,加大价值下注
盲注位过紧放宽按钮位和关煞位的开池范围

不要第一天就同时加入全部四项调整。先证明基准范围优于旧的一刀切策略,再让对手建模逐步调整按钮位和盲注位。

如何测试新系列?

测试范围时一次只改一项。翻牌前调整看似细小,却会改变后续每个下注轮,因为机器人到达翻牌圈的牌组已经不同。如果一次部署同时放宽按钮位、扩大大盲防守并改变下注尺度,你将无法判断究竟哪项改动有效。

使用此测试循环:

  1. 选择一个位置,通常是BTN或BB。
  2. 在此范围内换手 5 至 10 手。 3、跑至少300手。
  3. 比较筹码趋势、重买和大输牌。
  4. 仅当日志解释了结果时才保留更改。

最快得到的信号不是总体胜率,而是“翻牌前入池后亏损超过 20bb 的手牌”。先筛出这些牌局。如果新按钮位范围增加了五组边缘非同花牌,而它们持续输掉过大底池,就撤回改动;如果它们经常偷到盲注且很少进入摊牌,则继续测试。

范围设计靠的是朴素而严格的纪律。好机器人不需要在翻牌前追求冒险创意,只需在前位少玩一些牌,在后位有控制地扩大压力。

常见问题解答

扑克机器人应该使用求解器完美的范围吗?

一开始不是。解算器范围假定特定的游戏树和对手响应。一个简单的 6-max 范围表更容易测试,更容易记录,并且通常比你的机器人在翻牌后无法玩的复制图表更好。

大盲注如何防守?

大盲注应该以价格来防守。如果在 90 筹码底池中跟注 20,您需要的赢率比在 300 筹码底池中跟注 200 少得多。从底池赔率开始,然后过滤掉翻牌后打得不好的牌。

无代码机器人应该使用什么范围?

从 The Shark 模板开始。Bot Builder 文档将其定义为紧凶风格,紧度 0.30、侵略度 0.75。对大多数新用户而言,它比松散模板更适合作为基准。

位置范围可以代替手牌评估吗?

不。范围决定翻牌前是否进入这手牌。手牌评估和胜率决定牌面出现后做什么。两者都用。

继续阅读