我有一个正在努力的项目。它是一个分布式的tic tac toe游戏,有一个控制器和两个玩家。它利用半双工管道在进程之间进行通信。问题是进程没有正确通信,我不明白为什么。任何想法或帮助将非常感谢。这是代码:
// This tic tac toe program illustrates a three process application
// where two peer processes communicate through an oracle or server.
// A parent process acts as a controller and two child processes
// acts as PlayerX and PlayerO. Players send their choice of input to
// controller which checks the input and displays results.
// Libraries
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <sys/wait.h>
#include <sys/types.h>
// communication pipes constants
const int PIPE_READ = 0;
const int PIPE_WRITE = 1;
// position structure
struct _position {
int row;
int column;
};
typedef struct _position POSITION;
#define DEF_POSN(p, r, c) { p.row = r; p.column = c; }
//buffer for position
POSITION posn;
// message structure
struct _msg {
char cmd;
int data;
};
typedef struct _msg MESSAGE;
#define DEF_MSG(m, s, d) { m.cmd = s; m.data = d; }
// buffer for message
MESSAGE msg;
// controller and players can talk
void controllerSays(char * s){
printf("Controller says: %s\n", s);
}
void playerOSays(char * s ){
printf("Player O says: %s\n", s);
}
void playerXSays(char * s){
printf("Player X says: %s\n", s);
}
//controller will be a state machine
enum gameStatus {
QUIT = 0,
READY = 1,
CONTINUE =2,
P1_WIN = 3,
P2_WIN = 4,
DRAW = 5,
};
typedef enum gameStatus GameStatus;
// Global variables
char array[3][3] = {
{' ', ' ', ' '},
{' ', ' ', ' '},
{' ', ' ', ' '}
};
// Functions
int checkInput(int column, int row, int playerId)
{
// ERRORS:
// (-1) -> Wrong boundaries.
// (-2) -> Movement not allowed.
if( !((column >= 1 && column <= 3) && ( row >= 1 && row <= 3)) ) {
return -1; // Wrong boundaries
}
column -= 1;
row -= 1;
if( array[column][row] == ' ' ) { // Move is allowed
array[column][row] = (playerId == 1) ? 'O' : 'X';
} else {
return -2; // Error. There is already a mark in that position
}
return 1; // Successfull
}
void init_board()
{
int i, j;
for( i = 0; i < 3; i++ )
for( j = 0; j < 3; j++ )
array[i][j] = ' ';
}
void draw_grid()
{
// Print out the grid
printf(" 1 2 3 \n");
printf("1 %c | %c | %c \n", array[0][0], array[0][1], array[0][2]);
printf(" ---+---+--- \n");
printf("2 %c | %c | %c \n", array[1][0], array[1][1], array[1][2]);
printf(" ---+---+--- \n");
printf("3 %c | %c | %c \n", array[2][0], array[2][1], array[2][2]);
}
int winnerExists()
{
// Variables of function winnerExists.
int i, j;
for( i = 0; i < 3; i++ ) {
// Check horizontal for player 1
if( (array[i][0] == 'O' ) && (array[i][1] == 'O') && (array[i][2] == 'O') )
return P1_WIN;
// Check horizontal for player 2
else if( (array[i][0] == 'X') && (array[i][1] == 'X') && (array[i][2] == 'X') )
return P2_WIN;
// Check vertical for player 1
if( (array[0][i] == 'O') && (array[1][i] == 'O') && (array[2][i] == 'O') )
return P1_WIN;
// Check vertical for player 2
else if( (array[0][i] == 'X') && (array[1][i] == 'X') && (array[2][i] == 'X') )
return P2_WIN;
}
// Diagonal check for player 1
if( (array[0][0] == 'O') && (array[1][1] == 'O') && (array[2][2] == 'O') ) {
return P1_WIN;
}
else if( (array[0][2] == 'O') && (array[1][1] == 'O') && (array[2][0] == 'O') ) {
return P1_WIN;
}
// Diagonal check for player 2
if( (array[0][0] == 'X') && (array[1][1] == 'X') && (array[2][2] == 'X') ) {
return P2_WIN;
}
else if( (array[0][2] == 'X') && (array[1][1] == 'X') && (array[2][0] == 'X') ) {
return P2_WIN;
}
for( i = 0; i < 3; i++ ) {
for( j = 0; j < 3; j++ ) {
if( array[i][j] == ' ' )
return CONTINUE; // No winner yet.
}
}
// This is a tie. Nobody wins.
return DRAW;
}
void playerOprocess(int READ, int WRITE){
char reply = ' ';
int row;
int column;
GameStatus status = READY;
while (status != QUIT) {
playerOSays("in the loop p1");
// check what controller says
read(READ, &msg, sizeof(msg));
// want to play?
if (msg.cmd == 'r'){
playerOSays("Controller asks if you want to play a game? (Y/N): ");
scanf("%c", &reply);
DEF_MSG(msg, reply, 0);
write(WRITE, &msg, sizeof(msg));
// if submited data is invalid
} else if (msg.cmd == 'e') {
if (msg.data == -1){
playerOSays("Error: Wrong boundaries!\n");
} else if (msg.data == -2) {
playerOSays("Error: There is already a mark there!\n");
}
draw_grid();
playerOSays("Please enter the row and column,\n where you wish to place your mark (O): ");
scanf("%d %d", &row, &column);
DEF_POSN( posn, row, column);
write(WRITE, &posn, sizeof(posn));
// if everything is ok and we continue playing
} else if (msg.cmd == 'c') {
draw_grid();
playerOSays("Please enter the row and column,\n where you wish to place your mark (X): ");
scanf("%d %d", &row, &column);
DEF_POSN( posn, row, column);
write(WRITE, &posn, sizeof(posn));
// if player1 wins
} else if (msg.cmd == 'o') {
playerOSays("Hooray! I am the winner!");
// if player2 wins
} else if (msg.cmd == 'x') {
playerOSays("Nooo! I lost the game!");
// if a draw
} else if (msg.cmd == 'd') {
playerOSays("Dammit! Its a draw!");
// if quit
} else if (msg.cmd == 'q') {
playerOSays("I'm outta here!");
status = QUIT;
}
}
close(READ);
close(WRITE);
}
void playerXprocess(int READ, int WRITE){
char reply = ' ';
int row;
int column;
GameStatus status = READY;
while (status != QUIT){
playerXSays("in the loop p2");
// check what controller says
read(READ, &msg, sizeof(msg));
// want to play?
if (msg.cmd == 'r'){
playerXSays("Controller asks if you want to play a game? (Y/N): ");
scanf("%c", &reply);
DEF_MSG(msg, reply, 0);
write(WRITE, &msg, sizeof(msg));
// if submited data is invalid
}
if (msg.cmd == 'e') {
if (msg.data == -1){
playerXSays("Error: Wrong boundaries!\n");
} else if (msg.data == -2) {
playerXSays("Error: There is already a mark there!\n");
}
draw_grid();
playerXSays("Please enter the row and column,\n where you wish to place your mark (X): ");
scanf("%d %d", &row, &column);
DEF_POSN( posn, row, column);
write(WRITE, &posn, sizeof(posn));
// if everything is ok and we continue playing
} else if (msg.cmd == 'c') {
draw_grid();
playerXSays("Please enter the row and column,\n where you wish to place your mark (X): ");
scanf("%d %d", &row, &column);
DEF_POSN( posn, row, column);
write(WRITE, &posn, sizeof(posn));
// if player2 wins
} else if (msg.cmd == 'x') {
playerXSays("Hooray! I am the winner!");
// if player1 wins
} else if (msg.cmd == 'o') {
playerXSays("Nooo! I lost the game!");
// if a draw
} else if (msg.cmd == 'd') {
playerXSays("Dammit! Its a draw!");
// if quit
} else if (msg.cmd == 'q') {
playerXSays("I'm outta here!");
status = QUIT;
}
}
close(READ);
close(WRITE);
}
void controller(int READ_X, int WRITE_X, int READ_O, int WRITE_O){
int playerID = 1;
int row;
int column;
int inputCheck;
GameStatus status = READY;
while (status != QUIT){
controllerSays("in controller loop");
// send message to player 1 asking if he wants to play
// and get response from him
DEF_MSG(msg, 'r', 0);
write(WRITE_O, &msg, sizeof(msg));
sleep(5);
read(READ_O, &msg, sizeof(msg));
if ((msg.cmd == 'y') || (msg.cmd == 'Y')){
// send message to player 2 asking if he wants to play
// and get response from him
DEF_MSG(msg, 'r', 0);
write(WRITE_X, &msg, sizeof(msg));
read(READ_X, &msg, sizeof(msg));
if (msg.cmd == 'y' || msg.cmd == 'Y'){
status = CONTINUE;
}else {
// if they dont want to play tell them to quit
DEF_MSG(msg, 'q', 0);
write(WRITE_O, &msg, sizeof(msg));
write(WRITE_X, &msg, sizeof(msg));
status = QUIT;
}
} else {
// if they dont want to play tell them to quit
DEF_MSG(msg, 'q', 0);
write(WRITE_O, &msg, sizeof(msg));
write(WRITE_X, &msg, sizeof(msg));
status = QUIT;
}
init_board(); // Initialize array
while (status == CONTINUE) {
if (playerID == 1){
// tell player1 to start a game and make a move
DEF_MSG(msg, 'c', 0);
write(WRITE_O, &msg, sizeof(msg));
read(READ_O, &posn, sizeof(posn));
row = posn.row;
column = posn.column;
// check if input is valid
inputCheck = checkInput(row, column, playerID);
// if not valid tell player1 to make a valid move
while (inputCheck != 1) {
DEF_MSG(msg, 'e', inputCheck);
write(WRITE_O, &msg, sizeof(msg));
read(READ_O, &posn, sizeof(posn));
row = posn.row;
column = posn.column;
inputCheck = checkInput(row, column, playerID);
}
// if move is valid check the status of the game
// and construct a message with status update
status = winnerExists();
if (status == CONTINUE) {
DEF_MSG (msg, 'c', 0);
} else if (status == P1_WIN) {
DEF_MSG (msg, 'o', 0);
status = READY;
} else if (status == P2_WIN) {
DEF_MSG (msg, 'x', 0);
status = READY;
} else if (status == DRAW) {
DEF_MSG (msg, 'd', 0);
status = READY;
}
// update players status
write(WRITE_O, &msg, sizeof(msg));
write(WRITE_X, &msg, sizeof(msg));
// flip players
(playerID== 1) ? 2 : 1;
} else if (playerID == 2) {
// tell player2 to start a game and make a move
DEF_MSG(msg, 'c', 0);
write(WRITE_X, &msg, sizeof(msg));
read(READ_X, &posn, sizeof(posn));
row = posn.row;
column = posn.column;
// check if input is valid
inputCheck = checkInput(row, column, playerID);
// if not valid tell player2 to make a valid move
while (inputCheck != 1) {
DEF_MSG(msg, 'e', inputCheck);
write(WRITE_X, &msg, sizeof(msg));
read(READ_X, &posn, sizeof(posn));
row = posn.row;
column = posn.column;
inputCheck = checkInput(row, column, playerID);
}
draw_grid(); // Draw initial grid
// if move is valid check the status of the game
// and construct a message with status update
status = winnerExists();
if (status == CONTINUE) {
DEF_MSG (msg, 'c', 0);
} else if (status == P1_WIN) {
DEF_MSG (msg, 'o', 0);
status = READY;
} else if (status == P2_WIN) {
DEF_MSG (msg, 'x', 0);
status = READY;
} else if (status == DRAW) {
DEF_MSG (msg, 'd', 0);
status = READY;
}
// update players status
write(WRITE_X, &msg, sizeof(msg));
write(WRITE_O, &msg, sizeof(msg));
// flip players
(playerID == 1) ? 2 : 1;
}
}
}
// close pipes
close(READ_X);
close(WRITE_X);
close(READ_O);
close(WRITE_O);
}
int main() {
// pipes for communication with playerX
int fd_toPlayerX[2];
int fd_toControllerX[2];
// pipes for communication with playerO
int fd_toPlayerO[2];
int fd_toControllerO[2];
pipe(fd_toPlayerX);
pipe(fd_toControllerX);
pipe(fd_toPlayerO);
pipe(fd_toControllerO);
pid_t playerX, playerO;
// fork parent process with two children.
playerX = fork();
if ( playerX < 0 ){
fprintf(stderr, "Fork failure\n");
return -1;
}
if (playerX == 0) {
// playerX code
// Close pipes
close(fd_toPlayerX[PIPE_WRITE]);
close(fd_toControllerX[PIPE_READ]);
// call for playerX routine
playerXprocess(fd_toPlayerX[PIPE_READ], fd_toControllerX[PIPE_WRITE]);
} else {
playerO = fork();
if ( playerO < 0 ){
fprintf(stderr, "Fork failure\n");
return -1;
}
if (playerO == 0) {
// playerO code
// Close pipes
close(fd_toPlayerO[PIPE_WRITE]);
close(fd_toControllerO[PIPE_READ]);
// call for playerO routine
playerOprocess(fd_toPlayerO[PIPE_READ], fd_toControllerO[PIPE_WRITE]);
} else {
// Controller code
// Close pipes on playerX side
close(fd_toPlayerX[PIPE_READ]);
close(fd_toControllerX[PIPE_WRITE]);
// Close pipes on playerO side
close(fd_toPlayerO[PIPE_READ]);
close(fd_toControllerO[PIPE_WRITE]);
// Call for controller routine
controller(fd_toControllerX[PIPE_READ], fd_toPlayerX[PIPE_WRITE], fd_toControllerO[PIPE_READ], fd_toPlayerO[PIPE_WRITE]);
wait(NULL);
}
}
return 0;
}
答案 0 :(得分:0)
将记录添加到您的代码中。这样,您就可以获得执行代码的历史记录以及原因。通过阅读日志,您可以查看实际事件是否与您认为应该发生的事件相符。
以最简单的形式,使用printf()
。我建议将每个打印调用打包在D()
:
#ifdef DEBUG
# define D(x) x
#else
# define D(x)
#endif
然后,您可以通过定义符号DEBUG
答案 1 :(得分:0)
问题似乎恰好在控制器的开头 处理。而不是检查来自playerO的消息,它跳转到playerX, 我不明白为什么。
在每个回合中你发送两个&#39; c&#39;发送给当前玩家的消息 - 一个在开头(评论tell player1 to start a game and make a move
),另一个在转弯结束时(评论update players status
)。但是玩家,当它收到一个&#39; c&#39;消息,绘制网格以及扫描输入,因此,在第一个回合结束时再次从playerO请求输入,并且在第一个回合开始时几乎同时从playerX请求输入。这里似乎需要两种不同的消息类型:一种用于请求移动输入,另一种用于更新网格显示。