Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #include<stdlib.h>
- #include<stdio.h>
- #include<string.h>
- #include<ctype.h>
- enum {
- EMPTY,
- PAWN, QUEEN, KING,
- KNIGHT, BISHOP, ROOK,
- BARRIER
- };
- enum {
- ANGLE0, ANGLE45, ANGLE90, ANGLE135
- };
- typedef unsigned char uchar;
- typedef struct {
- uchar figure : 3;
- uchar mobility : 2;
- uchar color : 1;
- uchar attacked : 1;
- uchar special : 1;
- } cell_t;
- cell_t desk[10][10];
- void clear_desk() {
- for (int i = 1; i <= 8; ++i) {
- for (int j = 1; j <= 8; ++j) {
- desk[i][j].figure = EMPTY;
- }
- }
- }
- void clear_desk_state() {
- for (int i = 1; i <= 8; ++i) {
- for (int j = 1; j <= 8; ++j) {
- desk[i][j].attacked = 0;
- desk[i][j].special = 0;
- }
- }
- }
- void init_desk() {
- for (int i = 0; i < 10; ++i) {
- desk[i][0].figure = BARRIER;
- desk[i][9].figure = BARRIER;
- desk[0][i].figure = BARRIER;
- desk[9][i].figure = BARRIER;
- }
- clear_desk();
- clear_desk_state();
- }
- char **move_table;
- int moveptr_list[6] = { 0, 0, 0, 0, 0, 0 };
- void clear_move_table() {
- for (int i = 0; i < 6; ++i) {
- moveptr_list[i] = 0;
- }
- }
- void init_move_table() {
- move_table = malloc(6 * sizeof(char*));
- for (int i = 0; i < 6; ++i) {
- move_table[i] = malloc(1024 * sizeof(char));
- }
- clear_move_table();
- }
- void destroy_move_table() {
- for (int i = 0; i < 6; ++i) {
- free(move_table[i]);
- }
- free(move_table);
- }
- void add_move(int fromX, int fromY, int toX, int toY) {
- char *move_list = move_table[desk[fromX][fromY].figure - 1];
- int moveptr = moveptr_list[desk[fromX][fromY].figure - 1];
- move_list[moveptr++] = fromX + 'a' - 1;
- move_list[moveptr++] = fromY + '0';
- move_list[moveptr++] = toX + 'a' - 1;
- move_list[moveptr++] = toY + '0';
- moveptr_list[desk[fromX][fromY].figure - 1] = moveptr;
- }
- void update_castling(void);
- void extra_check(void);
- struct {
- int fromX, fromY, toX, toY, figure;
- } current_move;
- int side;
- void set_current_move(int fromX, int fromY, int toX, int toY, int figure) {
- current_move.fromX = fromX;
- current_move.fromY = fromY;
- current_move.toX = toX;
- current_move.toY = toY;
- current_move.figure = figure;
- }
- void release_current_move() {
- int fromX = current_move.fromX,
- fromY = current_move.fromY,
- toX = current_move.toX,
- toY = current_move.toY,
- figure = current_move.figure;
- side = !desk[fromX][fromY].color;
- if (fromX == toX && fromY == toY) {
- return;
- }
- update_castling();
- extra_check();
- if (desk[fromX][fromY].figure == KING && abs(fromX - toX) > 1) {
- int _fromX = fromX < toX ? 8 : 1, _toX = (fromX + toX) / 2;
- desk[_toX][toY] = desk[_fromX][fromY];
- desk[_fromX][fromY].figure = EMPTY;
- }
- if (desk[fromX][fromY].figure == PAWN) {
- if (toY == (side ? 1 : 8)) {
- desk[fromX][fromY].figure = figure;
- }
- if (fromX != toX && desk[toX][toY].figure == EMPTY) {
- desk[toX][fromY].figure = EMPTY;
- }
- }
- desk[toX][toY] = desk[fromX][fromY];
- desk[fromX][fromY].figure = EMPTY;
- }
- int castling_active[2][3];
- void update_castling() {
- int fromX = current_move.fromX,
- fromY = current_move.fromY,
- toX = current_move.toX,
- toY = current_move.toY;
- for (int i = 1; i <= 8; i += 7) {
- for (int j = 1; j <= 8; j += 3 + (j == 1)) {
- castling_active[i < 8][j / 4] |= (fromX == j && fromY == i);
- castling_active[i < 8][j / 4] |= (toX == j && toY == i);
- }
- }
- }
- struct {
- int exist, X, Y;
- } extra;
- int extra_figure(const cell_t *cell) {
- if (cell->figure == EMPTY) {
- return 0;
- }
- if ((cell->color == side && cell->figure == KING) ||
- (cell->color != side && (cell->figure == ROOK || cell->figure == QUEEN)))
- {
- return cell->figure;
- } else {
- return -1;
- }
- }
- void extra_check() {
- int fromX = current_move.fromX,
- fromY = current_move.fromY,
- toX = current_move.toX,
- toY = current_move.toY;
- extra.exist = 0;
- if (desk[fromX][fromY].figure != PAWN || abs(fromY - toY) < 2) {
- return;
- }
- int X, Y;
- if (desk[toX - 1][toY].figure == PAWN && desk[toX - 1][toY].color == side) {
- X = toX - 1;
- Y = toY;
- } else if (desk[toX + 1][toY].figure == PAWN && desk[toX + 1][toY].color == side) {
- X = toX + 1;
- Y = toY;
- } else {
- return;
- }
- extra.exist = 1;
- extra.X = toX;
- extra.Y = toY + (side ? 1 : -1);
- int dec = 0, inc = 0;
- for (int i = X - 1; i > 0; --i) {
- int t = extra_figure(&desk[i][toY]);
- if (t > 0) {
- dec = t;
- break;
- } else if (t < 0) {
- return;
- }
- }
- for (int i = X + 1; i <= 8; ++i) {
- int t = extra_figure(&desk[i][toY]);
- if (t > 0) {
- inc = t;
- break;
- } else if (t < 0) {
- return;
- }
- }
- if (inc && dec && (dec == KING || inc == KING)) {
- extra.exist = 0;
- }
- }
- char get_figure_symbol(int figure) {
- return (figure == PAWN) * 'p' + (figure == QUEEN) * 'q' + (figure == KING) * 'k'
- + (figure == KNIGHT) * 'g' + (figure == BISHOP) * 'b' + (figure == ROOK) * 'r'
- + (figure == EMPTY) * '.';
- }
- int get_figure_number(char figure) {
- figure = tolower(figure);
- return (figure == 'p') * PAWN + (figure == 'q') * QUEEN + (figure == 'k') * KING
- + (figure == 'g') * KNIGHT + (figure == 'b') * BISHOP + (figure == 'r') * ROOK
- + (figure == '.') * EMPTY;
- }
- void unpack_desk(const char *position) {
- init_desk();
- for (int i = 0; i < 8; ++i) {
- for (int j = 0; j < 8; ++j) {
- const char c = position[i * 8 + j];
- desk[j + 1][i + 1] = (cell_t) {
- get_figure_number(c), 0,
- (c >= 'a' && c <= 'z'), 0, 0
- };
- }
- }
- }
- void unpack_castling(const char *position) {
- for (int i = 0; i < 2; ++i) {
- for (int j = 0; j < 3; ++j) {
- castling_active[i][j] = position[i * 3 + j] - '0';
- }
- }
- }
- void unpack_move(const char *position) {
- set_current_move(position[0] - 'a' + 1, position[1] - '0',
- position[2] - 'a' + 1, position[3] - '0',
- get_figure_number(position[4]));
- }
- void unpack_position(const char *position) {
- unpack_desk(position);
- unpack_castling(position + 64);
- unpack_move(position + 70);
- }
- char gamestate[50];
- int gamestate_move_released = 0;
- void decode_desk() {
- const char *target = gamestate;
- init_desk();
- static const int complete_offset[2][6] = {
- { 8, 9, 10, 12, 14, 16 },
- { 24, 25, 26, 28, 30, 32 }
- };
- int offset[2][6] = {
- { 0, 8, 9, 10, 12, 14 },
- { 16, 24, 25, 26, 28, 30 }
- };
- for (int i = 0; i < 2; ++i) {
- for (int j = 0; j < 6; ++j) {
- while (offset[i][j] != complete_offset[i][j]) {
- int pos = target[offset[i][j]] - 33;
- if (pos == (1 << 6)) {
- ++offset[i][j];
- break;
- }
- int x = (pos & 7) + 1,
- y = ((pos & (7 << 3)) >> 3) + 1;
- if (j + 1 == PAWN) {
- desk[x][y].figure = (((target[32 + offset[i][j] % 16] - 33) >> (i * 3)) & 7) + 1;
- } else {
- desk[x][y].figure = j + 1;
- }
- desk[x][y].color = i;
- ++offset[i][j];
- }
- }
- }
- }
- void decode_castling() {
- const char *target = gamestate + 40;
- for (int i = 0; i < 6; ++i) {
- castling_active[i / 3][i % 3] = ((target[0] - 33) >> i) & 1;
- }
- }
- void decode_move() {
- const char *target = gamestate + 41;
- set_current_move(((target[0] - 33) & 7) + 1, (((target[0] - 33) >> 3) & 7) + 1,
- ((target[1] - 33) & 7) + 1, (((target[1] - 33) >> 3) & 7) + 1,
- target[2] - 33);
- }
- void decode_position() {
- decode_desk();
- decode_castling();
- decode_move();
- }
- void encode_desk() {
- char *target = gamestate;
- static const int complete_offset[2][6] = {
- { 8, 9, 10, 12, 14, 16 },
- { 24, 25, 26, 28, 30, 32 }
- };
- int offset[2][6] = {
- { 0, 8, 9, 10, 12, 14 },
- { 16, 24, 25, 26, 28, 30 }
- };
- for (int i = 32; i < 40; ++i) {
- target[i] = 0;
- }
- for (int i = 0; i < 8; ++i) {
- for (int j = 0; j < 8; ++j) {
- if (desk[i + 1][j + 1].figure == EMPTY) {
- continue;
- }
- int color = desk[i + 1][j + 1].color,
- figure = desk[i + 1][j + 1].figure - 1;
- if (offset[color][figure] != complete_offset[color][figure]) {
- target[offset[color][figure]++] = (0 | i | (j << 3)) + 33;
- continue;
- }
- target[offset[color][PAWN - 1]] = (0 | i | (j << 3)) + 33;
- target[32 + offset[color][PAWN - 1] % 16] |= figure << (color * 3);
- ++offset[color][PAWN - 1];
- }
- }
- for (int i = 32; i < 40; ++i) {
- target[i] += 33;
- }
- for (int i = 0; i < 2; ++i) {
- for (int j = 0; j < 6; ++j) {
- while (offset[i][j] != complete_offset[i][j]) {
- target[offset[i][j]++] = (1 << 6) + 33;
- }
- }
- }
- }
- void encode_castling() {
- char *target = gamestate + 40;
- target[0] = 0;
- for (int i = 0; i < 6; ++i) {
- target[0] |= castling_active[i / 3][i % 3] << i;
- }
- target[0] += 33;
- }
- void encode_move() {
- char *target = gamestate + 41;
- target[0] = current_move.fromX - 1;
- target[0] |= (current_move.fromY - 1) << 3;
- target[0] += 33;
- target[1] = current_move.toX - 1;
- target[1] |= (current_move.toY - 1) << 3;
- target[1] += 33;
- target[2] = current_move.figure + 33;
- }
- void encode_position() {
- encode_desk();
- encode_castling();
- encode_move();
- }
- int atacks_on_king = 0;
- int get_mobility(int dx, int dy) {
- return abs(dx) == abs(dy) ? (dx == dy ? ANGLE45 : ANGLE135) : (dx ? ANGLE0 : ANGLE90);
- }
- int is_check() {
- return atacks_on_king == 1;
- }
- int is_multicheck() {
- return atacks_on_king > 1;
- }
- int is_correct(int x, int y) {
- return x > 0 && x < 9 && y > 0 && y < 9;
- }
- int is_figure(const cell_t *cell) {
- return cell->figure != EMPTY && cell->figure != BARRIER;
- }
- int is_ally(const cell_t *cell) {
- return is_figure(cell) && cell->color == side;
- }
- int is_enemy(const cell_t *cell) {
- return is_figure(cell) && cell->color != side;
- }
- int is_direction_correct(const cell_t *cell, int dx, int dy) {
- return (cell->figure != KNIGHT && get_mobility(dx, dy) == cell->mobility)
- || !cell->special;
- }
- int is_moveable(int x, int y, int dx, int dy) {
- if (!is_correct(x + dx, y + dy) || is_ally(&desk[x + dx][y + dy])
- || !is_direction_correct(&desk[x][y], dx, dy))
- {
- return 0;
- }
- return !is_check() || desk[x + dx][y + dy].special;
- }
- void atack_handler(int x, int y, int dx, int dy) {
- if (is_correct(x + dx, y + dy)) {
- cell_t *cell = &desk[x + dx][y + dy];
- cell->attacked = 1;
- if (is_ally(cell) && cell->figure == KING) {
- desk[x][y].special = 1;
- ++atacks_on_king;
- }
- }
- }
- void pierce_block(int x, int y, int dx, int dy) {
- desk[x][y].special = 1;
- desk[x][y].mobility = get_mobility(dx, dy);
- }
- void ally_line_handler(int x, int y, int dx, int dy) {
- if (!is_direction_correct(&desk[x][y], dx, dy)) {
- return;
- }
- for (int i = dx, j = dy; is_correct(x + i, y + j); i += dx, j += dy) {
- if (is_moveable(x, y, i, j)) {
- add_move(x, y, x + i, y + j);
- }
- if (is_figure(&desk[x + i][y + j])) {
- break;
- }
- }
- }
- int pierce_detector(int x, int y, int dx, int dy, int cnt) {
- cell_t *cell = &desk[x + dx][y + dy];
- if (!cnt) {
- atack_handler(x, y, dx, dy);
- }
- if (cell->figure == EMPTY) {
- return cnt;
- }
- ++cnt;
- cnt *= (cell->figure == KING ? -1 : 1);
- if (cell->figure == BARRIER || is_enemy(cell) || cnt == 2) {
- return -3;
- } else {
- return cnt;
- }
- }
- void enemy_line_handler(int x, int y, int dx, int dy) {
- int cnt = 0, i = 0, j = 0;
- do {
- i += dx;
- j += dy;
- cnt = pierce_detector(x, y, i, j, cnt);
- } while (cnt >= 0);
- if (cnt == -1) {
- atack_handler(x, y, i + dx, j + dy);
- for (i = x, j = y; desk[i][j].figure != KING; i += dx, j += dy) {
- desk[i][j].special = 1;
- }
- } else if (cnt == -2) {
- for (i = x, j = y; !is_ally(&desk[i][j]); i += dx, j += dy);
- pierce_block(i, j, dx, dy);
- }
- }
- typedef void (*line_handler_t)(int, int, int, int);
- void X_handler(int x, int y, int vh, int d, line_handler_t handl) {
- if (vh) {
- handl(x, y, 1, 0);
- handl(x, y, -1, 0);
- handl(x, y, 0, 1);
- handl(x, y, 0, -1);
- }
- if (d) {
- handl(x, y, 1, 1);
- handl(x, y, 1, -1);
- handl(x, y, -1, 1);
- handl(x, y, -1, -1);
- }
- }
- void ally_knight_handler(int x, int y) {
- for (int i = 1; i <= 2; ++i) {
- int j = 3 - i;
- if (is_moveable(x, y, i, j)) {
- add_move(x, y, x + i, y + j);
- }
- if (is_moveable(x, y, i, -j)) {
- add_move(x, y, x + i, y - j);
- }
- if (is_moveable(x, y, -i, j)) {
- add_move(x, y, x - i, y + j);
- }
- if (is_moveable(x, y, -i, -j)) {
- add_move(x, y, x - i, y - j);
- }
- }
- }
- void enemy_knight_handler(int x, int y) {
- for (int i = 1; i <= 2; ++i) {
- int j = 3 - i;
- atack_handler(x, y, i, j);
- atack_handler(x, y, i, -j);
- atack_handler(x, y, -i, j);
- atack_handler(x, y, -i, -j);
- }
- }
- void ally_king_handler(int x, int y) {
- for (int i = -1; i <= 1; ++i) {
- for (int j = -1; j <= 1; ++j) {
- if (is_correct(x + i, y + j) && !desk[x + i][y + j].attacked && !is_ally(&desk[x + i][y + j])) {
- add_move(x, y, x + i, y + j);
- }
- }
- }
- }
- void enemy_king_handler(int x, int y) {
- for (int i = -1; i <= 1; ++i) {
- for (int j = -1; j <= 1; ++j) {
- if (desk[x + i][y + j].figure != KING) {
- atack_handler(x, y, i, j);
- }
- }
- }
- }
- void pawn_kill_move(int x, int y, int dx, int dy) {
- if ((is_enemy(&desk[x + dx][y + dy]) && is_moveable(x, y, dx, dy))
- || (extra.exist && x + dx == extra.X && y + dy == extra.Y
- && (is_moveable(x, y, dx, dy) || is_moveable(x, y, dx, 0))
- )
- )
- {
- add_move(x, y, x + dx, y + dy);
- }
- }
- void ally_pawn_handler(int x, int y) {
- int t = (side ? 1 : -1);
- pawn_kill_move(x, y, 1, t);
- pawn_kill_move(x, y, -1, t);
- if (is_figure(&desk[x][y + t])){
- return;
- }
- if (is_moveable(x, y, 0, t)) {
- add_move(x, y, x, y + t);
- }
- if (y == 7 - 5 * side && !is_figure(&desk[x][y + 2 * t]) && is_moveable(x, y, 0, 2 * t)) {
- add_move(x, y, x, y + 2 * t);
- }
- }
- void enemy_pawn_handler(int x, int y) {
- atack_handler(x, y, 1, -(side ? 1 : -1));
- atack_handler(x, y, -1, -(side ? 1 : -1));
- }
- void ally_figure_handler(int x, int y) {
- if (!is_figure(&desk[x][y]) || is_enemy(&desk[x][y])
- || (is_multicheck() && desk[x][y].figure != KING))
- {
- return;
- } else if (desk[x][y].figure == PAWN) {
- ally_pawn_handler(x, y);
- } else if (desk[x][y].figure == KING) {
- ally_king_handler(x, y);
- } else if (desk[x][y].figure == KNIGHT) {
- ally_knight_handler(x, y);
- } else if (desk[x][y].figure == ROOK) {
- X_handler(x, y, 1, 0, ally_line_handler);
- } else if (desk[x][y].figure == BISHOP) {
- X_handler(x, y, 0, 1, ally_line_handler);
- } else if (desk[x][y].figure == QUEEN) {
- X_handler(x, y, 1, 1, ally_line_handler);
- }
- }
- void enemy_figure_handler(int x, int y) {
- if (!is_figure(&desk[x][y]) || is_ally(&desk[x][y])) {
- return;
- } else if (desk[x][y].figure == PAWN) {
- enemy_pawn_handler(x, y);
- } else if (desk[x][y].figure == KING) {
- enemy_king_handler(x, y);
- } else if (desk[x][y].figure == KNIGHT) {
- enemy_knight_handler(x, y);
- } else if (desk[x][y].figure == ROOK) {
- X_handler(x, y, 1, 0, enemy_line_handler);
- } else if (desk[x][y].figure == BISHOP) {
- X_handler(x, y, 0, 1, enemy_line_handler);
- } else if (desk[x][y].figure == QUEEN) {
- X_handler(x, y, 1, 1, enemy_line_handler);
- }
- }
- typedef void (*cell_handler_t)(int, int);
- void desk_handler(cell_handler_t handl) {
- for (int i = 1; i <= 8; ++i) {
- for (int j = 1; j <= 8; ++j) {
- handl(i, j);
- }
- }
- }
- void castle_handler() {
- if (is_check() || is_multicheck() || castling_active[side][1]) {
- return;
- }
- int sideline = 8 - side * 7;
- if (!castling_active[side][0]
- && !desk[4][sideline].attacked && !is_figure(&desk[4][sideline])
- && !desk[3][sideline].attacked && !is_figure(&desk[3][sideline]))
- {
- add_move(5, sideline, 3, sideline);
- }
- if (!castling_active[side][2]
- && !desk[6][sideline].attacked && !is_figure(&desk[6][sideline])
- && !desk[7][sideline].attacked && !is_figure(&desk[7][sideline]))
- {
- add_move(5, sideline, 7, sideline);
- }
- }
- void position_handler() {
- atacks_on_king = 0;
- clear_move_table();
- clear_desk_state();
- release_current_move();
- desk_handler(enemy_figure_handler);
- desk_handler(ally_figure_handler);
- castle_handler();
- }
- int is_gamestate_move_completed() {
- const char *move = gamestate + 44;
- return move[5] != '?' || (move[4] != '?' && (move[0] != 'p' || (move[4] != '1' && move[4] != '8')));
- }
- void clear_gamestate_move() {
- memcpy(gamestate + 44, "??????", 6);
- }
- void gamestate_move_handler() {
- gamestate_move_released = 0;
- if (is_gamestate_move_completed()) {
- unpack_move(gamestate + 45);
- encode_position();
- position_handler();
- clear_gamestate_move();
- gamestate_move_released = 1;
- }
- }
- const char *starting =
- "rgbqkbgr"
- "pppppppp"
- "........"
- "........"
- "........"
- "........"
- "PPPPPPPP"
- "RGBQKBGR"
- "000000e8e8k";
- void init_gamestate() {
- unpack_position(starting);
- position_handler();
- encode_position();
- clear_gamestate_move();
- }
- void gamestate_handler() {
- decode_position();
- position_handler();
- gamestate_move_handler();
- }
- void output_move_figures() {
- char result[13];
- int cnt = 0;
- for (int i = 0; i < 6; ++i) {
- if (moveptr_list[i]) {
- result[cnt * 2] = get_figure_symbol(i + 1);
- result[cnt * 2 + 1] = ' ';
- ++cnt;
- }
- }
- result[cnt * 2] = '\0';
- puts(result);
- }
- void output_move_from(int figure) {
- int cnt = moveptr_list[figure - 1] / 4, ptr = 0;
- char *result = malloc((cnt * 3 + 1) * sizeof(char));
- for (int i = 0; i < cnt; ++i) {
- result[ptr * 3] = move_table[figure - 1][i * 4];
- result[ptr * 3 + 1] = move_table[figure - 1][i * 4 + 1];
- result[ptr * 3 + 2] = ' ';
- if (i && result[ptr * 3 - 3] == result[ptr * 3]
- && result[ptr * 3 - 2] == result[ptr * 3 + 1])
- {
- continue;
- }
- ++ptr;
- }
- result[ptr * 3] = '\0';
- puts(result);
- }
- void output_move_to(int figure, const char *from) {
- int cnt = 0, maxcnt = moveptr_list[figure - 1] / 4;
- char *result = malloc((maxcnt * 3 + 1) * sizeof(char));
- for (int i = 0; i < maxcnt; ++i) {
- if (move_table[figure - 1][i * 4] == from[0] && move_table[figure - 1][i * 4 + 1] == from[1]) {
- result[cnt * 3] = move_table[figure - 1][i * 4 + 2];
- result[cnt * 3 + 1] = move_table[figure - 1][i * 4 + 3];
- result[cnt * 3 + 2] = ' ';
- ++cnt;
- }
- }
- result[cnt * 3] = '\0';
- puts(result);
- }
- void output_move_transform() {
- puts("q g b r");
- }
- void output_gamestate() {
- fwrite(gamestate, 1, 50, stdout);
- putchar('\n');
- }
- void output_desk() {
- for (int i = 8; i >= 1; --i) {
- for (int j = 1; j <= 8; ++j) {
- putchar(get_figure_symbol(desk[j][i].figure) +
- (desk[j][i].color || desk[j][i].figure == EMPTY
- ? 0 : 'A' - 'a'));
- }
- putchar('\n');
- }
- }
- void output_move_variants() {
- const char *move = gamestate + 44;
- if (move[0] == '?') {
- output_move_figures();
- } else if (move[1] == '?') {
- output_move_from(get_figure_number(move[0]));
- } else if (move[3] == '?') {
- output_move_to(get_figure_number(move[0]), move + 1);
- } else {
- output_move_transform();
- }
- }
- void output_gamestate_info() {
- output_gamestate();
- output_desk();
- output_move_variants();
- printf("%d %d", side, gamestate_move_released);
- }
- int main(int argc, char **argv) {
- init_move_table();
- if (argc < 2) {
- return 0;
- } else if (!strcmp(argv[1], "init")) {
- init_gamestate();
- output_gamestate_info();
- } else if (!strcmp(argv[1], "handle")) {
- memcpy(gamestate, argv[2], 50);
- gamestate_handler();
- output_gamestate_info();
- }
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement