aboutsummaryrefslogblamecommitdiffstats
path: root/ajedrez.c
blob: 542c911032d4ee23520822ce216402355ace3779 (plain) (tree)
1
2
3
4
5
6
7
8
9


                                                            



                                                      

                   
 
                      
                                 
                   
                    


                   
                      

                   
                    


                       






                                                                                

                                                    
                                              

                                                                    
                        
                                 
 






                  


                                                                        
                                                        
                         






                        

             




                    




                      
                     



                            








                           
                  

                                
                                    

                                      
                                           
                    
 

                                    
                                       
                   

                   
 












                                                                         
                    

                                   
                                                                            

                                      
     










                                                                                                                                             
     





                                                                                                                                              
                                                                               
          
                                                       

















                                                                
                                                       
   
 

                                   
                                                                             




















                                                                                                                                              
                                                                              
          
                                                        

















                                                                
                                                      
   

 
                                        



                      

                                 

                             



                                                          






                    

                           


                                 
                                                              
                                    
                 


       


                            


             
                    







                                       

                                       
 


                                       
                                     
                                      
                                       



                                       

 












                                                        
         













                                                 


       

              
 
                            
                                                                           









                                               
             
           



         
              

 
                 


                         
                                  
                         
                         
                 

                                    
                         
                         

                  
                     
                                        
          
                                       


                 

 













                               






















                                                                                





                                                                   
                  
                  
              



                                                                      
                   

                                                                          
                    

                                                                          
                   


                     
                   


                                              
                                                             
                     


                           
                   


                                       
                                                             
                     


                                           
                   

                                       

                                                
                                                             
                     

              
                                   
                   
                                  
                   
                      




                                                                                
                      







                                                         
                      



                   


                                                                            
                   

            
                 

          

                      
              

 


                                            

 


                                
                                   














                       



     




                              
                                                                          



                                        
                                                                        
            
                                                                        







                       
                  
                                                    












                              




                                                    
                
            
                       
                   
                                                  
        
                                                 
           

                            
                                                     
          
                                                      

                                   
                                 

            


                                                              
                       
                         
                       

                      






                           
 


                                
                 
 

















                                                                          
                   








                                                                  

                   


                                                        

                    
            
                                
                    
     
 
       







                        



                







                                                           
                                                            


                          
                                                              











































                                                                                
                                      





















                                                                            
                                                                                  


                                              
                                                      

                                  

                                                                    
                          







                              









                                                                       

           
// SAKKOM: sakk a konzolban király! online multiplayer
// chess.com alternatíva, ami netcatet használ mint kliens
//
// AJEDREZ: servidor de ajedrez multijugador en línea
// alternativo a chess.com con un cliente para netcat.
// Hispanizado para texto-plano.xyz
//
// do what you want
// boa

#include <arpa/inet.h>
#include <pthread.h> // -lpthread
#include <signal.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <time.h>
#include <unistd.h>
#ifdef __BSD_VISIBLE
#include <netinet/in.h>
#include <sys/socket.h>
#endif

#define PRINT_ALL(f_, ...)                                                     \
  do {                                                                         \
    dprintf(w_fd, (f_), ##__VA_ARGS__);                                        \
    dprintf(b_fd, (f_), ##__VA_ARGS__);                                        \
  } while (0)

typedef enum mode { mode_ascii, mode_unicode } mode;
mode modes[2];
typedef enum color { c_w = 0, c_b = 1 } color;
typedef enum castle { castle_no, castle_long, castle_short } castle;

int colors[] = {39, 30};
char ascii_colors[] = {' ', '*'};

int abs(int a) {
  if (a >= 0)
    return a;
  else
    return -1 * a;
}

char symbols[7][7] = {" ", "♟︎", "♜", "♞", "♝", "♛", "♚"};
char ascii_symbols[7] = {' ', 'P', 'R', 'N', 'B', 'Q', 'K'};

typedef enum result { r_no, r_win, r_stalemate } result;
typedef enum piece_type {
  p_no,       // vacío
  p_pawn,     // peón
  p_rook,     // torre
  p_knight,   // caballo
  p_bishop,   // alfil
  p_queen,    // reina
  p_king      // rey
} piece_type;

typedef struct pos {
  int x;
  int y;
} pos;

typedef struct piece {
  piece_type p;
  color c;
} piece;

typedef struct move {
  pos f;   // pos. origen
  pos t;   // pos. destino
  piece p; // pieza movida
  piece e; // enemigo tomado
} move;

typedef struct en_passant {
  bool valid;
  pos p;
  piece *to_remove;
} en_passant;
en_passant enp;

piece table[8][8];
int w_fd = -1, b_fd = -1;
int *c_fd = &w_fd; // current fd
bool moved_king[2] = {false, false};
bool moved_rook_l[2] = {false, false};
bool moved_rook_r[2] = {false, false};
int remaining_time[2] = {30 * 60, 30 * 60};
int game_number = 1;

void do_move(move m);
bool is_move_legal(color c, move m);
bool in_check(color c, int cx, int cy);
void print_table();
void setup_table();
void play_game();

bool is_same_pos(pos p1, pos p2) { return p1.x == p2.x && p1.y == p2.y; }

bool is_empty(piece p) { return p.p == p_no; }
bool is_friend_of(color c, piece p) { return !is_empty(p) && p.c == c; }
bool is_enemy_of(color c, piece p) { return !is_empty(p) && p.c != c; }

bool is_inside(int i) { return i >= 0 && i < 8; }

bool is_move_inside(move m) {
  return is_inside(m.f.x) && is_inside(m.f.y) && is_inside(m.t.x) &&
         is_inside(m.t.y);
}

void print_table() {
  if (modes[c_w] == mode_unicode) {
    dprintf(w_fd,
            "\n                \e[43m\x1B[30m\033[1m NEGRO \x1B[0m\n\n   ");
    for (int x = 0; x < 8; x++) {
      dprintf(w_fd, "  %c ", 'A' + x);
    }
    dprintf(w_fd, "\n   \e[43m┏━━━┳━━━┳━━━┳━━━┳━━━┳━━━┳━━━┳━━━┓\x1B[0m\n");
    for (int y = 7; y >= 0; y--) {
      if (y != 7) {
        dprintf(w_fd, "\x1B[0m   "
                      "\e[43m┣━━━╋━━━╋━━━╋━━━╋━━━╋━━━╋━━━╋━━━┫\x1B[0m\n");
      }
      dprintf(w_fd, " %d \e[43m┃", y + 1);
      for (int x = 0; x < 8; x++)
        dprintf(w_fd, "\e[43m\x1B[%dm \033[1m%s \x1B[0m\e[43m┃",
                colors[table[x][y].c], symbols[table[x][y].p]);
      dprintf(w_fd, "\x1B[0m %d\x1B[0m\n", y + 1);
    }
    dprintf(w_fd, "   \e[43m┗━━━┻━━━┻━━━┻━━━┻━━━┻━━━┻━━━┻━━━┛\x1B[0m\n   ");
    for (int x = 0; x < 8; x++) {
      dprintf(w_fd, "  %c ", 'A' + x);
    }
    dprintf(
        w_fd,
        "\n\n                \e[43m\x1B[39m\033[1m BLANCO \x1B[0m\n\n\x1B[0m");
  } else {
    dprintf(w_fd, "\n               [ NEGRO ]\n\n   ");
    for (int x = 0; x < 8; x++) {
      dprintf(w_fd, "  %c ", 'A' + x);
    }
    dprintf(w_fd, "\n   +---+---+---+---+---+---+---+---+\n");
    for (int y = 7; y >= 0; y--) {
      if (y != 7) {
        dprintf(w_fd, "   +---+---+---+---+---+---+---+---+\n");
      }
      dprintf(w_fd, " %d |", y + 1);
      for (int x = 0; x < 8; x++)
        dprintf(w_fd, "%c%c |", ascii_colors[table[x][y].c],
                ascii_symbols[table[x][y].p]);
      dprintf(w_fd, " %d\n", y + 1);
    }
    dprintf(w_fd, "   +---+---+---+---+---+---+---+---+\n   ");
    for (int x = 0; x < 8; x++) {
      dprintf(w_fd, "  %c ", 'A' + x);
    }
    dprintf(w_fd, "\n\n               [ BLANCO ]\n\n");
  }

  if (modes[c_b] == mode_unicode) {
    dprintf(b_fd,
            "\n                \e[43m\x1B[39m\033[1m BLANCO \x1B[0m\n\n   ");
    for (int x = 0; x < 8; x++) {
      dprintf(b_fd, "  %c ", 'A' + 7 - x);
    }
    dprintf(b_fd, "\n   \e[43m┏━━━┳━━━┳━━━┳━━━┳━━━┳━━━┳━━━┳━━━┓\x1B[0m\n");
    for (int y = 0; y < 8; y++) {
      if (y != 0) {
        dprintf(b_fd, "\x1B[0m   "
                      "\e[43m┣━━━╋━━━╋━━━╋━━━╋━━━╋━━━╋━━━╋━━━┫\x1B[0m\n");
      }
      dprintf(b_fd, " %d \e[43m┃", y + 1);
      for (int x = 7; x >= 0; x--)
        dprintf(b_fd, "\e[43m\x1B[%dm \033[1m%s \x1B[0m\e[43m┃",
                colors[table[x][y].c], symbols[table[x][y].p]);
      dprintf(b_fd, "\x1B[0m %d\n", y + 1);
    }
    dprintf(b_fd, "   \e[43m┗━━━┻━━━┻━━━┻━━━┻━━━┻━━━┻━━━┻━━━┛\x1B[0m\n   ");
    for (int x = 0; x < 8; x++) {
      dprintf(b_fd, "  %c ", 'A' + 7 - x);
    }
    dprintf(
        b_fd,
        "\n\n                \e[43m\x1B[30m\033[1m NEGRO \x1B[0m\n\n\x1B[0m");
  } else {
    dprintf(b_fd, "\n               [ BLANCO ]\n\n   ");
    for (int x = 0; x < 8; x++) {
      dprintf(b_fd, "  %c ", 'A' + 7 - x);
    }
    dprintf(b_fd, "\n   +---+---+---+---+---+---+---+---+\n");
    for (int y = 0; y < 8; y++) {
      if (y != 0) {
        dprintf(b_fd, "   +---+---+---+---+---+---+---+---+\n");
      }
      dprintf(b_fd, " %d |", y + 1);
      for (int x = 7; x >= 0; x--)
        dprintf(b_fd, "%c%c |", ascii_colors[table[x][y].c],
                ascii_symbols[table[x][y].p]);
      dprintf(b_fd, " %d\n", y + 1);
    }
    dprintf(b_fd, "   +---+---+---+---+---+---+---+---+\n   ");
    for (int x = 0; x < 8; x++) {
      dprintf(b_fd, "  %c ", 'A' + 7 - x);
    }
    dprintf(b_fd, "\n\n               [ NEGRO ]\n\n");
  }
}

bool in_check(color c, int cx, int cy) {
  move m;
  m.t.x = cx;
  m.t.y = cy;
  m.e = table[cx][cy];
  for (int y = 0; y < 8; y++) {
    for (int x = 0; x < 8; x++) {
      if (cx == x && cy == y)
        continue;
      m.f.x = x;
      m.f.y = y;
      m.p = table[x][y];
      if (table[x][y].c != c && is_move_legal(m.p.c, m)) {
        return true;
      }
    }
  }
  return false;
}

bool in_check_sim(move m) {
  do_move(m);
  bool res = false;
  for (int y = 0; y < 8; y++) {
    for (int x = 0; x < 8; x++) {
      if (table[x][y].p == p_king && table[x][y].c == m.p.c) {
        res = in_check(m.p.c, x, y);
        goto out;
      }
    }
  }
out:
  table[m.f.x][m.f.y] = m.p;
  table[m.t.x][m.t.y] = m.e;
  return res;
}

void setup_table() {
  table[0][0] = (piece){p_rook, c_w};
  table[1][0] = (piece){p_knight, c_w};
  table[2][0] = (piece){p_bishop, c_w};
  table[3][0] = (piece){p_king, c_w};
  table[4][0] = (piece){p_queen, c_w};
  table[5][0] = (piece){p_bishop, c_w};
  table[6][0] = (piece){p_knight, c_w};
  table[7][0] = (piece){p_rook, c_w};
  for (int x = 0; x < 8; x++)
    table[x][1] = (piece){p_pawn, c_w};

  table[0][7] = (piece){p_rook, c_b};
  table[1][7] = (piece){p_knight, c_b};
  table[2][7] = (piece){p_bishop, c_b};
  table[3][7] = (piece){p_king, c_b};
  table[4][7] = (piece){p_queen, c_b};
  table[5][7] = (piece){p_bishop, c_b};
  table[6][7] = (piece){p_knight, c_b};
  table[7][7] = (piece){p_rook, c_b};
  for (int x = 0; x < 8; x++)
    table[x][6] = (piece){p_pawn, c_b};
}

pos find_king(color c) {
  for (int y = 0; y < 8; y++)
    for (int x = 0; x < 8; x++)
      if (table[x][y].p == p_king && table[x][y].c == c)
        return (pos){x, y};
  return (pos){-1, -1};
}

bool is_stalemate(color c) {
  pos kp = find_king(c);
  if (in_check(c, kp.x, kp.y))
    return false;

  move m;
  for (m.f.y = 0; m.f.y < 8; m.f.y++) {
    for (m.f.x = 0; m.f.x < 8; m.f.x++) {
      if (table[m.f.x][m.f.y].c == c) {
        m.p = table[m.f.x][m.f.y];
        for (m.t.y = 0; m.t.y < 8; m.t.y++) {
          for (m.t.x = 0; m.t.x < 8; m.t.x++) {
            if (m.t.x == m.f.x && m.t.y == m.f.y)
              continue;
            m.e = table[m.t.x][m.t.y];
            if (is_move_legal(c, m)) {
              return false;
            }
          }
        }
      }
    }
  }
  return true;
}

bool is_checkmate(color c) {
  // probably the most simple and least efficient way to solve this problem
  move m;
  for (m.f.y = 0; m.f.y < 8; m.f.y++) {
    for (m.f.x = 0; m.f.x < 8; m.f.x++) {
      if (table[m.f.x][m.f.y].c == c) {
        m.p = table[m.f.x][m.f.y];
        for (m.t.y = 0; m.t.y < 8; m.t.y++) {
          for (m.t.x = 0; m.t.x < 8; m.t.x++) {
            m.e = table[m.t.x][m.t.y];
            if (is_move_legal(c, m)) {
              return false;
            }
          }
        }
      }
    }
  }
  return true;
}

int move_num = 1;
void print_move(move m) {
  char buf[20];
  int n = 0;
  buf[n++] = ascii_symbols[m.p.p];
  buf[n++] = m.f.x + 'a';
  buf[n++] = m.f.y + '1';
  buf[n++] = ' ';
  if (m.e.p != p_no)
    buf[n++] = ascii_symbols[m.p.p];
  buf[n++] = m.t.x + 'a';
  buf[n++] = m.t.y + '1';
  buf[n++] = '\n';
  buf[n++] = '\0';
  if (m.p.c == c_w) {
    PRINT_ALL("%d. blanco: ", move_num);
  } else {
    PRINT_ALL("%d. negro: ", move_num);
    move_num++;
  }
  PRINT_ALL(buf);
}

move parse_move(char buf[50]) {
  move m;

  m.f.x = buf[0] - 'a';
  m.f.y = buf[1] - '1';
  m.t.x = buf[3] - 'a';
  m.t.y = buf[4] - '1';

  m.p = table[m.f.x][m.f.y];
  m.e = table[m.t.x][m.t.y];

  return m;
}

castle is_castle(color c, move m) {
  int dx = m.t.x - m.f.x, dy = m.t.y - m.f.y;
  if (m.p.p == p_king) {
    if (!moved_king[c] && dy == 0) {
      if (!moved_rook_l[c] && dx == -2 && table[m.f.x - 1][m.f.y].p == p_no &&
          table[m.f.x - 3][m.f.y].p == p_rook &&
          table[m.f.x - 3][m.f.y].c == c && !in_check(c, m.f.x - 1, m.f.y) &&
          !in_check(c, m.f.x, m.f.y)) {
        return castle_short;
      } else if (!moved_rook_r[c] && dx == 3 &&
                 table[m.f.x + 1][m.f.y].p == p_no &&
                 table[m.f.x + 2][m.f.y].p == p_no &&
                 table[m.f.x + 4][m.f.y].p == p_rook &&
                 table[m.f.x + 4][m.f.y].c == c &&
                 !in_check(c, m.f.x + 1, m.f.y) &&
                 !in_check(c, m.f.x + 2, m.f.y) && !in_check(c, m.f.x, m.f.y)) {
        return castle_long;
      }
    }
  }
  return castle_no;
}

bool is_move_legal(color c, move m) {
  if (!is_move_inside(m) || is_empty(m.p) || is_enemy_of(c, m.p) ||
      is_friend_of(c, m.e))
    return false;

  int dx = m.t.x - m.f.x, dy = m.t.y - m.f.y;
  int v_x, v_y, l;
  switch (m.p.p) {
  case p_pawn:
    if ((dx != 0 && ((dx != 1 && dx != -1) || (dy != 1 && c == c_w) ||
                     (dy != -1 && c == c_b) ||
                     (is_empty(m.e) && is_same_pos(m.t, enp.p)))) ||
        dy < -2 || dy > 2 || (dy == 1 && c != c_w) ||
        (dy == 2 &&
         (c != c_w || m.f.y != 1 || table[m.f.x][m.f.y + 1].p != p_no)) ||
        (dy == -1 && c != c_b) ||
        (dy == -2 &&
         (c != c_b || m.f.y != 6 || table[m.f.x][m.f.y - 1].p != p_no)) ||
        (dx == 0 && !is_empty(m.e)))
      return false;
    break;
  case p_rook:
    if (dx * dy != 0)
      return false;
    v_x = (dx != 0) ? ((dx > 0) ? 1 : -1) : 0;
    v_y = (dy != 0) ? ((dy > 0) ? 1 : -1) : 0;
    for (int n = 1; n < abs(dx + dy); n++)
      if (!is_empty(table[m.f.x + n * v_x][m.f.y + n * v_y]))
        return false;
    break;
  case p_bishop:
    if (abs(dx) != abs(dy))
      return false;
    v_x = dx ? ((dx > 0) ? 1 : -1) : 0;
    v_y = dy ? ((dy > 0) ? 1 : -1) : 0;
    for (int n = 1; n < abs(dx); n++)
      if (!is_empty(table[m.f.x + n * v_x][m.f.y + n * v_y]))
        return false;
    break;
  case p_queen:
    if (dx * dy != 0 && abs(dx) != abs(dy))
      return false;
    v_x = dx ? ((dx > 0) ? 1 : -1) : 0;
    v_y = dy ? ((dy > 0) ? 1 : -1) : 0;
    l = (dx * dy == 0) ? abs(dx + dy) : abs(dx);
    for (int n = 1; n < l; n++)
      if (!is_empty(table[m.f.x + n * v_x][m.f.y + n * v_y]))
        return false;
    break;
  case p_king:
    if (abs(dx) > 3 || abs(dy) > 1)
      return false;
    if (in_check(c, m.t.x, m.t.y))
      return false;
    if (abs(dx) > 1) {
      if (!moved_king[c] && dy == 0) {
        if (!moved_rook_l[c] && dx == -2 && table[m.f.x - 1][m.f.y].p == p_no &&
            table[m.f.x - 3][m.f.y].p == p_rook &&
            table[m.f.x - 3][m.f.y].c == c && !in_check(c, m.f.x - 1, m.f.y) &&
            !in_check(c, m.f.x, m.f.y)) {
          return true;
        } else if (!moved_rook_r[c] && dx == 3 &&
                   table[m.f.x + 1][m.f.y].p == p_no &&
                   table[m.f.x + 2][m.f.y].p == p_no &&
                   table[m.f.x + 4][m.f.y].p == p_rook &&
                   table[m.f.x + 4][m.f.y].c == c &&
                   !in_check(c, m.f.x + 1, m.f.y) &&
                   !in_check(c, m.f.x + 2, m.f.y) &&
                   !in_check(c, m.f.x, m.f.y)) {
          return true;
        }
      }
      return false;
    }
    break;
  case p_knight:
    if (!((abs(dx) == 2 && abs(dy) == 1) || (abs(dx) == 1 && abs(dy) == 2)))
      return false;
    break;
  case p_no:
    return false;
    break;
  }
  if (in_check_sim(m))
    return false;
  return true;
}

void do_move(move m) {
  table[m.t.x][m.t.y] = table[m.f.x][m.f.y];
  table[m.f.x][m.f.y].p = p_no;
}

piece_type choose_type(int fd) {
  char cbuf[10] = {0};
  while (true) {
    dprintf(fd, "¿qué hacer?\n");
    dprintf(fd, "> ");
    read(fd, cbuf, 10);
    switch (cbuf[0]) {
    case 'P':
      return p_pawn;
    case 'R':
      return p_rook;
    case 'N':
      return p_knight;
    case 'B':
      return p_bishop;
    case 'Q':
      return p_queen;
    case 'K':
      return p_king;
    }
  }
}

color c_c;
bool is_printing = false;
void *run_timer(void *vargp) {
  while (true) {
    if (!is_printing) {
      dprintf(*c_fd, "\0337\r%02d:%02d > \0338", remaining_time[c_c] / 60,
              remaining_time[c_c] % 60);
      remaining_time[c_c]--;
      if (remaining_time[c_c] <= 0) {
        if (c_c == c_w)
          PRINT_ALL("blanco se ha quedado sin tiempo. ¡negro gana!\n");
        else
          PRINT_ALL("negro se ha quedado sin tiempo. ¡blanco gana!\n");
        raise(SIGTERM);
      }
    }
    sleep(1);
  }
  return NULL;
}

void play_game() {
  PRINT_ALL("¿interfaz (a)scii o (u)nicode? [u] ");
  char input_str[50];
  read(w_fd, input_str, 50);
  if (input_str[0] == 'a')
    modes[c_w] = mode_ascii;
  else
    modes[c_w] = mode_unicode;

  read(b_fd, input_str, 50);
  if (input_str[0] == 'a')
    modes[c_b] = mode_ascii;
  else
    modes[c_b] = mode_unicode;

  c_c = c_w; // current color
  is_printing = true;
  pthread_t thread_id;
  pthread_create(&thread_id, NULL, run_timer, NULL);

  print_table();
  for (;;) {
    is_printing = true;
    if (c_c == c_w)
      dprintf(b_fd, "blanco está pensando...\n");
    else
      dprintf(w_fd, "negro está pensando...\n");
  no_print:
    if (is_checkmate(c_c)) {
      if (c_c == c_w)
        PRINT_ALL("\n¡jaque mate! ¡negro gana!\n");
      else
        PRINT_ALL("\n¡jaque mate! ¡blanco gana!\n");
      break;
    } else if (is_stalemate(c_c)) {
      PRINT_ALL("\n¡empate!\n");
      break;
    }
    dprintf(*c_fd, "\n%02d:%02d > ", remaining_time[c_c] / 60,
            remaining_time[c_c] % 60);
    is_printing = false;
    char buf[50] = {0};
    read(*c_fd, buf, 50);
    is_printing = true;
    if (buf[0] == 's')
      goto skip;
    if (buf[0] == ':') {
      if (c_c == c_w)
        dprintf(b_fd, buf);
      else
        dprintf(w_fd, buf);
      goto no_print;
    }

    move m = parse_move(buf);

    if (is_move_legal(c_c, m)) {
      do_move(m);

      castle ct = is_castle(c_c, m);
      if (ct == castle_short) {
        table[m.f.x - 1][m.f.y] = table[m.f.x - 3][m.f.y];
        table[m.f.x - 3][m.f.y].p = p_no;
      } else if (ct == castle_long) {
        table[m.f.x + 2][m.f.y] = table[m.f.x + 4][m.f.y];
        table[m.f.x + 4][m.f.y].p = p_no;
      }

      if (m.p.p == p_rook &&
          ((m.f.x == 7 && m.f.y == 0) || (m.f.x == 7 && m.f.y == 7)))
        moved_rook_r[c_c] = true;
      else if (m.p.p == p_rook &&
               ((m.f.x == 0 && m.f.y == 0) || (m.f.x == 0 && m.f.y == 7)))
        moved_rook_l[c_c] = true;
      else if (m.p.p == p_king)
        moved_king[c_c] = true;

      // en passant
      if (enp.valid && is_same_pos(enp.p, m.t) && m.p.p == p_pawn)
        enp.to_remove->p = p_no;
      enp.valid = false;
      if (m.p.p == p_pawn && abs(m.f.y - m.t.y) == 2) {
        enp.valid = true;
        enp.to_remove = &table[m.t.x][m.t.y];
        enp.p.x = m.t.x;
        enp.p.y = m.t.y + (c_c == c_w ? -1 : 1);
      }

      // trade pawn
      if ((m.t.y == 0 || m.t.y == 7) && m.p.p == p_pawn)
        table[m.t.x][m.t.y].p = choose_type(*c_fd);

      print_table();
      print_move(m);
    } else {
      dprintf(*c_fd, "error\n");
      goto no_print;
    }

  skip:
    if (c_fd == &w_fd) {
      c_fd = &b_fd;
      c_c = c_b;
    } else {
      c_fd = &w_fd;
      c_c = c_w;
    }
  }
}

int main() {
  setup_table();
  // stolen from: https://git.sr.ht/~martijnbraam/among-sus
  fd_set rfds, afds;
  uint16_t port = 1234;
  int listen_fd, listen6_fd, new_fd, i;
  socklen_t client_size;
  struct sockaddr_in listen_addr = {0}, client_addr = {0};
  struct sockaddr_in6 listen6_addr = {0};

  if ((listen_fd = socket(PF_INET, SOCK_STREAM, 0)) == -1) {
    perror("IPv4 socket");
    exit(EXIT_FAILURE);
  }
  if ((listen6_fd = socket(PF_INET6, SOCK_STREAM, 0)) == -1) {
    perror("IPv6 socket");
    exit(EXIT_FAILURE);
  }

  i = 1;
  if (setsockopt(listen_fd, SOL_SOCKET, SO_REUSEADDR, &i, sizeof(i))) {
    perror("IPv4 setsockopt");
    exit(EXIT_FAILURE);
  }

  if (setsockopt(listen6_fd, SOL_SOCKET, SO_REUSEADDR, &i, sizeof(i))) {
    perror("IPv6 setsockopt");
    exit(EXIT_FAILURE);
  }

  listen_addr.sin_family = AF_INET;
  listen_addr.sin_addr.s_addr = htonl(INADDR_ANY);
  listen_addr.sin_port = htons(port);

  listen6_addr.sin6_family = AF_INET6;
  listen6_addr.sin6_addr = in6addr_any;
  listen6_addr.sin6_port = htons(port);
  if (setsockopt(listen6_fd, IPPROTO_IPV6, IPV6_V6ONLY, &i, sizeof(i))) {
    perror("setsockopt");
    exit(EXIT_FAILURE);
  }
  if (setsockopt(listen6_fd, IPPROTO_IPV6, IPV6_V6ONLY, &i, sizeof(i))) {
    perror("setsockopt");
    exit(EXIT_FAILURE);
  }

  if (bind(listen_fd, (struct sockaddr *)&listen_addr, sizeof(listen_addr)) <
      0) {
    perror("ipv4 bind");
    return -1;
  }
  if (bind(listen6_fd, (struct sockaddr *)&listen6_addr, sizeof(listen6_addr)) <
      0) {
    perror("ipv6 bind");
    return -1;
  }

  listen(listen_fd, 5);
  listen(listen6_fd, 5);
  printf("Escuchando en :%d\n", port);

  FD_ZERO(&afds);
  FD_SET(listen_fd, &afds);
  FD_SET(listen6_fd, &afds);

  while (1) {
    rfds = afds;
    if (select(FD_SETSIZE, &rfds, NULL, NULL, NULL) < 0) {
      perror("select");
      exit(EXIT_FAILURE);
    }

    for (i = 0; i < FD_SETSIZE; ++i) {
      if (FD_ISSET(i, &rfds)) {
        if (i == listen_fd || i == listen6_fd) {
          client_size = sizeof(client_addr);
          new_fd = accept(i, (struct sockaddr *)&client_addr, &client_size);
          if (new_fd < 0) {
            perror("accept");
            exit(EXIT_FAILURE);
          }

          printf("Nueva conexión desde %s:%d\n", inet_ntoa(client_addr.sin_addr),
                 ntohs(client_addr.sin_port));
          FD_SET(new_fd, &afds);
          if (w_fd == -1) {
            dprintf(new_fd, "tú eres las blancas\n");
            w_fd = new_fd;
          } else if (b_fd == -1) {
            dprintf(new_fd, "tú eres las negras\n");
            dprintf(w_fd, "ha entrado las negras, ¡comenzamos!\n");
            b_fd = new_fd;
            if (fork() == 0) {
              play_game();
              return 0;
            } else {
              w_fd = -1;
              b_fd = -1;
              game_number++;
            }
          } else {
            // write(new_fd, "nincs hely!\n", strlen("nincs hely!\n"));
          }
        } else {
          close(i);
          FD_CLR(i, &afds);
        }
      }
    }
  }
  return 0;
}
Un proyecto texto-plano.xyz