# HW04 參考答案
## 4.1 Sorting
Credit: 41047029S 林O可 (TA)
:::spoiler `mysort.c`
```c=
#include "mysort.h"
#include <inttypes.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
// 1. All even numbers should be before odd numbers.
// 2. All odd numbers are in ascending order.
// 3. All even numbers are in descending order.
// if x and y should be swapped, return 1
int _cmp(const void *a, const void *b) {
// cast to int64_t to avoid overflow on edge cases
int64_t x = *(int32_t *)a;
int64_t y = *(int32_t *)b;
bool x_is_even = (x < 0 ? -x : x) % 2 == 0;
bool y_is_even = (y < 0 ? -y : y) % 2 == 0;
if (x_is_even && y_is_even) {
return y > x ? 1 : -1;
} else if (!x_is_even && !y_is_even) {
return x > y ? 1 : -1;
} else {
return y_is_even ? 1 : -1;
}
}
void mysort(int32_t array[], int32_t size) {
qsort(array, size, sizeof(int32_t), _cmp);
}
void myprint(int32_t array[], int32_t size) {
for (size_t i = 0; i < size; ++i) {
printf("%" PRId32 " ", array[i]);
}
printf("\n");
}
```
:::
## 4.2 Differential of a Function
Credit: 41247001S 盧O安
:::spoiler Code
```c
#include <math.h>
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <time.h>
static int64_t flowed = 0;
void sisiu(int64_t array1[],int64_t array2[],int64_t a,int64_t b){
int64_t num = -1;
for(int64_t i= 0;i<=a;i++){
if(array1[i]!=0){
num = array1[i] > 0 ? array1[i]:-array1[i];
break;
}
}
if(num==-1)return;
//printf("%d",num);
for(int64_t i=2;i<=num;i++){
int32_t done = 1;
for(int64_t j=0;j<=a;j++){
if(array1[j]%i){
done = 0;
break;
}
}
for(int64_t j=0;j<=b;j++){
if(array2[j]%i){
done = 0;
break;
}
}
if(done){
for(int64_t j=0;j<=a;j++) array1[j] /= i;
for(int64_t j=0;j<=b;j++) array2[j] /= i;
num /= i;
i -= 1;
}
}
}
void output_line(int64_t a){
while(a){
printf("-");
a -= 1;
}
printf("\n");
}
void countflowed(int64_t array1[],int64_t array2[],int64_t a,int64_t b){
while(flowed <= a && flowed <= b){
if(array1[flowed] == array2[flowed] && array2[flowed] == 0) flowed += 1;
else return;
}
}
int64_t number_length(int64_t target){
if(target<0) target *= -1;
if(target>9) return number_length(target/10) + 1;
if(target) return 1;
return 0;
}
int64_t countline(int64_t array1[],int64_t array2[],int64_t a,int64_t b){
int64_t bigger[2];
bigger[0] = 0;
bigger[1] = 0;
int64_t las = 1;
for(int64_t i=a;i>=0;i--){
if(array1[i]){
if(!las && array1[i] != 0)bigger[0] += 1;
else if(las&&array1[i]<0) bigger[0] += 1;
if(i != 0 && array1[i]!=1 && array1[i]!=-1)bigger[0] += number_length(array1[i]);
else if(i==0)bigger[0] += number_length(array1[i]);
if(i>1) bigger[0] += number_length(i) + 2;
else if(i==1) bigger[0] += 1;
las = 0;
}
}
las = 1;
for(int64_t i=b;i>=0;i--){
if(array2[i]){
if(!las && array2[i] != 0)bigger[1] += 1;
else if(las&&array2[i]<0) bigger[1] += 1;
if(i != 0 && array2[i]!=1 && array2[i]!=-1)bigger[1] += number_length(array2[i]);
else if(i==0)bigger[1] += number_length(array2[i]);
if(i>1) bigger[1] += number_length(i) + 2;
else if(i==1) bigger[1] += 1;
las = 0;
}
}
int64_t answer = 0;
while(bigger[0]>0|| bigger[1]>0){
answer += 1;
bigger[0] -= 1;
bigger[1] -= 1;
}
return answer;
}
void output(int64_t array[],int64_t length){
int64_t las = 1;
for(int64_t i=length;i>=0;i--){
if(!array[i]&&!i&&las)printf("0");
if(array[i]){
if(!las && array[i] > 0)printf("+");
if(i != 0 && array[i]!=1 && array[i]!=-1)printf("%ld",array[i]);
else if(i==0)printf("%ld",array[i]);
else if(array[i]==-1) printf("-");
if(i-flowed>1) printf("x^%ld",i-flowed);
else if(i-flowed==1) printf("x");
las = 0;
}
}
printf("\n");
}
int main(){
long double ld_degree[2];
int64_t degree[2];
int32_t errors = 0;
char temps[1000];
printf("Please enter f(x) degree: ");
scanf("%LF",&ld_degree[0]);
if(ld_degree[0]!=(int64_t)ld_degree[0] || ld_degree[0]<0 || ld_degree[0] > 4294967295){
errors = 1;
if(errors){
printf("Error Input, the degree is invalid!\n");
return 0;
}
}
else{
degree[0] = ld_degree[0];
}
long double *ld_f = calloc(degree[0]+1,sizeof(long double));
printf("Please enter f(x) coefficients: ");
if(!errors){
for(int64_t i=ld_degree[0];i>=0;i--) scanf("%LF",&ld_f[i]);
}
int32_t more[2] = {0};
scanf("%[^\n]%n",temps,&more[0]);
printf("Please enter g(x) degree: ");
scanf("%LF",&ld_degree[1]);
if(ld_degree[1]!=(int64_t)ld_degree[1] || ld_degree[1]<0 || ld_degree[1] > 4294967295){
errors = 1;
if(errors){
printf("Error Input, the degree is invalid!\n");
return 0;
}
}
else{
degree[1] = ld_degree[1];
}
long double *ld_g = calloc(degree[1]+1,sizeof(long double));
printf("Please enter g(x) coefficients: ");
if(!errors){
for(int64_t i=ld_degree[1];i>=0;i--) scanf("%LF",&ld_g[i]);
}
scanf("%[^\n]%n",temps,&more[1]);
if(errors){
printf("Error Input, the degree is invalid!\n");
return 0;
}
if(more[0]-1> 0|| more[1]-1> 0){
//printf("%d %d",more[0],more[1]);
printf("Wrong Input, the coefficients are more than degree!\n");
return 0;
}
/*for(int i=0;i<degree[0]+1;i++)printf("%LF ",ld_f[i]);
printf("\n");
for(int i=0;i<degree[1]+1;i++)printf("%LF ",ld_g[i]);
printf("\n");*/
int64_t **f = calloc(2,sizeof(int64_t *)),**g= calloc(2,sizeof(int64_t *));
for(int32_t i=0;i<2;i++){
f[i] = calloc(degree[0]+1,sizeof(int64_t));
g[i] = calloc(degree[1]+1,sizeof(int64_t));
}
for(int64_t i=degree[0];i>=0;i--){
//printf("%LF\n",ld_g[0]);
if(i==degree[0]&&!ld_f[i]){
printf("The input is invalid,first coefficients should not be 0.\n");
return 0;
}
if(ld_f[i] < -2147483648 || ld_f[i] > 2147483647 || ld_f[i]!=(int32_t)ld_f[i]){
printf("The coefficients is out of range!\n");
printf("%LF %d",ld_f[i],(int32_t)ld_f[i]);
return 0;
}
f[0][i] = ld_f[i];
if(i!=0){
f[1][i-1] = f[0][i] * (i);
}
}
//printf("%LF\n",ld_g[0]);
for(int64_t i=degree[1];i>=0;i--){
//printf("%LF %ld\n",ld_g[i],i);
if(i==degree[1]&&!ld_g[i]){
printf("The input is invalid,first coefficients should not be 0.\n");
return 0;
}
if(ld_g[i] < -2147483648 || ld_g[i] > 2147483647|| ld_g[i]!=(int32_t)ld_g[i]){
printf("The coefficients is out of range!\n");
printf("%LF %d",ld_g[i],(int32_t)ld_g[i]);
return 0;
}
g[0][i] = ld_g[i];
if(i!=0){
g[1][i-1] = g[0][i] * (i);
}
}
printf("f(x): ");
output(f[0],degree[0]);
printf("g(x): ");
output(g[0],degree[1]);
int64_t *multiply_ = calloc(degree[0] + degree[1] + 1,sizeof(int64_t));
int64_t *fded_mulg = calloc(degree[0] + degree[1] + 1,sizeof(int64_t));
int64_t *gded_mulf = calloc(degree[0] + degree[1] + 1,sizeof(int64_t));
for(int64_t i=0;i<degree[0] + degree[1] + 1;i++){
multiply_[i] = 0;
fded_mulg[i] = 0;
gded_mulf[i] = 0;
}
for(int64_t i=degree[0]-1;i>=0;i--){
for(int64_t j=degree[1];j>=0;j--){
fded_mulg[i+j] += f[1][i] * g[0][j];
multiply_[i+j] += f[1][i] *g[0][j];
}
}
for(int64_t i=degree[1]-1;i>=0;i--){
for(int64_t j=degree[0];j>=0;j--){
gded_mulf[i+j] += g[1][i] * f[0][j];
multiply_[i+j] += g[1][i] * f[0][j];
}
}
printf("(f(x)g(x))': ");
output(multiply_,degree[0] + degree[1]);
int64_t *mul_gg = calloc(degree[1] + degree[1] + 1,sizeof(int64_t));
for(int64_t i=0;i<degree[1]+degree[1]+1;i++) mul_gg[i] = 0;
for(int64_t i=degree[1];i>=0;i--){
for(int64_t j=degree[1];j>=0;j--){
mul_gg[i+j] += g[0][i] * g[0][j];
}
}
for(int64_t i=0;i<degree[0] + degree[1] + 1;i++){
multiply_[i] -= gded_mulf[i];
multiply_[i] -= gded_mulf[i];
}
countflowed(multiply_,mul_gg,degree[0] + degree[1],degree[1] + degree[1]);
sisiu(multiply_,mul_gg,degree[0] + degree[1],degree[1] + degree[1]);
printf(" f(x) ");
if(!countline(multiply_,multiply_,degree[0] + degree[1],degree[0] + degree[1])){
printf("0\n");
}
else{
output(multiply_,degree[0] + degree[1]);
}
printf("(----)': ");
output_line(countline(multiply_,mul_gg,degree[0] + degree[1],degree[1] + degree[1]));
printf(" g(x) ");
output(mul_gg,degree[1] + degree[1]);
//output(mul_gg,degree[1] + degree[1] + 1);
}
```
:::
## 4.3 GSAT
Credit: 41247007S 邱O婷 (revised by TA)
:::spoiler hw0403.c
```c=
#include <stdio.h>
#include <stdint.h>
#include "gsat.h"
#include <stdlib.h>
#define NUM_SUBJECTS 6
void sortScores(int32_t scores[], int size) {
for (int i = 0; i < size - 1; i++) {
for (int j = 0; j < size - i - 1; j++) {
if (scores[j] < scores[j + 1]) {
int32_t temp = scores[j];
scores[j] = scores[j + 1];
scores[j + 1] = temp;
}
}
}
}
void printPercentileScore(int32_t scores[][NUM_SUBJECTS], int studentNumber, int subject, double percentile) {
int32_t tempScores[STUDENT_NUMBER];
for (int i = 0; i < studentNumber; i++) {
tempScores[i] = scores[i][subject];
}
sortScores(tempScores, studentNumber);
// Computing the index for the percentile, adjusted for zero-based array indexing
int index = (int)(percentile / 100 * studentNumber) - 1;
index = (percentile / 100 * studentNumber) > index ? index + 1 : index;
// Boundary check to avoid array out-of-bounds access
index = index < 0 ? 0 : index;
index = index >= studentNumber ? studentNumber - 1 : index;
printf(subject == 0 ? "%5d " : "%9d ", tempScores[index]);
}
int main() {
int studentNumber = sizeof(score) / sizeof(score[0]);
double percentiles[] = {12, 25, 50, 75, 88};
printf(" CHINESE | ENGLISH | MATH_A | MATH_B | SOCIAL | SCIENCE\n");
for (int i = 0; i < sizeof(percentiles) / sizeof(percentiles[0]); i++) {
printf("TOP %.0f%% ", percentiles[i]);
for (int j = 0; j < NUM_SUBJECTS; j++) {
printPercentileScore(score, studentNumber, j, percentiles[i]);
}
printf("\n");
}
return 0;
}
```
:::
## 4.4 Xiangqi
Credit: 41247014S 李O達
:::spoiler mychess.c
```c
#include"mychess.h"
int32_t checkmate( int32_t board[10][9] )
{
//檢查棋盤是否有效
int32_t check_board[18];
for ( int32_t i = 0; i < 18; i++ )
{
check_board[i] = 0;
}
for ( int32_t i = 0; i < 10; i++ )
{
for ( int32_t j = 0; j < 9; j++ )
{
if ( board[i][j] < 0 || (board[i][j] > RED_SOLDIER && board[i][j] < BLACK_GENERAL) || board[i][j] > BLACK_SOLDIER )
return -1;
else
check_board[board[i][j]] += 1;
if ( board[i][j] == RED_GENERAL && (i>2 || j<3 || j>5) )//檢查紅將軍位置
return -1;
if ( board[i][j] == BLACK_GENERAL && (i<7 || j<3 || j>5) )//檢查黑將軍位置
return -1;
if ( board[i][j] == RED_ADVISOR )//檢查紅士位置
{
if( i == 0 && ( j==3 || j==5 ) )
continue;
else if( i == 1 && j == 4 )
continue;
else if( i == 2 && ( j==3 || j==5 ) )
continue;
else
return -1;
}
if ( board[i][j] == BLACK_ADVISOR )//檢查黑士位置
{
if( i == 7 && ( j==3 || j==5 ) )
continue;
else if( i == 8 && j == 4 )
continue;
else if( i == 9 && ( j==3 || j==5 ) )
continue;
else
return -1;
}
if ( board[i][j] == RED_ELEPHANT )//檢查紅象位置
{
if( i == 0 && ( j==2 || j==6 ) )
continue;
else if( i == 2 && ( j==0 || j==4 || j==8 ) )
continue;
else if( i == 4 && ( j==2 || j==6 ) )
continue;
else
return -1;
}
if ( board[i][j] == BLACK_ELEPHANT )//檢查黑象位置
{
if( i == 5 && ( j==2 || j==6 ) )
continue;
else if( i == 7 && ( j==0 || j==4 || j==8 ) )
continue;
else if( i == 9 && ( j==2 || j==6 ) )
continue;
else
return -1;
}
if ( board[i][j] == RED_SOLDIER )//檢查紅兵位置
{
if( (i == 3 || i == 4) && ( j==0 || j==2 || j == 4 || j == 6 || j == 8 ) )
continue;
else if ( i >= 5 && i <= 9 )
continue;
else return -1;
}
if ( board[i][j] == BLACK_SOLDIER )//檢查黑兵位置
{
if( (i == 5 || i == 6) && ( j==0 || j==2 || j == 4 || j == 6 || j == 8 ) )
continue;
else if ( i >= 0 && i <= 4 )
continue;
else return -1;
}
}
}
for ( int32_t i = 0; i < 18; i++ )//檢查棋子數量
{
if ( i == RED_GENERAL || i== BLACK_GENERAL )
{
if ( check_board[i] != 1 )
return -1;
}
else if ( (i >= RED_ADVISOR && i <= RED_CANNON) || (i >= BLACK_ADVISOR && i <= BLACK_CANNON) )
{
if ( check_board[i] > 2 )
return -1;
}
else if ( i==RED_SOLDIER || i == BLACK_SOLDIER )
{
if ( check_board[i] > 5 )
return -1;
}
}
//輸出
int32_t check_general = 0, check_horse = 0, check_chariot = 0, check_cannon = 0, check_soldier = 0;
int32_t *check_general_ptr = &check_general, *check_horse_ptr = &check_horse, *check_chariot_ptr = &check_chariot, *check_cannon_ptr = &check_cannon, *check_soldier_ptr = &check_soldier;
int32_t ans_general[5][2]={0}, ans_horse[5][2]={0}, ans_chariot[5][2]={0}, ans_cannon[5][2]={0}, ans_soldier[5][2]={0};
int32_t number = 1;
for ( int32_t i = 0; i < 10; i++ )
{
for ( int32_t j = 0; j < 9; j++ )
{
if ( board[i][j] == RED_GENERAL )
{
if ( MOVE_GENERAL(i,j,1,board,ans_general,check_general_ptr) == 1 )
{
for ( int32_t k=0; k<*check_general_ptr; k++ )
{
printf("%d) Move General from (%d,%d) to (%d,%d)\n", number, i, j, ans_general[k][0], ans_general[k][1] );
number += 1;
}
*check_general_ptr = 0;
}
}
}
}
for ( int32_t i = 0; i < 10; i++ )
{
for ( int32_t j = 0; j < 9; j++ )
{
if ( board[i][j] == RED_HORSE )
{
if ( MOVE_HORSE(i,j,1,board,ans_horse,check_horse_ptr) == 1 )
{
for ( int32_t k=0; k<*check_horse_ptr; k++ )
{
printf("%d) Move Horse from (%d,%d) to (%d,%d)\n", number, i, j, ans_horse[k][0], ans_horse[k][1] );
number += 1;
}
*check_horse_ptr = 0;
}
}
}
}
for ( int32_t i = 0; i < 10; i++ )
{
for ( int32_t j = 0; j < 9; j++ )
{
if ( board[i][j] == RED_CHARIOT )
{
if ( MOVE_CHARIOT(i,j,board,ans_chariot,check_chariot_ptr) == 1 )
{
for ( int32_t k=0; k<*check_chariot_ptr; k++ )
{
printf("%d) Move Chariot from (%d,%d) to (%d,%d)\n", number, i, j, ans_chariot[k][0], ans_chariot[k][1] );
number += 1;
}
*check_chariot_ptr = 0;
}
}
}
}
for ( int32_t i = 0; i < 10; i++ )
{
for ( int32_t j = 0; j < 9; j++ )
{
if ( board[i][j] == RED_CANNON )
{
if ( MOVE_CANNON(i,j,board,ans_cannon,check_cannon_ptr) == 1 )
{
for ( int32_t k=0; k<*check_cannon_ptr; k++ )
{
printf("%d) Move Cannon from (%d,%d) to (%d,%d)\n", number, i, j, ans_cannon[k][0], ans_cannon[k][1] );
number += 1;
}
*check_cannon_ptr = 0;
}
}
}
}
for ( int32_t i = 0; i < 10; i++ )
{
for ( int32_t j = 0; j < 9; j++ )
{
if ( board[i][j] == RED_SOLDIER )
{
if ( MOVE_SOLDIER(i,j,1,board,ans_soldier,check_soldier_ptr) == 1 )
{
for ( int32_t k=0; k<*check_soldier_ptr; k++ )
{
printf("%d) Move Soldier from (%d,%d) to (%d,%d)\n", number, i, j, ans_soldier[k][0], ans_soldier[k][1] );
number += 1;
}
*check_soldier_ptr = 0;
}
}
}
}
}
int32_t MOVE_GENERAL( int32_t x , int32_t y ,int32_t times, int32_t board[10][9] , int32_t ans_general[5][2], int32_t *check_general_ptr)
{
int32_t walk[2][2] = { {0,1}, {0,-1} };
for ( int32_t i = 0; i < 2; i++ )
{
if ( times == 1 )
{
int32_t tmpx = x + walk[i][0];
int32_t tmpy = y + walk[i][1];
if ( tmpx<0 || tmpx>2 || tmpy<3 || tmpy>5 )
continue;
if ( board[tmpx][tmpy]>=RED_GENERAL && board[tmpx][tmpy]<=RED_SOLDIER )
continue;
MOVE_GENERAL( tmpx, tmpy, 2, board, ans_general, check_general_ptr );
}
if ( times == 2 )
{
for ( int32_t j = x+1; j<10 ; j++ )
{
if ( board[j][y] == BLACK_GENERAL )
{
ans_general[*check_general_ptr][0] = x;
ans_general[*check_general_ptr][1] = y;
*check_general_ptr += 1;
return 0;
}
else if ( board[j][y] != EMPTY )
return 0;
}
}
}
if ( *check_general_ptr != 0 )
return 1;
else
return 0;
}
int32_t MOVE_HORSE( int32_t x, int32_t y,int32_t times, int32_t board[10][9], int32_t ans_horse[5][2], int32_t *check_horse_ptr)
{
int32_t walk[8][2] = { {-2,-1}, {-2,1}, {-1,-2}, {-1,2}, {1,-2}, {1,2}, {2,-1}, {2,1} };
int32_t leg[8][2] = { {-1,0}, {-1,0}, {0,-1}, {0,1}, {0,-1}, {0,1}, {1,0}, {1,0} };
for ( int32_t i = 0; i < 8; i++ )
{
int32_t tmpx = x + walk[i][0];
int32_t tmpy = y + walk[i][1];
int32_t tmplegx = x + leg[i][0];
int32_t tmplegy = y + leg[i][1];
if ( tmpx<0 || tmpx>9 || tmpy<0 || tmpy>8 )
continue;
if ( board[tmpx][tmpy]>=RED_GENERAL && board[tmpx][tmpy]<=RED_SOLDIER )
continue;
if ( board[tmplegx][tmplegy] != EMPTY )
continue;
if ( times == 1 )
MOVE_HORSE( tmpx, tmpy, 2, board, ans_horse, check_horse_ptr );
if ( times == 2 )
{
if ( board[tmpx][tmpy] == BLACK_GENERAL )
{
ans_horse[*check_horse_ptr][0] = x;
ans_horse[*check_horse_ptr][1] = y;
*check_horse_ptr += 1;
return 0;
}
else
continue;
}
}
if ( *check_horse_ptr != 0 )
return 1;
else
return 0;
}
int32_t MOVE_CHARIOT( int32_t x, int32_t y, int32_t board[10][9], int32_t ans_chariot[5][2] , int32_t *check_chariot_ptr)
{
int32_t block=0;
for ( int32_t i=x-1 ; i>=0 ; i-- )
{
if ( board[i][y]>=RED_GENERAL && board[i][y]<=RED_SOLDIER )
break;
if ( board[i][y]>=BLACK_GENERAL && board[i][y]<=BLACK_SOLDIER )
block += 1;
if ( block > 1 )
break;
else
CHARIOT_EAT_GENERAL( i, y, board, ans_chariot, check_chariot_ptr );
}
block = 0;
for ( int32_t i=y-1 ; i>=0 ; i-- )
{
if ( board[x][i]>=RED_GENERAL && board[x][i]<=RED_SOLDIER )
break;
if ( board[x][i]>=BLACK_GENERAL && board[x][i]<=BLACK_SOLDIER )
block += 1;
if ( block > 1 )
break;
else
CHARIOT_EAT_GENERAL( x, i, board, ans_chariot, check_chariot_ptr );
}
block = 0;
for ( int32_t i=y+1 ; i<=8 ; i++ )
{
if ( board[x][i]>=RED_GENERAL && board[x][i]<=RED_SOLDIER )
break;
if ( board[x][i]>=BLACK_GENERAL && board[x][i]<=BLACK_SOLDIER )
block += 1;
if ( block > 1 )
break;
else
CHARIOT_EAT_GENERAL( x, i, board, ans_chariot, check_chariot_ptr );
}
block = 0;
for ( int32_t i=x+1 ; i<=9 ; i++ )
{
if ( board[i][y]>=RED_GENERAL && board[i][y]<=RED_SOLDIER )
break;
if ( board[i][y]>=BLACK_GENERAL && board[i][y]<=BLACK_SOLDIER )
block += 1;
if ( block > 1 )
break;
else
CHARIOT_EAT_GENERAL( i, y, board, ans_chariot, check_chariot_ptr );
}
if ( *check_chariot_ptr != 0 )
return 1;
else
return 0;
}
int32_t MOVE_CANNON( int32_t x, int32_t y, int32_t board[10][9], int32_t ans_cannon[5][2] , int32_t *check_cannon_ptr)
{
int32_t block=0;
for ( int32_t i=x-1 ; i >= 0 ; i-- )
{
if ( board[i][y]!= 0 )
block += 1;
if ( block == 0 )
CANNON_EAT_GENERAL( i, y, board, ans_cannon, check_cannon_ptr );
if ( block == 1 )
{
int32_t landing_point=0;
for ( int32_t j=i-1 ; j >= 0 ; j-- )
{
if ( board[j][y]!= EMPTY )
landing_point += 1;
if ( landing_point==1 && board[j][y]>=BLACK_GENERAL && board[j][y]<=BLACK_SOLDIER )
{
CANNON_EAT_GENERAL( j, y, board, ans_cannon, check_cannon_ptr );
break;
}
if ( landing_point > 1 )
break;
}
break;
}
}
block=0;
for ( int32_t i=y-1 ; i >= 0 ; i-- )
{
if ( board[x][i]!= 0 )
block += 1;
if ( block == 0 )
CANNON_EAT_GENERAL( x, i, board, ans_cannon, check_cannon_ptr );
if ( block == 1 )
{
int32_t landing_point=0;
for ( int32_t j=i-1 ; j >= 0 ; j-- )
{
if ( board[x][j]!= EMPTY )
landing_point += 1;
if ( landing_point==1 && board[x][j]>=BLACK_GENERAL && board[x][j]<=BLACK_SOLDIER )
{
CANNON_EAT_GENERAL( x, j, board, ans_cannon, check_cannon_ptr );
break;
}
if ( landing_point > 1 )
break;
}
break;
}
}
block=0;
for ( int32_t i=y+1 ; i <= 8 ; i++ )
{
if ( board[x][i]!= 0 )
block += 1;
if ( block == 0 )
CANNON_EAT_GENERAL(x,i,board,ans_cannon,check_cannon_ptr);
if ( block == 1 )
{
int32_t landing_point=0;
for ( int32_t j=i+1 ; j < 8 ; j++ )
{
if ( board[x][j]!= EMPTY )
landing_point += 1;
if ( landing_point==1 && board[x][j]>=BLACK_GENERAL && board[x][j]<=BLACK_SOLDIER )
{
CANNON_EAT_GENERAL(x,j,board,ans_cannon,check_cannon_ptr);
break;
}
if ( landing_point > 1 )
break;
}
break;
}
}
block=0;
for ( int32_t i=x+1 ; i <= 9 ; i++ )
{
if ( board[i][y]!= 0 )
block += 1;
if ( block == 0 )
CANNON_EAT_GENERAL(i,y,board,ans_cannon,check_cannon_ptr);
if ( block == 1 )
{
int32_t landing_point=0;
for ( int32_t j=i+1 ; j < 9 ; j++ )
{
if ( board[j][y]!= EMPTY )
landing_point += 1;
if ( landing_point==1 && board[j][y]>=BLACK_GENERAL && board[j][y]<=BLACK_SOLDIER )
{
CANNON_EAT_GENERAL(j,y,board,ans_cannon,check_cannon_ptr);
break;
}
if ( landing_point > 1 )
break;
}
break;
}
}
if ( *check_cannon_ptr != 0 )
return 1;
else
return 0;
}
int32_t MOVE_SOLDIER( int32_t x, int32_t y, int32_t times, int32_t board[10][9], int32_t ans_soldier[5][2], int32_t *check_soldier_ptr )
{
int32_t walk[3][2] = { {0,-1}, {0,1}, {1,0} };
for ( int32_t i = 0; i < 3; i++ )
{
int32_t tmpx = x + walk[i][0];
int32_t tmpy = y + walk[i][1];
if ( tmpx<0 || tmpx>9 || tmpy<0 || tmpy>8 )
continue;
if ( board[tmpx][tmpy]>=RED_GENERAL && board[tmpx][tmpy]<=RED_SOLDIER )
continue;
if ( times == 1 )
MOVE_SOLDIER( tmpx, tmpy, 2, board, ans_soldier, check_soldier_ptr );
if ( times == 2 )
{
if ( board[tmpx][tmpy] == BLACK_GENERAL )
{
ans_soldier[*check_soldier_ptr][0] = x;
ans_soldier[*check_soldier_ptr][1] = y;
*check_soldier_ptr += 1;
return 0;
}
else
continue;
}
}
if ( *check_soldier_ptr != 0 )
return 1;
else
return 0;
}
int32_t CHARIOT_EAT_GENERAL(int32_t x, int32_t y, int32_t board[10][9], int32_t ans_chariot[5][2], int32_t *check_chariot_ptr)
{
for ( int32_t i=x-1 ; i>=0 ; i-- )
{
if ( board[i][y]!=EMPTY && board[i][y]!=BLACK_GENERAL )
break;
if ( board[i][y] == BLACK_GENERAL )
{
ans_chariot[*check_chariot_ptr][0] = x;
ans_chariot[*check_chariot_ptr][1] = y;
*check_chariot_ptr += 1;
return 0;
}
}
for ( int32_t i=y-1 ; i>=0 ; i-- )
{
if ( board[x][i]!=EMPTY && board[x][i]!=BLACK_GENERAL )
break;
if ( board[x][i] == BLACK_GENERAL )
{
ans_chariot[*check_chariot_ptr][0] = x;
ans_chariot[*check_chariot_ptr][1] = y;
*check_chariot_ptr += 1;
return 0;
}
}
for ( int32_t i=y+1 ; i<=8 ; i++ )
{
if ( board[x][i]!=EMPTY && board[x][i]!=BLACK_GENERAL )
break;
if ( board[x][i] == BLACK_GENERAL )
{
ans_chariot[*check_chariot_ptr][0] = x;
ans_chariot[*check_chariot_ptr][1] = y;
*check_chariot_ptr += 1;
return 0;
}
}
for ( int32_t i=x+1 ; i<=9 ; i++ )
{
if ( board[i][y]!=EMPTY && board[i][y]!=BLACK_GENERAL )
break;
if ( board[i][y] == BLACK_GENERAL )
{
ans_chariot[*check_chariot_ptr][0] = x;
ans_chariot[*check_chariot_ptr][1] = y;
*check_chariot_ptr += 1;
return 0;
}
}
}
int32_t CANNON_EAT_GENERAL(int32_t x, int32_t y, int32_t board[10][9], int32_t ans_cannon[5][2], int32_t *check_cannon_ptr)
{
int32_t block=0;
for ( int32_t i=x-1 ; i>=0 ; i-- )
{
if ( board[i][y] != EMPTY )
block += 1;
if ( board[i][y]== RED_CANNON )
block -= 1;
if ( block>2 )
break;
if ( block == 2 && board[i][y] == BLACK_GENERAL )
{
ans_cannon[*check_cannon_ptr][0] = x;
ans_cannon[*check_cannon_ptr][1] = y;
*check_cannon_ptr += 1;
return 0;
}
}
block = 0;
for ( int32_t i=y-1 ; i>=0 ; i-- )
{
if ( board[x][i]!= EMPTY )
block += 1;
if ( board[x][i]== RED_CANNON )
block -= 1;
if ( block>2 )
break;
if ( block == 2 && board[x][i] == BLACK_GENERAL )
{
ans_cannon[*check_cannon_ptr][0] = x;
ans_cannon[*check_cannon_ptr][1] = y;
*check_cannon_ptr += 1;
return 0;
}
}
block = 0;
for ( int32_t i=y+1 ; i<=8 ; i++ )
{
if ( board[x][i]!= EMPTY )
block += 1;
if ( board[x][i]== RED_CANNON )
block -= 1;
if ( block>2 )
break;
if ( block == 2 && board[x][i] == BLACK_GENERAL )
{
ans_cannon[*check_cannon_ptr][0] = x;
ans_cannon[*check_cannon_ptr][1] = y;
*check_cannon_ptr += 1;
return 0;
}
}
block = 0;
for ( int32_t i=x+1 ; i<=9 ; i++ )
{
if ( board[i][y]!= EMPTY )
block += 1;
if ( board[i][y]== RED_CANNON )
block -= 1;
if ( block>2 )
break;
if ( block == 2 && board[i][y] == BLACK_GENERAL )
{
ans_cannon[*check_cannon_ptr][0] = x;
ans_cannon[*check_cannon_ptr][1] = y;
*check_cannon_ptr += 1;
return 0;
}
}
}
```
:::
:::spoiler mychess.h
```c
#pragma once
#include<stdint.h>
#include<stdio.h>
#include<stdlib.h>
#define EMPTY (0)
#define RED_GENERAL (1)
#define RED_ADVISOR (2)
#define RED_ELEPHANT (3)
#define RED_HORSE (4)
#define RED_CHARIOT (5)
#define RED_CANNON (6)
#define RED_SOLDIER (7)
#define BLACK_GENERAL (11)
#define BLACK_ADVISOR (12)
#define BLACK_ELEPHANT (13)
#define BLACK_HORSE (14)
#define BLACK_CHARIOT (15)
#define BLACK_CANNON (16)
#define BLACK_SOLDIER (17)
int32_t checkmate( int32_t board[10][9] );
int32_t MOVE_GENERAL( int32_t x , int32_t y ,int32_t times, int32_t board[10][9] , int32_t ans_general[5][2], int32_t *check_general_ptr);
int32_t MOVE_HORSE( int32_t x, int32_t y,int32_t times, int32_t board[10][9], int32_t ans_horse[5][2], int32_t *check_horse_ptr);
int32_t MOVE_CHARIOT( int32_t x, int32_t y, int32_t board[10][9], int32_t ans_chariot[5][2] , int32_t *check_chariot_ptr);
int32_t MOVE_CANNON( int32_t x, int32_t y, int32_t board[10][9], int32_t ans_cannon[5][2] , int32_t *check_cannon_ptr);
int32_t MOVE_SOLDIER( int32_t x, int32_t y, int32_t times, int32_t board[10][9], int32_t ans_soldier[5][2], int32_t *check_soldier_ptr );
int32_t CHARIOT_EAT_GENERAL(int32_t x, int32_t y, int32_t board[10][9], int32_t ans_chariot[5][2], int32_t *check_chariot_ptr);
int32_t CANNON_EAT_GENERAL(int32_t x, int32_t y, int32_t board[10][9], int32_t ans_cannon[5][2], int32_t *check_cannon_ptr);
```
:::
## 4.5 Japanese Mahjong
Credit: 41247039S 韓O劭
:::spoiler hw0405.c
```c
#include <stdio.h>
#include <stdint.h>
#include "mahjong.h"
int main() {
myMahjong mahjong = { {0}, {0}, { {0},{0} }, 0, 0, 0, 0, 0 };
// Hand input
int32_t meld = 0, validHand = 1;
while (meld != 4) {
printf("Please input meld: ");
int32_t tile = 0, count = 0;
while (count <= 14) {
if (scanf("%d", &tile) != 1 || !isValidNewTile(mahjong, tile)) {
if (tile != 0) {
validHand = 0;
}
break;
}
mahjong.tilesAmount[tile]++;
mahjong.tiles[mahjong.totalTiles++] = tile;
count++;
}
mahjong.melds[meld][MELD_TILES] = mahjong.totalTiles;
int32_t check = isValidMeld(mahjong, meld);
// printf("check=%d, total=%d\n", check, mahjong.totalTiles);
if (validHand == 0 || check == 0) {
validHand = 0;
meld = -1;
break;
} else if (check == 2) {
meld = 1;
break;
}
printf("Is open group(1: YES 0: NO): ");
int32_t openMeld = 0;
if (scanf("%d", &openMeld) != 1 || (openMeld != 0 && openMeld != 1)) {
validHand = 0;
meld = -1;
break;
}
mahjong.melds[meld][MELD_OPEN] = openMeld;
meld++;
}
mahjong.totalMelds = meld;
// Pair input
if (validHand && meld != 1) {
printf("Please input pair: ");
int32_t pair = 0;
while (pair < 2) {
int32_t tile = 0;
if (scanf("%d", &tile) != 1 || !isValidNewTile(mahjong, tile)) {
validHand = 0;
break;
}
mahjong.tilesAmount[tile]++;
mahjong.tiles[mahjong.totalTiles++] = tile;
pair++;
}
}
if (validHand && meld != 1) {
int32_t pair1 = mahjong.tiles[mahjong.totalTiles - 1];
int32_t pair2 = mahjong.tiles[mahjong.totalTiles - 2];
if (!isValidPair(pair1, pair2)) {
validHand = 0;
}
}
// Winning tile input
if (validHand) {
int32_t tile = 0;
printf("Please input winning tile: ");
if (scanf("%d", &tile) != 1 || !isValidWinningTile(mahjong, tile)) {
// printf("Invalid winning tile!\n");
validHand = 0;
}
mahjong.winningTile = tile;
}
// Wind input
if (validHand) {
int32_t playerWind = 0;
printf("Player's wind(0:E 1:S 2:W 3:N): ");
if (scanf("%d", &playerWind) != 1 || !isValidWind(playerWind)) {
// printf("Invalid player wind!\n");
validHand = 0;
}
mahjong.playerWind = playerWind;
}
if (validHand) {
int32_t prevailingWind = 0;
printf("Prevailing wind(0:E 1:S 2:W 3:N): ");
if (scanf("%d", &prevailingWind) != 1 || !isValidWind(prevailingWind)) {
// printf("Invalid player wind!\n");
validHand = 0;
}
mahjong.prevailingWind = prevailingWind;
}
// printf("All tiles: \n");
// for (int32_t i = 0; i < mahjong.totalMelds; i++) {
// int32_t head = (i == 0) ? 0 : mahjong.melds[i-1][MELD_TILES];
// int32_t tail = mahjong.melds[i][MELD_TILES];
// for (int32_t j = head; j < tail; j++) {
// printf("%d ", mahjong.tiles[j]);
// }
// printf("\n");
// }
if (!validHand) {
mahjong.totalMelds = -1;
}
printf("\n");
calculateHan(mahjong);
return 0;
}
```
:::
:::spoiler mahjong.c
```c
#include "mahjong.h"
int32_t isValidNewTile(myMahjong mahjong, int32_t tile) {
if (tile < 1 || tile > 34) {
return 0;
}
if (mahjong.tilesAmount[tile] == 4) {
return 0;
}
return 1;
}
int32_t isValidAmountOfTiles(myMahjong mahjong) {
int32_t tilesAmount[35] = {0};
for (int32_t i = 0; i < mahjong.totalTiles; i++) {
int32_t tile = mahjong.tiles[i];
tilesAmount[tile]++;
if (tilesAmount[tile] > 4) {
return 0;
}
}
return 1;
}
int32_t isValidMeld(myMahjong mahjong, int32_t meld) {
if (meld < 0 || meld > 4) {
return 0;
}
if (isStraightMeld(mahjong, meld) || isTripletOrKanMeld(mahjong, meld)) {
return 1;
}
if (isSpecialMeld(mahjong, meld)) {
return 2;
}
return 0;
}
int32_t isValidPair(int32_t tile1, int32_t tile2) {
return (tile1 == tile2);
}
int32_t isValidWinningTile(myMahjong mahjong, int32_t tile) {
int32_t check = 0;
if (mahjong.tiles[mahjong.totalTiles-1] == tile) {
return 1;
}
for (int32_t i = 0; i < mahjong.totalMelds; i++) {
int32_t head = (i == 0) ? 0 : mahjong.melds[i-1][MELD_TILES];
int32_t tail = mahjong.melds[i][MELD_TILES];
for (int32_t j = head; j < tail; j++) {
if ((mahjong.tiles[j] == tile) && (isTripletOrKanMeld(mahjong, i) != 2)) {
check = 1;
break;
}
}
}
// printf("check=%d\n", check);
return check;
}
int32_t isValidWind(int32_t wind) {
return (wind == 0 || wind == 1 || wind == 2 || wind == 3);
}
void calculateHan(myMahjong mahjong) {
int32_t result = 0;
printf("The Score is...\n");
if (mahjong.totalMelds == -1) {
printYaku(ERROR_YAKU);
printf("Total: 0 Han\n");
return;
}
result = handleYakuman(mahjong);
if (result != 0) {
printf("Total: %d Yakuman\n", result / 100);
return;
}
result = handleYaku(mahjong);
if (result == 0) {
printYaku(NO_YAKU);
}
printf("Total: %d Han", result);
if (result >= 13) {
printf(" (Kazoe-yakuman)");
}
printf("\n");
}
```
:::
:::spoiler mahjong_yaku.c
```c
#include "mahjong_yaku.h"
int32_t isHonorTile(int32_t tile) {
return (tile == EAST || tile == SOUTH ||
tile == WEST || tile == NORTH ||
tile == WHITE || tile == GREEN ||
tile == RED);
}
int32_t isYaochuTile(int32_t tile) {
return (tile == PIN_1 || tile == PIN_9 ||
tile == SO_1 || tile == SO_9 ||
tile == MAN_1 || tile == MAN_9 ||
tile == EAST || tile == SOUTH ||
tile == WEST || tile == NORTH ||
tile == WHITE || tile == GREEN ||
tile == RED);
}
int32_t isStraightMeld(myMahjong mahjong, int32_t meld) {
int32_t head = (meld == 0) ? 0 : mahjong.melds[meld-1][MELD_TILES];
int32_t tail = mahjong.melds[meld][MELD_TILES];
int32_t tiles = tail - head;
if (tiles != 3) {
return 0;
}
int32_t tempMeld[3] = {0};
for (int32_t i = head; i < tail; i++) {
tempMeld[i - head] = mahjong.tiles[i];
}
for (int32_t i = 0; i < tiles - 1; i++) {
for (int32_t j = i + 1; j < tiles; j++) {
if (tempMeld[i] > tempMeld[j]) {
int32_t temp = tempMeld[i];
tempMeld[i] = tempMeld[j];
tempMeld[j] = temp;
}
}
}
switch (tempMeld[0]) {
case PIN_8: case PIN_9:
case SO_8: case SO_9:
case MAN_8: case MAN_9:
case EAST: case SOUTH: case WEST: case NORTH:
case WHITE: case GREEN: case RED:
return 0;
break;
default:
break;
}
if ((tempMeld[0] + 1 == tempMeld[1]) && (tempMeld[1] + 1 == tempMeld[2])) {
// printf("Is straight!\n");
return 1;
}
return 0;
}
int32_t isTripletOrKanMeld(myMahjong mahjong, int32_t meld) {
int32_t head = (meld == 0) ? 0 : mahjong.melds[meld-1][MELD_TILES];
int32_t tail = mahjong.melds[meld][MELD_TILES];
int32_t tiles = tail - head;
if (tiles != 3 && tiles != 4) {
return 0;
}
for (int32_t i = head; i < tail - 1; i++) {
if (mahjong.tiles[i] != mahjong.tiles[i + 1]) {
return 0;
}
}
return tiles - 2;
}
int32_t isSpecialMeld(myMahjong mahjong, int32_t meld) {
int32_t head = (meld == 0) ? 0 : mahjong.melds[meld-1][MELD_TILES];
int32_t tail = mahjong.melds[meld][MELD_TILES];
int32_t tiles = tail - head;
if (tiles != 14) {
return 0;
}
if (!isThirteenOrphans(mahjong) && !isSevenPairs(mahjong)) {
return 0;
}
return 1;
}
int32_t isClosedHand(myMahjong mahjong) {
for (int32_t i = 0; i < mahjong.totalMelds; i++) {
if (mahjong.melds[i][MELD_OPEN] == 1) {
return 0;
}
}
return 1;
}
int32_t amountOfHonors(myMahjong mahjong) {
int32_t total = 0;
for (int32_t i = EAST; i <= RED; i++) {
total += mahjong.tilesAmount[i];
}
return total;
}
int32_t amountOfTerminals(myMahjong mahjong) {
int32_t total = 0;
total += mahjong.tilesAmount[PIN_1];
total += mahjong.tilesAmount[PIN_9];
total += mahjong.tilesAmount[SO_1];
total += mahjong.tilesAmount[SO_9];
total += mahjong.tilesAmount[MAN_1];
total += mahjong.tilesAmount[MAN_9];
return total;
}
int32_t handleYakuman(myMahjong mahjong) {
int32_t total = 0;
// 2 Yakuman
if (isFourWinds(mahjong) == TWO_YAKUMAN) {
printYaku(BIG_FOUR_WINDS);
total += TWO_YAKUMAN;
}
if (isFourConcealedTriplets(mahjong) == TWO_YAKUMAN) {
printYaku(FOUR_CONCEALED_TRIPLETS_SINGLE_WAIT);
total += TWO_YAKUMAN;
}
if (isNineGates(mahjong) == TWO_YAKUMAN) {
printYaku(NINE_GATES_NINE_WAIT);
total += TWO_YAKUMAN;
}
if (isThirteenOrphans(mahjong) == TWO_YAKUMAN) {
printYaku(THIRTEEN_ORPHANS_13_WAIT);
total += TWO_YAKUMAN;
}
// 1 Yakuman
if (isAllGreen(mahjong) == ONE_YAKUMAN) {
printYaku(ALL_GREEN);
total += ONE_YAKUMAN;
}
if (isAllHonors(mahjong) == ONE_YAKUMAN) {
printYaku(ALL_HONORS);
total += ONE_YAKUMAN;
}
if (isAllTerminals(mahjong) == ONE_YAKUMAN) {
printYaku(ALL_TERMINALS);
total += ONE_YAKUMAN;
}
if (isBigThreeDragons(mahjong) == ONE_YAKUMAN) {
printYaku(BIG_THREE_DRAGONS);
total += ONE_YAKUMAN;
}
if (isFourConcealedTriplets(mahjong) == ONE_YAKUMAN) {
printYaku(FOUR_CONCEALED_TRIPLETS);
total += ONE_YAKUMAN;
}
if (isFourKans(mahjong) == ONE_YAKUMAN) {
printYaku(FOUR_KANS);
total += ONE_YAKUMAN;
}
if (isFourWinds(mahjong) == ONE_YAKUMAN) {
printYaku(LITTLE_FOUR_WINDS);
total += ONE_YAKUMAN;
}
if (isNineGates(mahjong) == ONE_YAKUMAN) {
printYaku(NINE_GATES);
total += ONE_YAKUMAN;
}
if (isThirteenOrphans(mahjong) == ONE_YAKUMAN) {
printYaku(THIRTEEN_ORPHANS);
total += ONE_YAKUMAN;
}
return total;
}
int32_t isFourWinds(myMahjong mahjong) {
int32_t triplet = 0, pair = 0;
for (int32_t i = EAST; i <= NORTH; i++) {
if (mahjong.tilesAmount[i] >= 3) {
triplet++;
} else if (mahjong.tilesAmount[i] == 2) {
pair++;
}
}
if (triplet == 4 && pair == 0) {
return TWO_YAKUMAN;
} else if (triplet == 3 && pair == 1) {
return ONE_YAKUMAN;
}
return 0;
}
int32_t isFourConcealedTriplets(myMahjong mahjong) {
int32_t triplet = 0;
for (int32_t i = 0; i < mahjong.totalMelds; i++) {
if (isTripletOrKanMeld(mahjong, i)) {
triplet++;
}
}
if (triplet == 4 && isClosedHand(mahjong)) {
if (mahjong.winningTile == mahjong.tiles[mahjong.totalTiles-1]) {
return TWO_YAKUMAN;
} else {
return ONE_YAKUMAN;
}
}
return 0;
}
int32_t isNineGates(myMahjong mahjong) {
if (!isClosedHand(mahjong)) {
return 0;
}
for (int32_t i = 0; i < 3; i++) {
int32_t check = 0, nineWait = 0;
for (int32_t j = 1; j <= 9; j++) {
int32_t tile = i * 9 + j;
int32_t amount = mahjong.tilesAmount[tile];
if ((j == 1 || j == 9) && amount >= 3) {
check++;
if (amount == 4 && mahjong.winningTile == tile) {
nineWait = 1;
}
} else if ((j != 1 && j != 9) && amount >= 1) {
check++;
if (amount == 2 && mahjong.winningTile == tile) {
nineWait = 1;
}
}
}
// printf("check=%d wait=%d\n", check, nineWait);
if (check == 9) {
return (nineWait == 1) ? TWO_YAKUMAN : ONE_YAKUMAN;
}
}
return 0;
}
int32_t isThirteenOrphans(myMahjong mahjong) {
if (mahjong.tilesAmount[PIN_1] >= 1 && mahjong.tilesAmount[PIN_9] >= 1 &&
mahjong.tilesAmount[SO_1] >= 1 && mahjong.tilesAmount[SO_9] >= 1 &&
mahjong.tilesAmount[MAN_1] >= 1 && mahjong.tilesAmount[MAN_9] >= 1 &&
mahjong.tilesAmount[EAST] >= 1 && mahjong.tilesAmount[SOUTH] >= 1 &&
mahjong.tilesAmount[WEST] >= 1 && mahjong.tilesAmount[NORTH] >= 1 &&
mahjong.tilesAmount[WHITE] >= 1 && mahjong.tilesAmount[GREEN] >= 1 &&
mahjong.tilesAmount[RED] >= 1 && mahjong.totalTiles == 14) {
if (mahjong.tilesAmount[mahjong.winningTile] == 2) {
return TWO_YAKUMAN;
}
return ONE_YAKUMAN;
}
return 0;
}
int32_t isAllGreen(myMahjong mahjong) {
int32_t so2 = mahjong.tilesAmount[SO_2];
int32_t so3 = mahjong.tilesAmount[SO_3];
int32_t so4 = mahjong.tilesAmount[SO_4];
int32_t so6 = mahjong.tilesAmount[SO_6];
int32_t so8 = mahjong.tilesAmount[SO_8];
int32_t green = mahjong.tilesAmount[GREEN];
int32_t total = so2 + so3 + so4 + so6 + so8 + green;
if (total == mahjong.totalTiles) {
return ONE_YAKUMAN;
}
return 0;
}
int32_t isAllHonors(myMahjong mahjong) {
if (amountOfHonors(mahjong) == mahjong.totalTiles) {
return ONE_YAKUMAN;
}
return 0;
}
int32_t isAllTerminals(myMahjong mahjong) {
if (amountOfTerminals(mahjong) == mahjong.totalTiles) {
return ONE_YAKUMAN;
}
return 0;
}
int32_t isBigThreeDragons(myMahjong mahjong) {
int32_t white = mahjong.tilesAmount[WHITE];
int32_t green = mahjong.tilesAmount[GREEN];
int32_t red = mahjong.tilesAmount[RED];
if (white >= 3 && green >= 3 && red >= 3) {
return ONE_YAKUMAN;
}
return 0;
}
int32_t isFourKans(myMahjong mahjong) {
if (mahjong.totalTiles == 18) {
return ONE_YAKUMAN;
}
return 0;
}
int32_t handleYaku(myMahjong mahjong) {
int32_t total = 0;
// 6 Han
if (isFlush(mahjong) == SIX_HAN) {
printYaku(FLUSH);
total += SIX_HAN;
}
// 5 Han
if (isFlush(mahjong) == FIVE_HAN) {
printYaku(FLUSH_OPEN);
total += FIVE_HAN;
}
// 3 Han
if (isHalfFlush(mahjong) == THREE_HAN) {
printYaku(HALF_FLUSH);
total += THREE_HAN;
}
if (isTerminalInEachSet(mahjong) == THREE_HAN) {
printYaku(TERMINAL_IN_EACH_SET);
total += THREE_HAN;
}
// 2 Han
if (isAllTerminalsAndHonors(mahjong) == TWO_HAN) {
printYaku(ALL_TERMINALS_AND_HONORS);
total += TWO_HAN;
}
if (isAllTriplets(mahjong) == TWO_HAN) {
printYaku(ALL_TRIPLETS);
total += TWO_HAN;
}
if (isHalfFlush(mahjong) == TWO_HAN) {
printYaku(HALF_FLUSH_OPEN);
total += TWO_HAN;
}
if (isLittleThreeDragons(mahjong) == TWO_HAN) {
printYaku(LITTLE_THREE_DRAGONS);
total += TWO_HAN;
}
if (isSevenPairs(mahjong) == TWO_HAN) {
printYaku(SEVEN_PAIRS);
total += TWO_HAN;
}
if (isStraight(mahjong) == TWO_HAN) {
printYaku(STRAIGHT);
total += TWO_HAN;
}
if (isTerminalInEachSet(mahjong) == TWO_HAN) {
printYaku(TERMINAL_IN_EACH_SET_OPEN);
total += TWO_HAN;
}
if (isTerminalOrHonorInEachSet(mahjong) == TWO_HAN) {
printYaku(TERMINAL_OR_HONOR_IN_EACH_SET);
total += TWO_HAN;
}
if (isThreeColourStraights(mahjong) == TWO_HAN) {
printYaku(THREE_COLOUR_STRAIGHTS);
total += TWO_HAN;
}
if (isThreeColourTriplets(mahjong) == TWO_HAN) {
printYaku(THREE_COLOUR_TRIPLETS);
total += TWO_HAN;
}
if (isThreeConcealedTriplets(mahjong) == TWO_HAN) {
printYaku(THREE_CONCEALED_TRIPLETS);
total += TWO_HAN;
}
if (isThreeKans(mahjong) == TWO_HAN) {
printYaku(THREE_KANS);
total += TWO_HAN;
}
if (isIdenticalSequences(mahjong) == THREE_HAN) {
printYaku(TWO_SETS_OF_IDENTICAL_SEQUENCES);
total += THREE_HAN;
}
// 1 Han
if (isAllSimples(mahjong) == ONE_HAN) {
printYaku(ALL_SIMPLES);
total += ONE_HAN;
}
if (hasHonerGreen(mahjong) == ONE_HAN) {
printYaku(HONER_GREEN);
total += ONE_HAN;
}
if (hasHonerPlayerWind(mahjong) == ONE_HAN) {
printYaku(HONER_PLAYER_WIND);
total += ONE_HAN;
}
if (hasHonerPrevailingWind(mahjong) == ONE_HAN) {
printYaku(HONER_PREVAILING_WIND);
total += ONE_HAN;
}
if (hasHonerRed(mahjong) == ONE_HAN) {
printYaku(HONER_RED);
total += ONE_HAN;
}
if (hasHonerWhite(mahjong) == ONE_HAN) {
printYaku(HONER_WHITE);
total += ONE_HAN;
}
if (hasNoPointsHand(mahjong) == ONE_HAN) {
printYaku(NO_POINTS_HAND);
total += ONE_HAN;
}
if (isIdenticalSequences(mahjong) == ONE_HAN) {
printYaku(ONE_SET_OF_IDENTICAL_SEQUENCES);
total += ONE_HAN;
}
if (isStraight(mahjong) == ONE_HAN) {
printYaku(STRAIGHT_OPEN);
total += ONE_HAN;
}
if (isTerminalOrHonorInEachSet(mahjong) == ONE_HAN) {
printYaku(TERMINAL_OR_HONOR_IN_EACH_SET_OPEN);
total += ONE_HAN;
}
if (isThreeColourStraights(mahjong) == ONE_HAN) {
printYaku(THREE_COLOUR_STRAIGHTS_OPEN);
total += ONE_HAN;
}
return total;
}
int32_t isFlush(myMahjong mahjong) {
for (int32_t i = 0; i < 3; i++) {
int32_t total = 0;
for (int32_t j = 1; j <= 9; j++) {
total += mahjong.tilesAmount[i * 9 + j];
}
if (total == mahjong.totalTiles) {
return (isClosedHand(mahjong)) ? SIX_HAN : FIVE_HAN;
}
}
return 0;
}
int32_t isHalfFlush(myMahjong mahjong) {
if (amountOfHonors(mahjong) == 0) {
return 0;
}
for (int32_t i = 0; i < 3; i++) {
int32_t totalSuits = 0;
for (int32_t j = 1; j <= 9; j++) {
totalSuits += mahjong.tilesAmount[i * 9 + j];
}
if ((totalSuits + amountOfHonors(mahjong)) == mahjong.totalTiles) {
return (isClosedHand(mahjong)) ? THREE_HAN : TWO_HAN;
}
}
return 0;
}
int32_t isTerminalInEachSet(myMahjong mahjong) {
if (amountOfHonors(mahjong) != 0) {
return 0;
}
int32_t check = 0;
for (int32_t i = 0; i < mahjong.totalMelds; i++) {
int32_t head = (i == 0) ? 0 : mahjong.melds[i-1][MELD_TILES];
int32_t tail = mahjong.melds[i][MELD_TILES];
for (int32_t j = head; j < tail; j++) {
if (isYaochuTile(mahjong.tiles[j])) {
check++;
break;
}
}
}
if (isYaochuTile(mahjong.tiles[mahjong.totalTiles-1])) {
check++;
}
if (check == 5) {
return (isClosedHand(mahjong)) ? THREE_HAN : TWO_HAN;
}
return 0;
}
int32_t isAllTerminalsAndHonors(myMahjong mahjong) {
int32_t honors = amountOfHonors(mahjong);
int32_t terminals = amountOfTerminals(mahjong);
if (honors == 0 || terminals == 0) {
return 0;
}
if (honors + terminals == mahjong.totalTiles) {
return TWO_HAN;
}
return 0;
}
int32_t isAllTriplets(myMahjong mahjong) {
int32_t triplet = 0;
for (int32_t i = 0; i < mahjong.totalMelds; i++) {
if (isTripletOrKanMeld(mahjong, i)) {
triplet++;
}
}
if (triplet == 4) {
return TWO_HAN;
// return (pair == 1) ? TWO_YAKUMAN : ONE_YAKUMAN;
}
return 0;
}
int32_t isLittleThreeDragons(myMahjong mahjong) {
int32_t triplet = 0, pair = 0;
for (int32_t i = WHITE; i <= RED; i++) {
if (mahjong.tilesAmount[i] >= 3) {
triplet++;
} else if (mahjong.tilesAmount[i] == 2) {
pair = 1;
}
}
if (triplet == 2 && pair == 1) {
return TWO_HAN;
}
return 0;
}
int32_t isSevenPairs(myMahjong mahjong) {
int32_t pair = 0;
for (int32_t i = 1; i <= TILE_TYPE; i++) {
if (mahjong.tilesAmount[i] == 2) {
pair++;
} else if (mahjong.tilesAmount[i] != 0) {
return 0;
}
}
if (pair == 7 && mahjong.totalMelds != 4) {
return TWO_HAN;
}
return 0;
}
int32_t isStraight(myMahjong mahjong) {
int32_t check123[3] = {0}, check456[3] = {0}, check789[3] = {0};
for (int32_t i = 0; i < mahjong.totalMelds; i++) {
if (!isStraightMeld(mahjong, i)) {
continue;
}
// printf("is straight!\n");
int32_t head = (i == 0) ? 0 : mahjong.melds[i-1][MELD_TILES];
int32_t tail = mahjong.melds[i][MELD_TILES];
int32_t check[9] = {0};
for (int32_t j = head; j < tail; j++) {
int32_t num = (mahjong.tiles[j] - 1) % 9;
int32_t type = (mahjong.tiles[j] - 1) / 9 + 1;
check[num] = type;
}
// printf("check: ");
// for(int32_t j = 0; j < 9; j++) {
// printf("%d ", check[j]);
// }
// printf("\n");
if (check[0] && (check[0] == check[1]) && (check[0] == check[2])) {
check123[check[0] - 1]++;
}
if (check[3] && (check[3] == check[4]) && (check[3] == check[5])) {
check456[check[3] - 1]++;
}
if (check[6] && (check[6] == check[7]) && (check[6] == check[8])) {
check789[check[6] - 1]++;
}
}
// for (int32_t i = 0; i < 3; i++) {
// printf("i=%d: %d %d %d\n", i+1, check123[i], check456[i], check789[i]);
// }
if ((check123[0] && check456[0] && check789[0]) ||
(check123[1] && check456[1] && check789[1]) ||
(check123[2] && check456[2] && check789[2])) {
return (isClosedHand(mahjong)) ? TWO_HAN : ONE_HAN;
}
return 0;
}
int32_t isTerminalOrHonorInEachSet(myMahjong mahjong) {
if (amountOfHonors(mahjong) == 0) {
return 0;
}
int32_t straight = 0, yaochu = 0;
for (int32_t i = 0; i < mahjong.totalMelds; i++) {
if (isStraightMeld(mahjong, i)) {
straight++;
}
int32_t head = (i == 0) ? 0 : mahjong.melds[i-1][MELD_TILES];
int32_t tail = mahjong.melds[i][MELD_TILES];
for (int32_t i = head; i < tail; i++) {
if (isYaochuTile(mahjong.tiles[i])) {
yaochu++;
break;
}
}
}
if (isYaochuTile(mahjong.tiles[mahjong.totalTiles-1])) {
yaochu++;
}
if (straight && (yaochu == mahjong.totalMelds + 1)) {
return (isClosedHand(mahjong)) ? TWO_HAN : ONE_HAN;
}
return 0;
}
int32_t isThreeColourStraights(myMahjong mahjong) {
int32_t result[7][3] = {0};
for (int32_t i = 0; i < mahjong.totalMelds; i++) {
if (!isStraightMeld(mahjong, i)) {
continue;
}
int32_t head = (i == 0) ? 0 : mahjong.melds[i-1][MELD_TILES];
int32_t tail = mahjong.melds[i][MELD_TILES];
int32_t check[9] = {0};
for (int32_t j = head; j < tail; j++) {
int32_t num = (mahjong.tiles[j] - 1) % 9;
int32_t type = (mahjong.tiles[j] - 1) / 9 + 1;
check[num] = type;
}
for (int32_t j = 0; j < 7; j++) {
if (check[j] && (check[j] == check[j+1]) && (check[j] == check[j+2])) {
result[j][check[j] - 1]++;
}
}
}
// printf(" P S M\n");
// for (int32_t i = 0; i < 7; i++) {
// printf("%d%d%d: ", i+1,i+2,i+3);
// for (int32_t j = 0; j < 3; j++) {
// printf("%d ", result[i][j]);
// }
// printf("\n");
// }
for (int32_t i = 0; i < 7; i++) {
if (result[i][0] && result[i][1] && result[i][2]) {
return (isClosedHand(mahjong)) ? TWO_HAN : ONE_HAN;
}
}
return 0;
}
int32_t isThreeColourTriplets(myMahjong mahjong) {
int32_t result[9][3] = {0};
for (int32_t i = 0; i < mahjong.totalMelds; i++) {
if (!isTripletOrKanMeld(mahjong, i)) {
continue;
}
int32_t head = (i == 0) ? 0 : mahjong.melds[i-1][MELD_TILES];
int32_t tile = mahjong.tiles[head];
if (isHonorTile(tile)) {
continue;
}
result[(tile - 1) % 9][(tile - 1) / 9]++;
}
// printf(" P S M\n");
// for (int32_t i = 0; i < 9; i++) {
// printf("%d: ", i+1);
// for (int32_t j = 0; j < 3; j++) {
// printf("%d ", result[i][j]);
// }
// printf("\n");
// }
for (int32_t i = 0; i < 9; i++) {
if (result[i][0] && result[i][1] && result[i][2]) {
return TWO_HAN;
}
}
return 0;
}
int32_t isThreeConcealedTriplets(myMahjong mahjong) {
int32_t close = 0;
for (int32_t i = 0; i < mahjong.totalMelds; i++) {
if (!isTripletOrKanMeld(mahjong, i)) {
continue;
}
if (mahjong.melds[i][MELD_OPEN] == 0) {
close++;
}
}
if (close == 3) {
return TWO_HAN;
}
return 0;
}
int32_t isThreeKans(myMahjong mahjong) {
if (mahjong.totalTiles == 17) {
return TWO_HAN;
}
return 0;
}
int32_t isIdenticalSequences(myMahjong mahjong) {
if (!isClosedHand(mahjong)) {
return 0;
}
int32_t result[7][3] = {0};
for (int32_t i = 0; i < mahjong.totalMelds; i++) {
if (!isStraightMeld(mahjong, i)) {
continue;
}
int32_t head = (i == 0) ? 0 : mahjong.melds[i-1][MELD_TILES];
int32_t tail = mahjong.melds[i][MELD_TILES];
int32_t check[9] = {0};
for (int32_t j = head; j < tail; j++) {
int32_t num = (mahjong.tiles[j] - 1) % 9;
int32_t type = (mahjong.tiles[j] - 1) / 9 + 1;
check[num] = type;
}
for (int32_t j = 0; j < 7; j++) {
if (check[j] && (check[j] == check[j+1]) && (check[j] == check[j+2])) {
result[j][check[j] - 1]++;
}
}
}
int32_t identical = 0;
for (int32_t i = 0; i < 7; i++) {
for (int32_t j = 0; j < 3; j++) {
if (result[i][j] == 2) {
identical++;
}
}
}
if (identical == 2) {
return THREE_HAN;
} else if (identical == 1) {
return ONE_HAN;
}
return 0;
}
int32_t isAllSimples(myMahjong mahjong) {
for (int32_t i = 0; i < mahjong.totalTiles; i++) {
if (isYaochuTile(mahjong.tiles[i])) {
return 0;
}
}
return ONE_HAN;
}
int32_t hasHonerGreen(myMahjong mahjong) {
if (mahjong.tilesAmount[GREEN] >= 3) {
return ONE_HAN;
}
return 0;
}
int32_t hasHonerPlayerWind(myMahjong mahjong) {
for (int32_t i = EAST; i <= NORTH; i++) {
if (mahjong.tilesAmount[i] >= 3 && (mahjong.playerWind + EAST == i)) {
return ONE_HAN;
}
}
return 0;
}
int32_t hasHonerPrevailingWind(myMahjong mahjong) {
for (int32_t i = EAST; i <= NORTH; i++) {
if (mahjong.tilesAmount[i] >= 3 && (mahjong.prevailingWind + EAST == i)) {
return ONE_HAN;
}
}
return 0;
}
int32_t hasHonerRed(myMahjong mahjong) {
if (mahjong.tilesAmount[RED] >= 3) {
return ONE_HAN;
}
return 0;
}
int32_t hasHonerWhite(myMahjong mahjong) {
if (mahjong.tilesAmount[WHITE] >= 3) {
return ONE_HAN;
}
return 0;
}
int32_t hasNoPointsHand(myMahjong mahjong) {
if (!isClosedHand(mahjong)) {
return 0;
}
int32_t noPointsHand = 0;
for (int32_t i = 0; i < mahjong.totalMelds; i++) {
if (!isStraightMeld(mahjong, i)) {
return 0;
}
int32_t head = (i == 0) ? 0 : mahjong.melds[i-1][MELD_TILES];
int32_t tail = mahjong.melds[i][MELD_TILES];
int32_t check[9] = {0};
for (int32_t j = head; j < tail; j++) {
int32_t num = (mahjong.tiles[j] - 1) % 9;
check[num] = mahjong.tiles[j];
}
for (int32_t j = 0; j < 7; j++) {
if ((check[j] && check[j+1] == mahjong.winningTile) ||
(j == 6 && check[j] == mahjong.winningTile) ||
(j == 0 && check[j+2] == mahjong.winningTile)) {
break;
} else if (check[j] == mahjong.winningTile ||
(check[j] && check[j+2] == mahjong.winningTile)) {
noPointsHand++;
break;
}
}
}
if (noPointsHand) {
return ONE_HAN;
}
return 0;
}
void printYaku(int32_t yaku) {
printf(" ");
switch (yaku) {
// Two Yakuman
case BIG_FOUR_WINDS:
printf("Big four winds (2 Yakuman)\n"); break;
case FOUR_CONCEALED_TRIPLETS_SINGLE_WAIT:
printf("Four concealed triplets single wait (2 Yakuman)\n"); break;
case NINE_GATES_NINE_WAIT:
printf("Nine gates nine wait (2 Yakuman)\n"); break;
case THIRTEEN_ORPHANS_13_WAIT:
printf("Thirteen orphans 13 wait (2 Yakuman)\n"); break;
// One Yakuman
case ALL_GREEN:
printf("All green (1 Yakuman)\n"); break;
case ALL_HONORS:
printf("All honors (1 Yakuman)\n"); break;
case ALL_TERMINALS:
printf("All terminals (1 Yakuman)\n"); break;
case BIG_THREE_DRAGONS:
printf("Big three dragons (1 Yakuman)\n"); break;
case FOUR_CONCEALED_TRIPLETS:
printf("Four concealed triplets (1 Yakuman)\n"); break;
case FOUR_KANS:
printf("Four kans (1 Yakuman)\n"); break;
case LITTLE_FOUR_WINDS:
printf("Little four winds (1 Yakuman)\n"); break;
case NINE_GATES:
printf("Nine gates (1 Yakuman)\n"); break;
case THIRTEEN_ORPHANS:
printf("Thirteen orphans (1 Yakuman)\n"); break;
// 6 Han
case FLUSH:
printf("Flush (6 Han)\n"); break;
// 5 Han
case FLUSH_OPEN:
printf("Flush (5 Han)\n"); break;
// 3 Han
case HALF_FLUSH:
printf("Half-flush (3 Han)\n"); break;
case TERMINAL_IN_EACH_SET:
printf("Terminal in each set (3 Han)\n"); break;
case TWO_SETS_OF_IDENTICAL_SEQUENCES:
printf("Two sets of identical sequences (3 Han)\n"); break;
// 2 Han
case ALL_TERMINALS_AND_HONORS:
printf("All terminals and honors (2 Han)\n"); break;
case ALL_TRIPLETS:
printf("All triplets (2 Han)\n"); break;
case HALF_FLUSH_OPEN:
printf("Half-flush (2 Han)\n"); break;
case LITTLE_THREE_DRAGONS:
printf("Little three dragons (2 Han)\n"); break;
case SEVEN_PAIRS:
printf("Seven pairs (2 Han)\n"); break;
case STRAIGHT:
printf("Straight (2 Han)\n"); break;
case TERMINAL_IN_EACH_SET_OPEN:
printf("Terminal in each set (2 Han)\n"); break;
case TERMINAL_OR_HONOR_IN_EACH_SET:
printf("Terminal or honor in each set (2 Han)\n"); break;
case THREE_COLOUR_STRAIGHTS:
printf("Three colour straights (2 Han)\n"); break;
case THREE_COLOUR_TRIPLETS:
printf("Three colour triplets (2 Han)\n"); break;
case THREE_CONCEALED_TRIPLETS:
printf("Three concealed triplets (2 Han)\n"); break;
case THREE_KANS:
printf("Three kans (2 Han)\n"); break;
// 1 Han
case ALL_SIMPLES:
printf("All simples (1 Han)\n"); break;
case HONER_GREEN:
printf("Honer: Green (1 Han)\n"); break;
case HONER_PLAYER_WIND:
printf("Honer: Player's wind (1 Han)\n"); break;
case HONER_PREVAILING_WIND:
printf("Honer: Prevailing wind (1 Han)\n"); break;
case HONER_RED:
printf("Honer: Red (1 Han)\n"); break;
case HONER_WHITE:
printf("Honer: White (1 Han)\n"); break;
case NO_POINTS_HAND:
printf("No-points Hand (1 Han)\n"); break;
case ONE_SET_OF_IDENTICAL_SEQUENCES:
printf("One set of identical sequences (1 Han)\n"); break;
case STRAIGHT_OPEN:
printf("Straight (1 Han)\n"); break;
case TERMINAL_OR_HONOR_IN_EACH_SET_OPEN:
printf("Terminal or honor in each set (1 Han)\n"); break;
case THREE_COLOUR_STRAIGHTS_OPEN:
printf("Three colour straights (1 Han)\n"); break;
case NO_YAKU:
printf("No Yaku\n"); break;
// Error
case ERROR_YAKU:
default:
printf("Unreasonable case\n"); break;
}
}
```
:::
## 4.6 What Happens?