Seguir ejecutando bucle mientras potencialmente tomando entrada

Estoy tratando de hacer un juego simple de Tetris en C. Llegué a la parte de entrada y me encontré con problemas. Hice un bucle que mueve la nueva pieza hacia abajo cada segundo. Ahora quiero que esto suceda, pero quiero que el jugador pueda presionar un botón para mover la pieza, como es el objeto del juego, por supuesto. Estas dos cosas no deben interferir. El bucle de juego es

for (i=1;i<100;i++) { printBoard(&current); if (move(&current)) spawn(&current); sleep(1); } 

Aquí la función mueve, mueve el bloque que cae hacia abajo una unidad y devuelve un 1 si el bloque toca el suelo u otra pieza, en cuyo caso se genera un nuevo bloque a través de la función de engendro. printboard simplemente imprime el tablero al terminal. ¿Cuál es la mejor manera de hacer esto?

Gracias por adelantado

Para completar, aquí está el código completo hasta ahora

 #include  #include  #define height 20 #define width 15 typedef struct board{ int x[height][width]; int score; } board; void printBoard(board * current){ int i,j; for (i=0;iscore); for (i=0;i<height-1;i++) { printf("|"); for (j=0;jx[i][j] == 0) printf(" "); else printf("x"); } printf("|\n"); } for (i=0;ix[0][4] = 2; current->x[1][4] = 2; current->x[1][5] = 2; current->x[1][6] = 2; current->x[1][7] = 2; } int move(board * current){ // returns 1 if block hits ground int i,j; for (i=(height-1);i>0;i--) for (j=0;jx[i-1][j] == 2){ if (i==(height-1) || current->x[i][j] == 1){ goto DONE; } current->x[i][j] = 2; current->x[i-1][j] = 0; } return 0; DONE: for (i=0;i<height;i++) for (j=0;jx[i][j] == 2) current->x[i][j] = 1; return 1; } int main(){ board current; current.score = 0; int i,j; for (i=0;i<height;i++) for (j=0;j<width;j++) current.x[i][j] = 0; spawn(&current); for (i=1;i<100;i++) { printBoard(&current); if (move(&current)) spawn(&current); sleep(1); } return 0; } 

la forma habitual de hacerlo es confiar en una encuesta () o seleccionar () llamada.

la idea es establecer un tiempo de espera en la llamada de selección (porque sería de 1 segundo) y realizar la actualización estándar cuando se produce el tiempo de espera.

La entrada del usuario se recupera a través de un descriptor de archivo (aquí supongo que sería estándar, por lo tanto 0) y cada vez que el usuario presiona un botón, la selección sale, pero esta vez, el fd está marcado como con entradas, por lo que solo tiene que lee la entrada y trata lo que acabas de leer. e ir de nuevo esperando en el select ()

El pseudo código se vería (tome del hombre seleccionado):

  int main(void) { fd_set rfds; struct timeval tv; int retval; /* look stdin (fd 0) for inputs */ FD_ZERO(&rfds); FD_SET(0, &rfds); /* wait 1 second. */ tv.tv_sec = 1; tv.tv_usec = 0; retval = select(1, &rfds, NULL, NULL, &tv); /* Carefull tv was updated (on linux) */ if (retval == -1) perror(" an error occured"); else if (retval == 1) { printf("Data is available on stdin \n"); /* FD_ISSET(0, &rfds) should be true */ handle_input(); } else { printf("Timeout.\n"); update_status(); } exit(EXIT_SUCCESS); } 

En un * nix, puede configurar su archivo de entrada de entrada en modo de no locking. Luego, puede intentar una lectura en cada intervalo de actualización y tendrá éxito o fallará con EAGAIN (asumiendo que no hay error):

 #include  #include  //... fcntl(0 /*==stdin*/, F_SETFL, O_NONBLOCK); 

Si su entrada es un terminal, también deberá deshabilitar el búfer de línea de terminales (por ejemplo, con cbreak() si vincula ncurses ).

select y la familia son útiles si no tiene nada más que hacer que esperar en la entrada. En ese caso, perder el tiempo de CPU que otros procesos podrían utilizar.