在C++中评估桥牌手
Evaluating Bridge Hands in C++
我正在开发一个程序,该程序应该读取一个文件(文件中的每一行代表一手 13 张牌(并评估每张桥牌。
最后我会问我的具体问题,但由于这个程序有很多内容,我将包括所有说明,以便您了解所需的内容。
以下是将要读入的文本文件:
2C QD TC AD 6C 3D TD 3H 5H 7H AS JH KH
3C 4C 2D AC QC 7S 7C TD 9C 4D KS 8D 6C
2C 3C KC JC 4C 8C 7C QC AC 5C 9C 6C TC
5H 3S 4D KC 9S 3D 4S 8H JC TC 8S 2S 4C
2S 5D 6S 8S 9D 3C 2H TH
2H 6D %S 8S 7S 4D 3H 4S KS QH JH 5C 9S
2C QD TC AD 6C 3D TD 3C 5H 7H AS JH KD QS
2C QD TC AD 6C 3D TD 2C 5D 7H AS JH KD
2H 6D TS 8Z 7S 4D 3H 4S KS QD JH 5C 9S
每对代表一张牌(价值和花色(。
法律价值包括:
2-9
T(10), A(Ace), K(King), Q(Queen), and J(Jack)
和西装:
C(Clubs), S(Spades), D(Diamonds), and H(Hearts)
一旦文件被读入,每手牌必须首先按花色排序,然后按花色内的等级排序(王牌很高(。排序完成后,必须使用以下规则评估每只手牌:
Aces = 4
Kings = 3
Queens = 2
Jacks = 1
voids (no cards in a suit) = 3
singletons (one card in a suit) = 2
doubletons (two cards in a suit) = 1
long suits (more than 5 cards in a suit) = 1 count for each card over 5 in number
评估后,每只手应按以下格式显示:
Example Input:
2C QD TC AD 6C 3D TD 3H 5H 7H AS JH KH
Example Output:
Clubs 10 6 2
Diamonds A Q 10 3
Hearts K J 7 5 3
Spades A
Points = 16
以下是有关该计划必须包括的内容的一些细节:
1. A data structure to hold cards in an ordered manner.
2. A function to read in the hand.
3. A function to evaluate the hand (with support functions).
4. A function to display the hand.
这是我能够想出的小代码。如果不清楚,注释是我认为需要完成的步骤,以使程序正常工作。现在它所做的只是打开文件,是的,我将删除"文件已打开"消息,我只是想确保文件确实处于打开状态。
//#include <program3.h>
#include <iostream>
#include <string>
#include <fstream>
using namespace std;
int main() {
//Create Array
//char bridgeHands[];
//Open file, if it doesn't exist, exit the program
ifstream bridgeFile;
bridgeFile.open("prog3.dat");
if(!bridgeFile) {
cerr << "Open Failure" << endl;
exit(1);
}
else {
//Read file into array
//Sort array
//Evaluate hands
//Display hands
cout << "File is open" << endl;
}
return 0;
}
我想我现在的具体问题是这个。我需要如何创建和加载数组?我从未使用过从成对的输入加载数组。另外,这如何与数据结构一起使用?
我相信你现在已经知道我在这方面非常陌生,并且正在学习(几乎所有我知道如何在C++中做的事情都是用该代码编写的(,所以任何帮助都非常感谢。谢谢你的时间。
我脑海中有很多悬而未决的问题。 首先和最重要的是:每只手应该在单独的线上,还是只是接下来的 13 张牌,不考虑换行符。 这将更改你读手的方式。 无论哪种情况,您的输入文件都有错误必须检测:在第一种情况下,第五种和第七种行的格式不正确,在第二个行中,数量卡片不是 13 的倍数,因此必须存在错误地方。
无论如何,解决这个问题的正确方法是定义类型(类(为牌和手牌,并定义用户定义 每个operator>>
,手operator>>
使用一个用于卡片。 例如:
std::istream& operator>>( std::istream& source, Card& object)
{
char value;
char suit;
source >> std::ws; // skip leading whitespace.
source.get(value); // these do _not_ skip whitespace
source.get(suit);
if ( source ) { // no errors on input...
// Map the characters to the internal representation and write
// them into `object`. This operator may have to be a friend
// to do this.
//
// If one of the characters isn't legal:
// source.setstate( std::ios_base::failbit );
}
return source;
}
对于手,如果您的输入是面向线的,则最佳解决方案大概是用std::getline
来读行,那么 std::istringstream
解析它。 确保检查一旦你读完了13卡。 (如果输入忽略行尾,则只需读取 13卡应该足够了。 无论策略如何,都要确保每次读取后检查错误,然后再使用您已阅读的值。 所以你是循环(要么在 std::istringstream
或原始来源,取决于(可能看起来像这样:
int i = 0;
while ( i != 13 && source >> dest[i] ) {
++ i;
}
if ( i == 13 ) {
// Input of 13 cards succeeded...
}
最后:你的输入包含错误(可能是故意的,以确保正确测试它们(。 这意味着最简单的外部循环形式将无法正常工作(因为它将在第一个错误处停止(。 如果我们假设直线定向全局输入,但手的>>
运算符忽略行结束,只寻找下一张 13 张牌:
std::string line;
int lineNumber = 0;
while ( std::getline( source, line ) ) {
++ lineNumber;
std::istringstream parser( line );
if ( parser >> hand >> std::ws && parser.get() == EOF) {
// Line is good, hand contains the instance to be evaluated
} else {
std::cerr << "Input format error in line " << lineNumber << std::endl;
}
}
在if
中确认条件:我们读一手,然后跳过空白;如果成功,我们将验证我们已达到文件末尾(否则,在文件末尾有额外的垃圾行(。 您可以给出更详细的错误消息,如果您将这些不同的操作分开,尽管要表明哪张卡有误,您必须输入 13 张卡直接在此级别,而不是将>>
用于Hand
。
另一个建议:我会选择一个内部代表这使得处理变得简单,具有用于输入的映射功能和输出。 这可能是两个枚举:一个用于值(使用按排名顺序排列的值(,一个用于花色(也按其排名顺序(。 这将使排序并且计数明显更容易,映射功能是非常简单:对于这样的小集合,只不过是一个数组与法律代表:输入,线性搜索,以及在输出上,只是索引。 (请注意,这可能会导致值 2
在内部0
数值,因为它将是枚举的第一个值。
使用 ifstream::getline()
函数读取和分析文件。在此链接中,您还可以找到一个很好的例子,如何将文件直接读取到std::array
中:
#include <iostream>
#include <sstream>
#include <vector>
#include <array>
int main()
{
std::istringstream input("abc|def|gh");
std::vector<std::array<char, 4>> v;
// note: the following loop terminates when std::ios_base::operator bool()
// on the stream returned from getline() returns false
for (std::array<char, 4> a; input.getline(&a[0], 4, '|'); ) {
v.push_back(a);
}
for (auto& a : v) {
std::cout << &a[0] << 'n';
}
}
但请仔细查看这是否适合您的情况。作为替代方案,您可以省略getline
的最后一个参数,以便真正逐行获取。然后,您必须使用 std::string::find()
和 std::string::substr()
解析这些行。
- std::condition_variable::wait()如何评估给定的谓词
- c++11评估顺序(未定义的行为)
- 如何使用"equal to"以外的评估编写开关语句
- 嵌套 if 中没有返回评估
- 懒惰的参数评估try_emplace?
- 在实践中,在运行时为零的乘法中是否有任何"lazy"评估
- 如何改进一堆在已知值范围内评估变量的 else-if 条件?
- C++17:使用 std::optional 来评估枚举是否包含值
- CNTK:->转发或 ->评估某些电脑上的崩溃,而不是其他电脑上的崩溃
- ConstexPR :GCC比Clang更努力地评估ConstexPR
- C++:Constexpr斐波那契数列评估
- C++能保证论点评估的原子性吗?
- 在编译时评估函数开销的通用方法
- 如何使用 std::forward 精确地评估参数包的扩展?
- MSVC 在不知道类型的情况下评估上下文(和错误)
- C++评估顺序优化是否意味着对不同的操作数使用不同的内核?
- 条件分支评估
- C++ constexpr语言 - 可以在编译时评估值吗?
- 井字游戏:评估节点的启发式值
- 布尔值始终评估为真