75 char *string = move->string; |
75 char *string = move->string; |
76 |
76 |
77 /* at least 8 characters should be available, wipe them out */ |
77 /* at least 8 characters should be available, wipe them out */ |
78 memset(string, 0, 8); |
78 memset(string, 0, 8); |
79 |
79 |
80 /* special formats for castling */ |
80 unsigned int idx; |
81 if ((move->piece&PIECE_MASK) == KING && |
81 if ((move->piece&PIECE_MASK) == KING && |
82 abs(move->tofile-move->fromfile) == 2) { |
82 abs(move->tofile-move->fromfile) == 2) { |
|
83 /* special formats for castling */ |
83 if (move->tofile==fileidx('c')) { |
84 if (move->tofile==fileidx('c')) { |
84 memcpy(string, "O-O-O", 5); |
85 memcpy(string, "O-O-O", 5); |
|
86 idx = 5; |
85 } else { |
87 } else { |
86 memcpy(string, "O-O", 3); |
88 memcpy(string, "O-O", 3); |
87 } |
89 idx = 3; |
88 } |
90 } |
89 |
91 } else { |
90 /* start by notating the piece character */ |
92 /* start by notating the piece character */ |
91 string[0] = getpiecechr(move->piece); |
93 string[0] = getpiecechr(move->piece); |
92 int idx = string[0] ? 1 : 0; |
94 idx = string[0] ? 1 : 0; |
93 |
95 |
94 /* find out how many source information we do need */ |
96 /* find out how many source information we do need */ |
95 uint8_t piece = move->piece & PIECE_MASK; |
97 uint8_t piece = move->piece & PIECE_MASK; |
96 if (piece == PAWN) { |
98 if (piece == PAWN) { |
|
99 if (move->capture) { |
|
100 string[idx++] = filechr(move->fromfile); |
|
101 } |
|
102 } else if (piece != KING) { |
|
103 /* resolve ambiguities, if any */ |
|
104 Move threats[16]; |
|
105 uint8_t threatcount; |
|
106 get_real_threats(gamestate, move->torow, move->tofile, |
|
107 move->piece&COLOR_MASK, threats, &threatcount); |
|
108 if (threatcount > 1) { |
|
109 int ambrows = 0, ambfiles = 0; |
|
110 for (uint8_t i = 0 ; i < threatcount ; i++) { |
|
111 if (threats[i].fromrow == move->fromrow) { |
|
112 ambrows++; |
|
113 } |
|
114 if (threats[i].fromfile == move->fromfile) { |
|
115 ambfiles++; |
|
116 } |
|
117 } |
|
118 /* ambiguous row, name file */ |
|
119 if (ambrows > 1) { |
|
120 string[idx++] = filechr(move->fromfile); |
|
121 } |
|
122 /* ambiguous file, name row */ |
|
123 if (ambfiles > 1) { |
|
124 string[idx++] = filechr(move->fromrow); |
|
125 } |
|
126 } |
|
127 } |
|
128 |
|
129 /* capturing? */ |
97 if (move->capture) { |
130 if (move->capture) { |
98 string[idx++] = filechr(move->fromfile); |
131 string[idx++] = 'x'; |
99 } |
132 } |
100 } else if (piece != KING) { |
133 |
101 Move threats[16]; |
134 /* destination */ |
102 uint8_t threatcount; |
135 string[idx++] = filechr(move->tofile); |
103 get_real_threats(gamestate, move->torow, move->tofile, |
136 string[idx++] = rowchr(move->torow); |
104 move->piece&COLOR_MASK, threats, &threatcount); |
137 |
105 if (threatcount > 1) { |
138 /* promotion? */ |
106 int ambrows = 0, ambfiles = 0; |
139 if (move->promotion) { |
107 for (uint8_t i = 0 ; i < threatcount ; i++) { |
140 string[idx++] = '='; |
108 if (threats[i].fromrow == move->fromrow) { |
141 string[idx++] = getpiecechr(move->promotion); |
109 ambrows++; |
142 } |
110 } |
|
111 if (threats[i].fromfile == move->fromfile) { |
|
112 ambfiles++; |
|
113 } |
|
114 } |
|
115 /* ambiguous row, name file */ |
|
116 if (ambrows > 1) { |
|
117 string[idx++] = filechr(move->fromfile); |
|
118 } |
|
119 /* ambiguous file, name row */ |
|
120 if (ambfiles > 1) { |
|
121 string[idx++] = filechr(move->fromrow); |
|
122 } |
|
123 } |
|
124 } |
|
125 |
|
126 /* capturing? */ |
|
127 if (move->capture) { |
|
128 string[idx++] = 'x'; |
|
129 } |
|
130 |
|
131 /* destination */ |
|
132 string[idx++] = filechr(move->tofile); |
|
133 string[idx++] = rowchr(move->torow); |
|
134 |
|
135 /* promotion? */ |
|
136 if (move->promotion) { |
|
137 string[idx++] = '='; |
|
138 string[idx++] = getpiecechr(move->promotion); |
|
139 } |
143 } |
140 |
144 |
141 /* check? */ |
145 /* check? */ |
142 if (move->check) { |
146 if (move->check) { |
143 /* works only, if this function is called when applying the move */ |
147 /* works only, if this function is called when applying the move */ |
454 Move candidates[32]; |
458 Move candidates[32]; |
455 int candidatecount = 0; |
459 int candidatecount = 0; |
456 for (uint8_t r = 0 ; r < 8 ; r++) { |
460 for (uint8_t r = 0 ; r < 8 ; r++) { |
457 for (uint8_t f = 0 ; f < 8 ; f++) { |
461 for (uint8_t f = 0 ; f < 8 ; f++) { |
458 if ((gamestate->board[r][f] & COLOR_MASK) == color) { |
462 if ((gamestate->board[r][f] & COLOR_MASK) == color) { |
459 // non-capturing move |
463 /* non-capturing move */ |
460 memset(&(candidates[candidatecount]), 0, sizeof(Move)); |
464 memset(&(candidates[candidatecount]), 0, sizeof(Move)); |
461 candidates[candidatecount].piece = gamestate->board[r][f]; |
465 candidates[candidatecount].piece = gamestate->board[r][f]; |
462 candidates[candidatecount].fromrow = r; |
466 candidates[candidatecount].fromrow = r; |
463 candidates[candidatecount].fromfile = f; |
467 candidates[candidatecount].fromfile = f; |
464 candidates[candidatecount].torow = row; |
468 candidates[candidatecount].torow = row; |
465 candidates[candidatecount].tofile = file; |
469 candidates[candidatecount].tofile = file; |
466 candidatecount++; |
470 candidatecount++; |
467 |
471 |
468 // capturing move |
472 /* capturing move */ |
469 memcpy(&(candidates[candidatecount]), |
473 memcpy(&(candidates[candidatecount]), |
470 &(candidates[candidatecount-1]), sizeof(Move)); |
474 &(candidates[candidatecount-1]), sizeof(Move)); |
471 candidates[candidatecount].capture = 1; |
475 candidates[candidatecount].capture = 1; |
472 candidatecount++; |
476 candidatecount++; |
473 } |
477 } |
570 if (get_threats(gamestate, move->torow, move->tofile, color, |
574 if (get_threats(gamestate, move->torow, move->tofile, color, |
571 threats, &threatcount)) { |
575 threats, &threatcount)) { |
572 |
576 |
573 int reason = INVALID_POSITION; |
577 int reason = INVALID_POSITION; |
574 |
578 |
575 // find threats for the specified position |
579 /* find threats for the specified position */ |
576 for (uint8_t i = 0 ; i < threatcount ; i++) { |
580 for (uint8_t i = 0 ; i < threatcount ; i++) { |
577 if ((threats[i].piece & (PIECE_MASK | COLOR_MASK)) |
581 if ((threats[i].piece & (PIECE_MASK | COLOR_MASK)) |
578 == move->piece && |
582 == move->piece && |
579 (move->fromrow == POS_UNSPECIFIED || |
583 (move->fromrow == POS_UNSPECIFIED || |
580 move->fromrow == threats[i].fromrow) && |
584 move->fromrow == threats[i].fromrow) && |
582 move->fromfile == threats[i].fromfile)) { |
586 move->fromfile == threats[i].fromfile)) { |
583 |
587 |
584 if (threat) { |
588 if (threat) { |
585 return AMBIGUOUS_MOVE; |
589 return AMBIGUOUS_MOVE; |
586 } else { |
590 } else { |
587 // found threat is no real threat |
591 /* found threat is no real threat */ |
588 if (is_pinned(gamestate, &(threats[i]))) { |
592 if (is_pinned(gamestate, &(threats[i]))) { |
589 reason = incheck?KING_IN_CHECK:PIECE_PINNED; |
593 reason = incheck?KING_IN_CHECK:PIECE_PINNED; |
590 } else { |
594 } else { |
591 threat = &(threats[i]); |
595 threat = &(threats[i]); |
592 } |
596 } |
593 } |
597 } |
594 } |
598 } |
595 } |
599 } |
596 |
600 |
597 // can't threaten specified position |
601 /* can't threaten specified position */ |
598 if (!threat) { |
602 if (!threat) { |
599 return reason; |
603 return reason; |
600 } |
604 } |
601 |
605 |
602 memcpy(move, threat, sizeof(Move)); |
606 memcpy(move, threat, sizeof(Move)); |