65.9K
CodeProject 正在变化。 阅读更多。
Home

一个 13x13 网格扑克牌型图 Windows Forms 用户控件

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.60/5 (5投票s)

2010年10月15日

LGPL3

6分钟阅读

viewsIcon

33834

downloadIcon

532

一个简单的 .NET 控件,用于显示两张牌扑克牌型的“标准”13x13 网格。

引言

我一直在玩扑克并编写自制工具,最近开始为朋友们编写一些,主要是教育和分析性的。我很快发现需要一个控件来显示特定牌型的相关信息,即标准的 13x13 牌图。

而且,由于这实际上很容易编码(比我最初想象的容易得多),并且我将 大量 使用它,所以编写一个通用的牌图以供我随心所欲地使用是有意义的。我想到其他人也可能发现这样的控件很有用,所以在这里我向大家展示它。

这是一个标准的 .NET Windows Forms 控件,用 C# 编写。我发现从源代码级别使用它非常容易,并且在下面进行了说明(基本上,复制并粘贴到您的项目中)。但是,由于它没有添加到工具箱(我对 .NET 用户控件的经验不是很多;如果可行,我很想知道),因此需要手动将几行代码添加到您希望图表显示的窗体中。我还提供了一个仅包含该控件的类库 DLL,已预先编译。

不是控件开发最佳实践的示例,而是一个有用的共享控件。

背景

如图所示,该控件实现了一个 13x13 的网格,可以轻松紧凑地显示各种德州扑克起手牌的属性。

PokerChartDemoEmpty.jpg

PokerChartDemo.jpg

顶部的图像显示了一个在设计时绘制的空白图表;底部的图像显示了所有口袋对都染成金色并显示 X 的图表。

大多数扑克玩家都熟悉这些网格;有关特定用法的示例,请参见 HU Nash Equilibrium Push/Fold 图表 此处

对角线以上的单元格代表同花牌型,对角线以下的单元格代表不同花牌型。

Using the Code

在没有将控件添加到工具箱的情况下,将图表添加到窗体(或其他容器)是一个简单的三步过程!

  1. 创建一个 Windows Forms 应用程序。
  2. 引用 DLL,PokerHandChart.csPokerHandChart.Designer.cs 这两个文件复制并粘贴到您的项目中(在解决方案资源管理器中)。
    • 如果复制了代码,您可能需要添加对 System.Drawing 的引用。
  3. 将以下代码添加到您的窗体的 .Designer.cs 文件中 - 是的,有些需要放在标记为“Windows Form Designer generated code”的区域内,这通常不是一个好主意,但这是将控件放置在窗体上的唯一方法 - 至少在不进行所有安装等的情况下(我是在 VS 2008 Express 中编写此代码的)- 它不支持用户控件项目,但此解决方案很简单。所以,代码如下:
  4. 在类级别声明一个类型为 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()' 方法)。所以请留意改进!

也许您可以将功能请求作为评论留下?

© . All rights reserved.