📄 hand.cpp
字号:
if (tmp.GoMahjong_real()) {
*this = tmp;
return true;
}
}
tmp = *this;
if (tmp.Chow(t, CHOW_UPPER, true, HT_RON)) {
if (tmp.GoMahjong_real()) {
*this = tmp;
return true;
}
}
tmp = *this;
if (tmp.Chow(t, CHOW_MIDDLE, true, HT_RON)) {
if (tmp.GoMahjong_real()) {
*this = tmp;
return true;
}
}
tmp = *this;
for (int j = 0; j < m_iNumTiles; j++) {
if (m_Tiles[j].flags & (HT_LOCKED | HT_TOCHOW))
continue;
if (m_Tiles[j].tile == t) {
tmp.AddTile(t, HT_PAIR | HT_RON | HT_FROMOPPONENT, tmp.m_iNumTileSets);
tmp.m_Tiles[j].flags |= (HT_PAIR | HT_RON);
tmp.m_Tiles[j].tileset = tmp.m_iNumTileSets;
// Add this pair to the tileset
tmp.m_TileSets[tmp.m_iNumTileSets].first = tmp.m_Tiles[j].tile;
tmp.m_TileSets[tmp.m_iNumTileSets].type = (HT_PAIR | HT_RON);
tmp.m_iNumTileSets++;
if (tmp.GoMahjong_real()) {
*this = tmp;
return true;
}
break;
}
}
// If all above fail, check if we have Thirteen Unique
// Wonders or Seven Pairs...
tmp = *this;
tmp.AddTile(t, HT_FROMOPPONENT);
if (tmp.ThirteenWonders()) {
*this = tmp;
return true;
}
if (tmp.SevenPairs()) {
*this = tmp;
return true;
}
return false; // does NOT have a Mahjong
}
// Check if we have "Thirteen Unique Wonders" special hand.
bool CHand::ThirteenWonders()
{
const CTile ttw[] = {"1C", "9C", "1D", "9D", "1B", "9B",
"EW", "SW", "WW", "NW", "RD", "GD", "WD"};
bool havetwo = false;
int i, j;
// first check if all the tiles are majors...
for (j = 0; j < m_iNumTiles; j++) {
if (!m_Tiles[j].tile.IsMajor())
return false; // we have minors; fail
}
for (i = 0; i < 13; i++) {
int count = 0;
for (j = 0; j < m_iNumTiles; j++) {
if (m_Tiles[j].tile == ttw[i]) {
count++;
}
}
if (count <= 0 || count > 2) {
return false; // we have 3 or more same tiles; fail
}
if (count == 2) {
if (havetwo) {
return false;
}
havetwo = true;
}
}
// MUST have one pair
if (havetwo) {
// Success. Set the "Thirteen Wonders" flag to all tiles
for (i = 0; i < m_iNumTiles; i++) {
m_Tiles[i].flags |= HT_THIRTEENWONDERS;
}
return true;
}
return false; // fail!
}
// Check if we have "Seven Pairs" special hand.
bool CHand::SevenPairs()
{
if (m_iNumTiles <= 0)
return true;
if (m_iNumTileSets > 0)
return false; // non-concealed hand is not possible
CHand tmp = *this;
CTile t = m_Tiles[0].tile;
// three or more same tiles is not allowed!
if (tmp.Pung(t, false))
return false;
tmp.RemoveTile(t);
if (tmp.RemoveTile(t)) {
if (tmp.SevenPairs()) {
// FIXME: add the seven pairs to the tileset?
for (int i = 0; i < m_iNumTiles; i++) {
m_Tiles[i].flags |= HT_PAIR;
}
return true;
}
}
return false;
}
// Return true if the hand in its current state of
// organization is a ready hand.
// (That is, we only need one more tile to go mah-jong.)
bool CHand::IsReady()
{
int i, concealed = 0;
CTile t[MAX_HANDTILE];
for (i = 0; i < m_iNumTiles; i++) {
if (m_Tiles[i].flags & (HT_LOCKED | HT_TOCHOW))
continue; // skip locked tiles
CHand tmp;
tmp = *this;
if (tmp.Pung(m_Tiles[i].tile, false)) {
if (tmp.IsReady()) {
return true;
}
}
tmp = *this;
if (tmp.Chow(m_Tiles[i].tile, CHOW_LOWER, false)) {
if (tmp.IsReady()) {
return true;
}
}
t[concealed++] = m_Tiles[i].tile;
}
if (concealed == 1) {
// only 1 tile remaining; can form a pair with another tile
return true;
} else if (concealed == 4) {
// check if we have 1 pair and another 2 tiles which can
// form a chew or pung with another tile.
// search for a pair
int m, n, other[2], count = 0;
for (m = 0; m < 4; m++) {
for (n = m + 1; n < 4; n++) {
if (m == n)
continue;
if (t[m] == t[n]) {
break; // we've found the pair
}
}
if (n < 4)
break; // break out if we've already found the pair
}
if (m >= 4 || n >= 4)
return false; // no pair found; fail
for (i = 0; i < 4; i++) {
if (i != m && i != n) {
assert(count < 2);
other[count++] = i;
}
}
assert(count == 2);
// If the other 2 tiles are not of the same suit...
if (t[other[0]].GetSuit() != t[other[1]].GetSuit())
return false; // fail!
int d = abs(t[other[0]].GetValue() - t[other[1]].GetValue());
return (d >= 0 && d < 3);
}
if (IsThirteenWondersReady())
return true;
if (IsSevenPairsReady())
return true;
return false; // does NOT have a Ready Hand
}
bool CHand::IsThirteenWondersReady()
{
const CTile ttw[] = {"1C", "9C", "1D", "9D", "1B", "9B",
"EW", "SW", "WW", "NW", "RD", "GD", "WD"};
bool havetwo = false;
int i, j;
// first check if all the tiles are majors...
for (j = 0; j < m_iNumTiles; j++) {
if (!m_Tiles[j].tile.IsMajor())
return false; // we have minors; fail
}
for (i = 0; i < 13; i++) {
int count = 0;
for (j = 0; j < m_iNumTiles; j++) {
if (m_Tiles[j].tile == ttw[i]) {
count++;
}
}
if (count > 2) {
return false; // we have 3 or more same tiles; fail
} else if (count == 2) {
if (havetwo) {
return false;
}
havetwo = true;
}
}
return true; // Success.
}
bool CHand::IsSevenPairsReady()
{
if (m_iNumTiles <= 1)
return true;
if (m_iNumTileSets > 0)
return false; // non-concealed hand is not possible
CHand tmp = *this;
CTile t = m_Tiles[0].tile;
tmp.RemoveTile(t);
if (tmp.RemoveTile(t)) {
if (tmp.RemoveTile(t)) {
// three or more same tiles is not allowed!
return false;
}
} else {
t = m_Tiles[1].tile;
tmp = *this;
tmp.RemoveTile(t);
if (tmp.RemoveTile(t)) {
if (tmp.RemoveTile(t)) {
// three or more same tiles is not allowed!
return false;
}
} else {
return false; // 2 or more "orphaned" tiles are found
}
}
return tmp.IsSevenPairsReady();
}
// Gets the waiting tiles, store it into the tiles array
// and returns the number of found waiting tiles.
int CHand::GetWaitingTile(CTile tiles[], int max)
{
int current = 0;
return GetWaitingTile(tiles, max, current);
}
// This is the real function to get the waiting tiles.
int CHand::GetWaitingTile(CTile tiles[], int max, int ¤t)
{
int i, j, concealed = 0;
CTile t[MAX_HANDTILE];
for (i = 0; i < m_iNumTiles; i++) {
if (m_Tiles[i].flags & (HT_LOCKED | HT_TOCHOW))
continue; // skip locked tiles
CHand tmp;
tmp = *this;
if (tmp.Pung(m_Tiles[i].tile, false)) {
tmp.GetWaitingTile(tiles, max, current);
}
tmp = *this;
if (tmp.Chow(m_Tiles[i].tile, CHOW_LOWER, false)) {
tmp.GetWaitingTile(tiles, max, current);
}
t[concealed++] = m_Tiles[i].tile;
}
if (concealed == 1) {
// only 1 tile remaining; can form a pair with another tile
for (j = 0; j < current; j++) {
if (tiles[j] == t[0])
break;
}
if (j >= current) {
if (current >= max) {
fprintf(stderr, "CHand::GetWaitingTile(): current >= max!\n");
return current;
}
tiles[current++] = t[0];
}
} else if (concealed == 4) {
// check if we have 1 pair and another 2 tiles which can
// form a chew or pung with another tile.
// search for a pair
int m, n, other[2], count = 0;
for (m = 0; m < 4; m++) {
for (n = m + 1; n < 4; n++) {
if (m == n)
continue;
if (t[m] == t[n]) {
break; // we've found the pair
}
}
if (n < 4)
break; // break out if we've already found the pair
}
if (m >= 4 || n >= 4)
return current; // no pair found; fail
for (i = 0; i < 4; i++) {
if (i != m && i != n) {
assert(count < 2);
other[count++] = i;
}
}
assert(count == 2);
// If the other 2 tiles are not of the same suit...
if (t[other[0]].GetSuit() != t[other[1]].GetSuit())
return current; // fail!
if (t[other[0]].GetValue() > t[other[1]].GetValue()) {
int temp = other[0];
other[0] = other[1];
other[1] = temp;
}
int d = t[other[1]].GetValue() - t[other[0]].GetValue();
assert(d >= 0);
switch (d) {
case 0:
for (j = 0; j < current; j++) {
if (tiles[j] == t[other[0]])
break;
}
if (j >= current) {
if (current >= max) {
fprintf(stderr, "CHand::GetWaitingTile(): current >= max!\n");
return current;
}
tiles[current++] = t[other[0]];
}
break;
case 1:
if (t[other[0]].GetSuit() & (TILESUIT_WIND | TILESUIT_DRAGON)) {
break; // chow is impossible for Winds or Dragons
}
if (t[other[0]].GetValue() > 1) {
for (j = 0; j < current; j++) {
if (tiles[j] == t[other[0]]() - 1)
break;
}
if (j >= current) {
if (current >= max) {
fprintf(stderr, "CHand::GetWaitingTile(): current >= max!\n");
return current;
}
tiles[current++] = t[other[0]]() - 1;
}
}
if (t[other[1]].GetValue() < 9) {
for (j = 0; j < current; j++) {
if (tiles[j] == t[other[1]]() + 1)
break;
}
if (j >= current) {
if (current >= max) {
fprintf(stderr, "CHand::GetWaitingTile(): current >= max!\n");
return current;
}
tiles[current++] = t[other[1]]() + 1;
}
}
break;
case 2:
if (t[other[0]].GetSuit() & (TILESUIT_WIND | TILESUIT_DRAGON)) {
break; // chow is impossible for Winds or Dragons
}
for (j = 0; j < current; j++) {
if (tiles[j] == t[other[0]]() + 1)
break;
}
if (j >= current) {
if (current >= max) {
fprintf(stderr, "CHand::GetWaitingTile(): current >= max!\n");
return current;
}
tiles[current++] = t[other[0]]() + 1;
}
break;
}
}
if (current <= 0) {
GetThirteenWondersWaitingTile(tiles, max, current);
}
if (current <= 0) {
GetSevenPairsWaitingTile(tiles, max, current);
}
return current;
}
int CHand::GetThirteenWondersWaitingTile(CTile tiles[], int max, int ¤t)
{
const CTile ttw[] = {"1C", "9C", "1D", "9D", "1B", "9B",
"EW", "SW", "WW", "NW", "RD", "GD", "WD"};
int i, j, zero = -1;
bool havetwo = false;
// first check if all the tiles are majors...
for (i = 0; i < m_iNumTiles; i++) {
if (!m_Tiles[i].tile.IsMajor())
return current; // we have minors; fail
}
for (i = 0; i < 13; i++) {
int count = 0;
for (j = 0; j < m_iNumTiles; j++) {
if (m_Tiles[j].tile == ttw[i]) {
count++;
}
}
if (count > 2) {
return current; // we have 3 or more same tiles; fail
} else if (count == 2) {
if (havetwo) {
return current; // fail
}
havetwo = true;
} else if (count == 0) {
zero = i;
}
}
if (!havetwo) {
// we're waiting for ALL majors!
for (i = 0; i < 13; i++) {
if (current >= max) {
fprintf(stderr, "CHand::GetThirteenWondersWaitingTile(): current >= max\n");
return current;
}
tiles[current++] = ttw[i];
}
} else if (zero != -1) {
if (current >= max) {
fprintf(stderr, "CHand::GetThirteenWondersWaitingTile(): current >= max\n");
return current;
}
tiles[current++] = ttw[zero];
}
return current; // success!
}
int CHand::GetSevenPairsWaitingTile(CTile tiles[], int max, int ¤t)
{
assert(m_iNumTiles >= 1);
if (m_iNumTiles == 1) {
// We've got the wanted tile
if (current >= max) {
fprintf(stderr, "CHand::GetSevenPairsWaitingTile(): current >= max\n");
return current;
}
tiles[current++] = m_Tiles[0].tile;
return current;
}
if (m_iNumTileSets > 0)
return current; // non-concealed hand is not possible
CHand tmp = *this;
CTile t = m_Tiles[0].tile;
tmp.RemoveTile(t);
if (tmp.RemoveTile(t)) {
if (tmp.RemoveTile(t)) {
return current; // three or more same tiles is not allowed!
}
} else {
t = m_Tiles[1].tile;
tmp = *this;
tmp.RemoveTile(t);
if (tmp.RemoveTile(t)) {
if (tmp.RemoveTile(t)) {
return current; // three or more same tiles is not allowed!
}
} else {
return current; // 2 or more "orphaned" tiles are found
}
}
return tmp.GetSevenPairsWaitingTile(tiles, max, current);
}
// Return true if the hand in its current state of
// organization is a concealed hand.
bool CHand::IsConcealed()
{
for (int i = 0; i < m_iNumTileSets; i++) {
if (m_TileSets[i].type & (HT_OPEN & ~HT_CLOSEDKONG)) {
if (m_TileSets[i].type & HT_RON)
continue;
return false; // it is NOT a concealed hand
}
}
return true; // it is a concealed hand
}
void CHand::Restore()
{
int i, n = 0;
const int flag = (HT_CLOSEDPUNG | HT_CLOSEDCHOW |
HT_PAIR | HT_THIRTEENWONDERS);
for (i = 0; i < m_iNumTiles; i++) {
m_Tiles[i].flags &= ~flag;
}
for (i = 0; i < m_iNumTileSets; i++) {
if (m_TileSets[i].type & flag)
continue;
m_TileSets[n++] = m_TileSets[i];
}
m_iNumTileSets = n;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -