一个 13x13 网格扑克牌型图 Windows Forms 用户控件
一个简单的 .NET 控件,用于显示两张牌扑克牌型的“标准”13x13 网格。
引言
我一直在玩扑克并编写自制工具,最近开始为朋友们编写一些,主要是教育和分析性的。我很快发现需要一个控件来显示特定牌型的相关信息,即标准的 13x13 牌图。
而且,由于这实际上很容易编码(比我最初想象的容易得多),并且我将 大量 使用它,所以编写一个通用的牌图以供我随心所欲地使用是有意义的。我想到其他人也可能发现这样的控件很有用,所以在这里我向大家展示它。
这是一个标准的 .NET Windows Forms 控件,用 C# 编写。我发现从源代码级别使用它非常容易,并且在下面进行了说明(基本上,复制并粘贴到您的项目中)。但是,由于它没有添加到工具箱(我对 .NET 用户控件的经验不是很多;如果可行,我很想知道),因此需要手动将几行代码添加到您希望图表显示的窗体中。我还提供了一个仅包含该控件的类库 DLL,已预先编译。
这不是控件开发最佳实践的示例,而是一个有用的共享控件。
背景
如图所示,该控件实现了一个 13x13 的网格,可以轻松紧凑地显示各种德州扑克起手牌的属性。
顶部的图像显示了一个在设计时绘制的空白图表;底部的图像显示了所有口袋对都染成金色并显示 X 的图表。
大多数扑克玩家都熟悉这些网格;有关特定用法的示例,请参见 HU Nash Equilibrium Push/Fold 图表 此处。
对角线以上的单元格代表同花牌型,对角线以下的单元格代表不同花牌型。
Using the Code
在没有将控件添加到工具箱的情况下,将图表添加到窗体(或其他容器)是一个简单的三步过程!
- 创建一个 Windows Forms 应用程序。
- 引用 DLL,或 将 PokerHandChart.cs 和 PokerHandChart.Designer.cs 这两个文件复制并粘贴到您的项目中(在解决方案资源管理器中)。
- 如果复制了代码,您可能需要添加对
System.Drawing
的引用。 - 将以下代码添加到您的窗体的 .Designer.cs 文件中 - 是的,有些需要放在标记为“Windows Form Designer generated code”的区域内,这通常不是一个好主意,但这是将控件放置在窗体上的唯一方法 - 至少在不进行所有安装等的情况下(我是在 VS 2008 Express 中编写此代码的)- 它不支持用户控件项目,但此解决方案很简单。所以,代码如下:
在类级别声明一个类型为 PokerHandChart
的成员变量,并将其余部分放在 InitializeComponent()
方法中,位于现有代码下方。
private PokerHandChartControl.PokerHandChart chart = null;
this.SuspendLayout();
// 1st and last line may already be there,
// so just place next 4 lines between
this.chart = new PokerHandChartControl.PokerHandChart();
this.chart.Location = new System.Drawing.Point(10, 120);
this.chart.Size = new System.Drawing.Size(200, 200); // (200, 100) wouldn't matter
this.Controls.Add(this.chart);
this.ResumeLayout(false);
注意:尺寸的确切大小并不重要,因为控件会自动变成正方形 - 您现在可以在窗体设计器中移动/调整控件的大小。
另外,添加此代码不会干扰将来在窗体上放置其他“标准”控件。您输入的此代码在您在窗体上调整控件大小/移动控件时将会更改(并被添加到) - 这只是为了在窗体上创建一个实例。控件会绘制一个空的 13x13 网格,并用卡片标记每一行/列... 完成此操作后,切换到您刚添加 PokerHandChart
的任何窗体的“设计”选项卡,您将看到一个空白图表。您现在可以移动和调整图表控件的大小,并注意到它始终保持为正方形。
注意:使用图表极其简单。
网格中的每个单元格都公开了属性,以允许控制单元格的显示。每个单元格都有一个前景和背景颜色,以及“DisplayValue
”(一个简单的 string
- 但它应该适合单元格!)您可以更改其字体(注意,仅限名称,此版本不支持字体大小,也许以后 ;-))。此外,每个单元格都有一个“Selected
”标签,用于选择牌型(例如,一个范围)- 至少标记已由用户或控件选择的牌型。列出卡片的标题也有可配置的颜色和字体(同样,不支持字体大小)。
标题行/列和每个单元格的字体大小是单元格大小的一个固定比例,因此会随着图表的整体大小而缩放。
每个单元格的值在图表中都水平和垂直居中显示。
这些属性的访问是通过一个公开这些属性的 GridCell
类来实现的。
我认为让这个图表控件特别易于使用的一个“特性”是每个单元格的索引器式访问器(仅获取)。有三种不同的索引器方法可用。
最简单的方法是使用一个包含牌型的 string
,例如,要获取代表 AKs 的单元格,我们可以使用 this["AKs"]
- 还有比这更简单的吗!嗯,通常,我们想访问许多单元格,通常在一个循环中,这时第二个索引器非常有用。它接受三个参数,即两张牌(作为 char
)和一个布尔值,以指示同花性。所以,再次,要访问 AKs,我们将使用 this['A', 'K', true]
。显然,对于口袋对,bool
被忽略。此外,编写 this['K', 'A', true]
将返回与之前相同的 GridCell
对象,因此该类“规范化”了牌型。因此,对于许多单元格的特殊本地访问,结合循环(或两个)的 this
访问器是最简单的方法。事实上,每个口袋对和同花牌型单元格都可以用几行代码访问(并且数组/枚举“ranks”对此有所帮助)。
foreach (char r1 in Hand.ranks)
foreach (char r2 in Hands.ranks)
if ( Hands.indexFor(r1) >= Hands.indexFor(r2) ) {
// So AA, AK but not KA,
//even though that would work it would
//visit most cells more than once, wasteful...
GridCell c = chart[r1, r2, suited];
c.DisplayValue = "11.5";
c.Foreground = Brushes.Blue;
c.CellFont = "Arial";
}
(使一个单元格显示“11.5”,背景为蓝色。)[Hands.indexFor(card)
是一个允许按等级比较牌的方法。]
最后,可以通过标准的数字坐标访问单元格,其中 AA 为 (0,0),AKs 为 (1, 0),依此类推。这是为了(半)完整性;我还没有使用它。
每个单元格都在类中自动创建和维护。开发人员只需要提供显示数据,如颜色,以及要在单元格中放置的一些文本或数字。
该控件还导出一个 Click 风格的事件,当用户单击其中一个单元格时触发。实际的 GridCell
对象会传递给任何订阅的事件侦听器。
chart.HandClickedEvent += HandClicked;
protected void HandClicked(object sender, GridCell hit_cell) { ... }
因此,该控件可以用于显示静态数据,也可以用于允许用户选择牌型/范围。
例如,有一些枚举,用于所有口袋对和所有 A-K 牌型,使得选择这些组非常容易。
foreach (string s in HandEnumerations.PocketPairs)
GridCell c = chart[s]; // Do something to each of these cells...
注意:在对图表进行任何更改后,必须调用 'UPDATE()
' - 无论是对图表本身还是对包含的窗体/容器!
唯一接受参数的枚举工厂方法是 SuitedConnector
/SuitedGapper
,您可以在其中提供手牌集合的下限(例如,所有 SC > 4?)以及间隔的距离。
还可以使用枚举器顺序访问每个单元格,并提供一些实用程序类(例如 HandEnumerations
)以方便使用。
尽情享用!
历史
- 版本 0.1.0 - 还没有,但我计划扩展一些“助手”类并添加我能想到的任何功能 ;-)
我想看看这个想法的响应程度,然后再投入太多精力(除了我需要的)来完善这个控件,但如果兴趣足够,我有很多事情可以做(例如一些重构/重命名/扩展)...(例如,现在显然缺少一个 'Clear()
' 方法)。所以请留意改进!
也许您可以将功能请求作为评论留下?