4

在过去的一年里,我一直在解析扑克手牌的历史,并且在一般的解析方面学到了很多东西。

我们从正则表达式开始,但很快意识到这不会轻易扩展。我们跳过了从 ruby​​ 到 c++ 的语言,最后意识到必须改变的是算法。

我们拿起了 Boost::Spirit 并看到我们的速度以我们原始速度的 10 倍以上的顺序急剧上升。然后我们跳到 java,目前正在使用 antlr 为每个站点创建语法。这绝对是迄今为止最快的方法,而且非常彻底,这很好,因为您确切地知道您在“完整”语法方面的立场。不幸的是,我花费了大量的时间来处理这些语法——它们工作得非常好,但还不完美。

无论如何,关于手头问题的背景已经足够了——是否有任何我不知道的“异国情调”或鲜为人知的解析技术?我只知道词法分析/解析语法和其他劣质正则表达式/循环方法。

对于那些不熟悉扑克手牌历史的人,我会发布一个,以便您了解结构是什么。

Full Tilt Poker Game #12037626529: Table durrrr (heads up, deep) - $500/$1000 -
Pot Limit Omaha Hi - 2:00:48 ET - 2009/05/05
Seat 1: durrrr ($196,456.50)
Seat 2: Gus Hansen ($65,499)
durrrr posts the small blind of $500
Gus Hansen posts the big blind of $1,000
The button is in seat #1
*** HOLE CARDS ***
durrrr raises to $3,000
Gus Hansen raises to $9,000
durrrr calls $6,000
*** FLOP *** [3d 4d 7d]
Gus Hansen has 15 seconds left to act
Gus Hansen checks
durrrr checks
*** TURN *** [3d 4d 7d] [Jh]
Gus Hansen checks
durrrr checks
*** RIVER *** [3d 4d 7d Jh] [Ah]
Gus Hansen has 15 seconds left to act
Gus Hansen checks
durrrr has 15 seconds left to act
123stayfree (Observer): GUS I NOW BRING U LUCK
durrrr bets $7,600
Gus Hansen has 15 seconds left to act
Gus Hansen has requested TIME
Hernandez777 (Observer): Gus has the super-duper nuts
Gus Hansen calls $7,600
Podobed45 (Observer): fluuuuuuuuuush
*** SHOW DOWN ***
durrrr shows [Kc 3s Qd As] two pair, Aces and Threes
Gus Hansen mucks
durrrr wins the pot ($33,199.50) with two pair, Aces and Threes
*** SUMMARY ***
Total pot $33,200 | Rake $0.50
Board: [3d 4d 7d Jh Ah]
Seat 1: durrrr (small blind) collected ($33,199.50)
Seat 2: Gus Hansen (big blind) mucked

我很清楚其他收集信息的方法(例如屏幕抓取和 dll 注入),但仍然需要将手牌历史转换为结构化数据,所以我只关注获取信息的方法,例如正则表达式/语法...

我想如果我找不到东西,我会用 ocamllex/ocamlyacc 重写我们的语法。

更新

仅供参考:正则表达式速度约为 60 手/秒,而语法处理 600+ 手/秒...在数据全部整理好后,整只手都转换为 xml... 需要 20-30 个正则表达式(在最后一次计数)对于您要解析的每个站点....语法方面的每个站点都有自己的语法,其中包含大量的词法分析器/解析器规则(但它的代码量仍然较小)

我确实有龙书并且一直在阅读它——这让我对使用 ocamllex/ocamlyacc 失去了兴趣……速度是这里游戏的名称……

4

8 回答 8

6

由于您正在寻找异国情调,请阅读有关 Vaughan Pratt 的自上而下运算符优先级的这篇文章......

http://javascript.crockford.com/tdop/tdop.html

于 2009-06-02T18:45:18.253 回答
4

解析器组合器是一种非常流行的用函数式语言(例如 Haskell)构建解析器的方法。

于 2009-06-02T17:57:59.973 回答
3

如果您希望最大限度地提高速度,那么您可能会更好地使用 OcamlYacc/FsYacc 而不是 ANTLR。OcamlYacc 创建 LL(1) 解析器,它通常比 ANTLR 样式的 LL(*) 解析器具有更好的性能(如果我错了,有人可以纠正我)。 [编辑添加:] 看起来有人纠正了我:OCamlYacc 生成 LALR(1) 解析器。我不能肯定地说 OcamlYacc 解析器是否比 ANTLR 解析器快。

OCaml/F# 是构建 DSL 的非常好的语言,在我看来比 Java 更适合这项工作,主要是因为它非常容易创建和遍历表示为联合数据结构的 AST。我推荐了本教程,该教程演示了如何在 F# 中解析 SQL。

于 2009-06-02T18:28:04.760 回答
2

你必须问自己,你真正想做的是玩解析器(诚然很有趣,而且我更喜欢我自己),或者你是否真的想在你的扑克机器人上完成工作。最有可能的是,异国情调的解析技术对于您需要的东西来说太过分了。只需选择具有一些简单易用的解析器的快速语言即可。您应该能够使用直接 C + flex 处理 10k 手/秒。或者,ocamllex + ocamlyacc 应该绰绰有余。如果你必须对你的代码进行 hadoopify,我认为你做错了什么。网络延迟应该最终成为您真正的瓶颈,而不是解析速度。你在什么机器上运行这个?

另一种选择是使用解析器生成器自动生成解析表,然后手动优化它,或者从 NFA 手动优化(虽然你可能不会节省太多,而且程序员时间的权衡可能不值得)。组合器解析可能会更慢。

平均而言,对于给定的等效功率语法,LL 将比 LALR 慢。特别是,如果扑克牌实际上可以被 LALR 解析器解析,那么 bison/byacc + flex 每次都会击败 ANTLR 牌。我个人对 menhir 非常满意,尽管与 godi + ocamlbuild 一起工作是一个疯狂的婊子。

——尼科

于 2009-06-12T17:11:13.267 回答
1

阅读龙书: http ://www.amazon.com/Compilers-Principles-Techniques-Alfred-Aho/dp/0201100886

它深入涵盖了词汇和句法分析(以及其他主题)。您可以使用它来帮助您理解您尝试解析的“语言”以确定最佳的解决方法。

于 2009-06-02T18:12:08.763 回答
1

维基百科对解析器类型有一个很好的概述,这里: http ://en.wikipedia.org/wiki/Parser

还有一个关于解析器生成器工具的比较,在这里:http ://en.wikipedia.org/wiki/Comparison_of_parser_generators

我认为GLR是一种鲜为人知的方法,它很有趣,因为它处理语言的歧义。

于 2009-06-02T18:13:41.897 回答
1

递归下降解析可能对您有用。它是非常可定制的。它可能比 yacc/antlr 慢一点,但可能足够快。基本思想:您将每个语法规则编码为一个函数。

于 2009-06-02T18:37:59.750 回答
1

由于您正在谈论使用 OCaml 进行解析,因此此页面概述了该语言的不同解析选项:

OCaml 语言的解析器生成器

如果您决定接受ocamlyacc(或menhir),这些教程可能比参考手册要容易一些:

于 2009-06-05T21:19:02.357 回答