# 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?