我在C中创建了一款名为“符文”的游戏,类似于国际象棋,但它有一个更大的棋盘和不同的棋子。我想知道如何改进代码,例如,通过用户界面的改进。
这个问题并不是那个问题的重复,因为在另一个问题中,这个问题有一个修改过的、易于阅读的代码版本。
/*
* runes.c The Game of Runes, similar to chess.
*
* RULES
* Pieces: Wizard, Peasant, Knight, Emperor, Archer, Dragon.
*
* Attack Abilities:
* Wizard can attack wizard, peasant, knight, emperor, archer.
* Peasant can attack peasant, knight.
* Knight can attack peasant, knight, emperor.
* Emperor cannot attack.
* Archer cannot attack, can only shoot.
* Dragon can attack anything.
*
* Movement Abilities:
* All pieces can move 1 square in any direction except for the following:
* Knight. It moves in the L shape, as in chess. It can jump over pieces.
* Dragon. Each turn, it can move 3 squares in any direction. It can jump
* over pieces. However, it cannot hover above a piece.
*
* Shooting Pieces:
* All pieces can kill enemy pieces if they can walk over them, with two
* exceptions:
* Archer. It can kill enemy pieces with 2 squares between them, 1 if
* diagonal. 1 piece cannot block the arrow, but 2 pieces can.
* Wizard. Same as Archer.
* Dragon. It can kill enemy pieces with up to 1 square between them, 1 if
* diagonal
*
* The Wizard, Dragon and Emperor are major pieces.
* The Peasant, Knight, and Archer are minor pieces.
* In general, major pieces are more "valuable" than minor pieces.
*
* Each turn, you can move up to 9 pieces, but you must move at least one.
* This is so you can move either of your four "battalions" at once (see
* diagram below).
*
* The objective of this game is to kill the opposing Dragon AND the opposing
* Emperor.
*
* TECHNICAL INFORMATION
* There is an array of 256 elements which describes the position of the
* pieces on the board. Starting at the top left.
*/
/* INITIAL PIECE POSITIONS
+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
16| | | | | | | | d | e | | | | | | | | <-- Black Side
+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
15| p | p | p | | p | p | p | | | p | p | p | | p | p | p |
+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
14| p | w | p | | p | w | p | | | p | w | p | | p | w | p |
+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
13| p | p | p | | p | p | p | | | p | p | p | | p | p | p |
+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
12| | | | | | | | | | | | | | | | |
+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
11| k | a | k | a | k | a | k | a | a | k | a | k | a | k | a | k |
+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
10| | | | | | | | | | | | | | | | |
+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
9 | | | | | | | | | | | | | | | | |
+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
8 | | | | | | | | | | | | | | | | |
+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
7 | | | | | | | | | | | | | | | | |
+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
6 | K | A | K | A | K | A | K | A | A | K | A | K | A | K | A | K |
+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
5 | | | | | | | | | | | | | | | | |
+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
4 | P | P | P | | P | P | P | | | P | P | P | | P | P | P |
+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
3 | P | W | P | | P | W | P | | | P | W | P | | P | W | P |
+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
2 | P | P | P | | P | P | P | | | P | P | P | | P | P | P |
+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
1 | | | | | | | | E | D | | | | | | | | <-- White Side
Y +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
X 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
/* Define constants for a black space and the players */
#define EMPTY ' '
#define BLACK 0
#define WHITE 1
/*
* This function gets the value of the piece on the board if any. Otherwise it
* returns EMPTY which is defined above. The x/y coordinates are on the board
* diagram above. Remember x=horizontal y=vertical. However, due to simplicity
* the x and y values are inverted, i.e. x=3,y=3 would be board[51]. Also,
* x=0,y=0 would be the top right.
*/
char get_piece_on_board(unsigned short x, unsigned short y, char board[])
{
return board[x+(y*16)];
}
/*
* Set a piece to a value. No error checking done.
*/
void set_piece(unsigned short x, unsigned short y, char piece, char board[])
{
board[x+(y*16)] = piece;
}
/*
* This should be obvious, it renders the board onto the screen.
*/
void render_board(char board[])
{
unsigned short x;
unsigned short y;
printf("+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+\n");
for (y = 0; y < 16; y++) {
for (x = 0; x < 16; x++) {
printf("| %c ", get_piece_on_board(x, y, board));
}
printf("|\n+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+\n");
}
}
/*
* Return WHITE or BLACK depending on the colour of a piece.
*/
char get_colour(char piece)
{
if (piece == EMPTY) {
return EMPTY;
}
return islower(piece) ? BLACK : WHITE;
}
/*
* Get the strength of a piece, from 0 to 6. We have a strength table here:
* On the left side of the chart is the attacking piece and the columns
* represent the piece that is being attacked. Note that this is for melee
* attacking only. Ranged attacks can hit anything.
* D A W P K E
* D 1 1 1 1 1 1 = 6
* W 1 1 1 1 1 = 5
* K 1 1 1 1 = 4
* P 1 1 1 = 3
* A = 0
* E = 0
*/
unsigned short get_strength(char piece)
{
switch (toupper(piece)) {
case 'D':
case 'A':
return 6;
break;
case 'W':
return 5;
break;
case 'K':
return 4;
break;
case 'P':
return 3;
break;
default:
return 0;
}
}
/*
* Check if a p1 is stronger than p2, i.e. can piece1 capture piece2?
*/
unsigned short is_stronger_than(unsigned short p1x, unsigned short p1y, unsigned short p2x, unsigned short p2y, char board[])
{
unsigned short s1 = get_strength(get_piece_on_board(p1x, p1y, board));
unsigned short s2 = get_strength(get_piece_on_board(p2x, p2y, board));
return s1 > 0 && s1 >= s2;
}
/*
* This function moves a piece. If you try to move the opponent's piece, it
* will display an error. If you try to move your piece into another of your
* pieces, it will also display an error. If you move your piece into the
* piece of an opponent, it will check if your piece is powerful enough to
* capture that piece. If so, the function will call set_piece() to capture
* your opponent's piece. Much of the logic in this program is in here.
*/
void move_piece(unsigned short oldx, unsigned short oldy, unsigned short newx, unsigned short newy, char current_player, char board[])
{
char oldpiece = get_piece_on_board(oldx, oldy, board);
char newpiece = get_piece_on_board(newx, newy, board);
/* First, check if that move is possible */
if (get_colour(oldpiece) != current_player) {
printf("Can't control other team member\n");
return;
} else if (get_colour(newpiece) == current_player) {
printf("Refrained from killing own team member\n");
return;
} else if (get_colour(oldpiece) == EMPTY) {
printf("The blank is not listening to you\n");
return;
}
/* These rules only apply for capturing another piece */
if (get_colour(newpiece) != EMPTY && is_stronger_than(oldx, oldy, newx, newy, board)) {
printf("Can't kill stronger piece\n");
return;
}
set_piece(newx, newy, get_piece_on_board(oldx, oldy, board), board);
set_piece(oldx, oldy, EMPTY, board); /* clear out old piece */
}
/*
* Tells a shooter (shooter x, shooter y) to shoot victim (victim x, victim y)
* Only archer, dragon and wizard can shoot. Note that shooting is very
* distinct from capturing, because when shooting anything can be attacked
* and the shooter does not move
*/
void shoot(unsigned short sx, unsigned short sy, unsigned short vx, unsigned short vy, char current_player, char board[])
{
char shooter = get_piece_on_board(sx, sy, board);
char victim = get_piece_on_board(vx, vy, board);
if (get_piece_on_board(sx, sy, board) != 'w' && get_piece_on_board(sx, sy, board) != 'W' && get_piece_on_board(sx, sy, board) != 'a' && get_piece_on_board(sx, sy, board) != 'A' && get_piece_on_board(sx, sy, board) != 'd' && get_piece_on_board(sx, sy, board) != 'D') {
printf("The blank will not follow orders\n");
return;
} else if (get_colour(shooter) != current_player) {
printf("Can't control other team member\n");
return;
} else if (get_colour(victim) == current_player) {
printf("Refrained from shooting own team member\n");
return;
} else if (get_colour(victim) == EMPTY) {
printf("Wasted arrow shooting empty square\n");
return;
}
set_piece(vx, vy, EMPTY, board); /* clear out killed piece */
}
/*
* This function prints out the title in ASCII art.
*/
void print_header(void)
{
printf("\n");
printf( "8888888 88 88 8888 88 8888888 8888888\n"
"88 88 88 88 88 88 88 88 88\n"
"8888888 88 88 88 88 88 8888888 88888\n"
"88 88 88 88 88 88 88 88 8888\n"
"88 88 88 88 88 88 88 88 88\n"
"88 88 8888888 88 8888 8888888 888888\n");
printf("\n");
}
/*
* Print out the instructions for Runes
*/
void print_instructions(void)
{
printf(
"RUNES INSTRUCTIONS:\n"
"Runes is a strategy game similar to chess. The key differences are the names\n"
"of the pieces, how they move, and that the board size is doubled. This aims\n"
"to create a more interesting game.\n"
"\n"
"Pieces:\n"
"There are 6 types of pieces: Peasant, Knight, Wizard, Emperor, Dragon, Archer.\n"
"All pieces can move 1 square in 8 directions, including diagonals, except for\n"
"the Dragon and the Knight. The Knight moves in the same L-shape as in chess,\n"
"and the Dragon can move 3 squares in a turn. The Knight and the Dragon can fly\n"
"or jump/teleport over pieces.\n"
"\n"
"Abilities:\n"
"The Dragon can breathe fire on a piece and destroy it if it is up to 1 square\n"
"away from it. This includes being right next to it, and being seperated by a\n"
"square. The Archer can shoot arrows at pieces if they are seperated by 2 squares\n"
"with at most 1 other piece between them. The Wizard does the same as the Archer,\n"
"except that the Wizard also shields ally pieces from any kind of damage if they\n"
"are right next to him. The only way to destroy a Battalion (a formation with a\n"
"Wizard in the center of other pieces) is to use a Dragon, Archer or another\n"
"Wizard.\n"
"\n"
"Piece Melee Strength:\n"
"A piece can only destroy other pieces if it is 'stronger' than that piece.\n"
"Here is a list of pieces and their point value:\n"
"Dragon can attack anything.\n"
"Wizard can attack anything except for Dragon.\n"
"Archer cannot attack.\n"
"Peasant can attack Peasant, Knight and Emperor.\n"
"Knight can attack Peasant, Knight, Emperor and Wizard.\n"
"Emperor cannot attack.\n"
"\n"
"Miscellaneous:\n"
"The objective is to destroy the opposing side's empereror and dragon. During\n"
"your nine turns, you cannot move one piece more than once. When shooting, all\n"
"projectiles can kill anything.\n"
);
}
/*
* Asks the user what to do
*/
void print_menu(char board[])
{
char choice;
printf("1. Start Game\n");
printf("2. Instructions\n");
printf("3. Exit\n");
printf("runes n> ");
choice = getchar();
switch (choice) {
case '1':
render_board(board);
return;
case '2':
print_instructions();
exit(EXIT_SUCCESS);
case '3':
exit(EXIT_SUCCESS);
default:
fprintf(stderr, "\nInvalid entry\n");
exit(EXIT_FAILURE);
}
}
/*
* Read a line from stdin for runes commands such as move.
*/
char *read_command_line(void)
{
char *line = NULL;
size_t bufsize = 0;
if (getline(&line, &bufsize, stdin) == -1) {
perror("getline");
}
return line;
}
/*
* Split the line into tokens.
*/
char **split_line(char *line)
{
const short int const_bufsize = 64;
const char delim[] = " \t\r\n\a";
int bufsize = const_bufsize;
int position;
char **tokens = malloc(bufsize * sizeof(char*));
char *token;
if (!tokens) {
perror("malloc");
exit(EXIT_FAILURE);
}
token = strtok(line, delim);
for (position = 0; token != NULL; position++) {
tokens[position] = token;
if (position >= bufsize) {
bufsize += const_bufsize;
tokens = realloc(tokens, bufsize * sizeof(char*));
if (!tokens) {
perror("malloc");
exit(EXIT_FAILURE);
}
}
token = strtok(NULL, delim);
}
tokens[position] = NULL;
return tokens;
}
/*
* Check for a winner. If so, print out and exit.
*/
void check_winner(char board[])
{
/* 4 bytes to tell if the emperors and dragons are present */
char wempror;
char bempror;
char wdragon;
char bdragon;
/* Initialise the emperors and dragons */
wempror = bempror = wdragon = bdragon = 0;
/* Loop through the board and check for the Emperor and the Dragon */
for (unsigned short i = 0; i <= 256; i++) {
if (board[i] == 'D') wdragon = 1;
if (board[i] == 'd') bdragon = 1;
if (board[i] == 'E') wempror = 1;
if (board[i] == 'e') bempror = 1;
}
/* Check if a side has lost */
if (!wdragon && !wempror) {
printf("White lost, Black won\n");
exit(EXIT_SUCCESS);
}
if (!bdragon && !bempror) {
printf("Black lost, White won\n");
exit(EXIT_SUCCESS);
}
}
/*
* Run runes commands: move, exit, surrender, pass, flee, help, instructions,
* render, shoot
* This function returns 1 if a turn was NOT used, 0 otherwise.
*/
unsigned short run_runes_commands(char **args, char current_player, char board[])
{
/* The pass command means skip current turn */
if (args[0] == NULL || strcmp(args[0], "pass") == 0) {
return 0; /* Turn was used */
} else if (strcmp(args[0], "surrender") == 0 || strcmp(args[0], "flee") == 0) { /* the other player wins */
if (current_player == WHITE) {
printf("White has surrendered, Black wins\n");
} else if (current_player == BLACK) {
printf("Black has surrendered, White wins\n");
}
exit(EXIT_SUCCESS);
} else if (strcmp(args[0], "exit") == 0) { /* unconditional exit */
exit(EXIT_SUCCESS);
} else if (strcmp(args[0], "move") == 0) {
if (args[1] == NULL || args[2] == NULL || args[3] == NULL || args[4] == NULL) {
printf("usage: move <oldx> <oldy> <newx> <newy>\n");
return 1;
}
move_piece(atoi(args[1])-1, atoi(args[2])-1, atoi(args[3])-1, atoi(args[4])-1, current_player, board);
render_board(board);
} else if (strcmp(args[0], "instructions") == 0) {
print_instructions();
return 1;
} else if (strcmp(args[0], "render") == 0) {
render_board(board);
return 1;
} else if (strcmp(args[0], "shoot") == 0) {
if (args[1] == NULL || args[2] == NULL || args[3] == NULL || args[4] == NULL) {
printf("usage: shoot <sx> <sy> <vx> <vy>\n");
return 1;
}
shoot(atoi(args[1])-1, atoi(args[2])-1, atoi(args[3])-1, atoi(args[4])-1, current_player, board);
render_board(board);
} else if (strcmp(args[0], "help") == 0) {
printf( "Runes Commands Help:\n"
"help - Show this help\n"
"surrender - lose, other player wins\n"
"flee - same as surrender\n"
"move - move a piece\n"
"pass - skip this move\n"
"instructions - redisplay instructions\n"
"render - redisplay board\n"
"shoot - shoot enemies\n"
"exit - quit game immediately\n");
return 1;
} else {
printf("Invalid command\n");
return 1;
}
return 0;
}
/*
* The aim is to put most of the code into the other functions, and keep main
* as neat as possible.
*/
int main(void)
{
char *line;
char **args;
const char players[] = "bw";
char board[256] = {
' ',' ',' ',' ',' ',' ',' ','d','e',' ',' ',' ',' ',' ',' ',' ',
'p','p','p',' ','p','p','p',' ',' ','p','p','p',' ','p','p','p',
'p','w','p',' ','p','w','p',' ',' ','p','w','p',' ','p','w','p',
'p','p','p',' ','p','p','p',' ',' ','p','p','p',' ','p','p','p',
' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',
'k','a','k','a','k','a','k','a','a','k','a','k','a','k','a','k',
' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',
' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',
' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',
' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',
'K','A','K','A','K','A','K','A','A','K','A','K','A','K','A','K',
' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',
'P','P','P',' ','P','P','P',' ',' ','P','P','P',' ','P','P','P',
'P','W','P',' ','P','W','P',' ',' ','P','W','P',' ','P','W','P',
'P','P','P',' ','P','P','P',' ',' ','P','P','P',' ','P','P','P',
' ',' ',' ',' ',' ',' ',' ','E','D',' ',' ',' ',' ',' ',' ',' '
};
print_header();
print_menu(board);
/* Main loop */
for (char current_player = WHITE; ; current_player = WHITE - current_player) {
for (unsigned short i = 0; i <= 9; i++) {
printf("runes %c> ", players[(int)current_player]);
line = read_command_line();
args = split_line(line);
if (run_runes_commands(args, current_player, board)) {
i--;
}
free(line);
free(args);
check_winner(board);
}
}
}发布于 2015-08-08 20:00:08
这段代码得到了改进,我看到您已经添加了命令shoot。我认为您仍然可以做一些事情来进一步改进代码。
能够在两个动作中获胜有点令人失望:
shoot 9 16 8 1
shoot 9 16 9 1这不应该是不可能的,因为龙不应该能够射击整个委员会。代码应该强制执行规则。
目前,代码中没有任何东西阻止将一块完全移出为板分配的空间之外。run_runes_commands例程应该验证坐标,或者底层的射击或移动处理程序应该这样做。
struct中
现在有两个基本的东西代表游戏状态,那就是board本身和current_player。此外,与其每次扫描整个棋盘,还可以追踪双方是否仍有龙和皇帝的棋子。我建议将所有这些信息存储在一个struct中,然后传递指向相关函数的struct指针。
的检查
与其传递坐标,不如将分段值传递到is_stronger_than:
unsigned short is_stronger_than(char oldpiece, char newpiece)
{
unsigned short s1 = get_strength(oldpiece);
unsigned short s2 = get_strength(newpiece);
return s2 > s1 || s1 == 0;
}现在,调用代码也简化了:
if (is_stronger_than(oldpiece, newpiece)) {您可以通过让get_strength返回一个弓箭手或皇帝的1和空方块的0的值来明确地检查一个空正方形的需要。
的检查
if的第一个shoot()子句过于复杂:
if (get_piece_on_board(sx, sy, board) != 'w' && get_piece_on_board(sx, sy, board) != 'W' && get_piece_on_board(sx, sy, board) != 'a' && get_piece_on_board(sx, sy, board) != 'A' && get_piece_on_board(sx, sy, board) != 'd' && get_piece_on_board(sx, sy, board) != 'D') {它可以大大简化:
if (shooter == EMPTY) {if...else测试时要小心
在move_piece例程中,由于第一个if子句,将永远不会打印“空白不听您的话”的消息:
if (get_colour(oldpiece) != current_player) {相反,空方块的检查应该首先进行。
if (oldpiece == EMPTY) {中使用const
在get_piece_on_board例程中,底层board不会被更改。通过声明参数const使其显式化:
char get_piece_on_board(unsigned short x, unsigned short y, const char board[])输入有效的移动有点困难,因为方块没有标签。相反,考虑打印在板呈现时所需的正方形编号:
void render_board(const char board[])
{
unsigned short x;
unsigned short y;
const char horz[]=" +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+";
puts(horz);
for (y = 0; y < 16; y++) {
printf("%2d", y+1);
for (x = 0; x < 16; x++) {
printf("| %c ", get_piece_on_board(x, y, board));
}
puts("|");
puts(horz);
}
puts(" X->1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16");
}请注意,这也使用单个const char[]作为水平行分隔符,并在适当情况下使用puts而不是printf。
发布于 2015-08-09 09:28:13
bool而不是unsigned short更清楚的是使用bool、true和false来自#include <stdbool.h>,而不是将unsigned short与1和0结合使用。
struct我支持Edward的建议,即使用结构来保持整个游戏状态。很快,您将需要更多的状态,并且您不希望创建单独的变量。例如,以下是您可能需要的一些状态(现在或将来):
如果你的棋子以一个确定的强度顺序攻击(即较强的碎片攻击较弱的碎片),那么强度表就很好。但情况可能是,你需要偏离力量表,以便让一个较弱的部分杀死一个更强大的部分。
根据你目前的规则(我知道这是不断变化的),弓箭手是唯一能杀死龙的人。在您当前的实现中,射手获得了最高的强度(6),因为它可以攻击任何东西,但这意味着向导不能攻击它,因为它只有5。但是您的规则规定,向导应该能够攻击射手。因此,这些规则不遵循严格的强度顺序模式:
D attacks D, W, A
A attacks D, W, A
W attacks W, A力量表的替代方法是有一个攻击表。攻击表保存允许被每个碎片攻击的部分。下面是一些示例代码,如果您决定使用它,您需要适应您自己的代码:
typedef enum PieceValue {
Emperor = 0,
Peasant,
Knight,
Archer,
Wizard,
Dragon,
Blank,
MaxPieces,
} PieceValue;
// The explicit way to specify the attack table:
#define BIT(piece) (1u << (piece))
const uint32_t AttackTable[MaxPieces] = {
[Emperor] = 0,
[Peasant] = BIT(Emperor) | BIT(Peasant),
[Knight] = BIT(Emperor) | BIT(Peasant) | BIT(Knight),
[Archer] = BIT(Emperor) | BIT(Peasant) | BIT(Knight) | BIT(Archer) |
BIT(Wizard) | BIT(Dragon),
[Wizard] = BIT(Emperor) | BIT(Peasant) | BIT(Knight) | BIT(Archer) |
BIT(Wizard),
[Dragon] = BIT(Emperor) | BIT(Peasant) | BIT(Knight) | BIT(Archer) |
BIT(Wizard) | BIT(Dragon),
[Blank] = 0,
};
// The shorter way to do the same thing, if all pieces attack up to
// a certain level of piece:
#define UPTO(piece) ((1u << (piece+1)) - 1)
const uint32_t AttackTable2[MaxPieces] = {
[Emperor] = 0,
[Peasant] = UPTO(Peasant),
[Knight] = UPTO(Knight),
[Archer] = UPTO(Dragon),
[Wizard] = UPTO(Wizard),
[Dragon] = UPTO(Dragon),
[Blank] = 0,
};
static PieceValue getPieceValue(char piece)
{
switch (toupper(piece)) {
case 'E': return Emperor;
case 'P': return Peasant;
case 'K': return Knight;
case 'A': return Archer;
case 'W': return Wizard;
case 'D': return Dragon;
default: return Blank;
}
}
static bool canAttack(char attacker, char victim)
{
PieceValue attackValue = getPieceValue(attacker);
PieceValue victimValue = getPieceValue(victim);
return (AttackTable[attackValue] & BIT(victimValue)) != 0;
}https://codereview.stackexchange.com/questions/100363
复制相似问题