//Gregory Szorc <gregory.szorc@case.edu>
//EECS 338 HW 2
//2005-09-29
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <stdio.h>
#include <stdlib.h>
#include <netdb.h>
#include <sys/types.h>
#include <unistd.h>
#include <wait.h>
void parentGameCoordinator();
void childGamePlayer(int inputPipe[], int outputPipe[]);
int getNextResponse(int inputPipe[]);
int getProcessId(int inputPipe[]);
int getWeapon(int inputPipe[]);
char * getWeaponName(int weapon);
//the protocol between the parent and children consists of two fields
//1) the action type of the message
//2) the value of the message
//specifies a packet containing the round result
const char * actionRoundResult = "0";
//query packet for what child process wants to do
const char * actionNextQuery = "1";
//response from above query packet
const char * actionNextResponse = "2";
//the chosen weapon
const char * actionRoundSelection = "3";
//the process id
const char * actionProcessId = "4";
//from parent to child telling to terminate
const char * actionEnd = "5";
const char * actionGetProcessId = "6";
const char * actionGetWeapon = "7";
const char * roundResponseNext = "0";
const char * roundResponseEnd = "1";
const char * roundResultWon = "0";
const char * roundResultLost = "1";
const char * roundResultDraw = "2";
const int weaponRock = 0;
const int weaponPaper = 1;
const int weaponScissors = 2;
int main(int argc, char *argv[])
{
parentGameCoordinator();
return EXIT_SUCCESS;
}
void parentGameCoordinator() {
int roundNumber = 1;
int player1InputPipe[2];
int player1OutputPipe[2];
pid_t player1Pid;
int player1Process;
int player1InputPipeStatus;
int player1OutputPipeStatus;
double player1Score = 0;
int player2InputPipe[2];
int player2OutputPipe[2];
pid_t player2Pid;
int player2Process;
int player2InputPipeStatus;
int player2OutputPipeStatus;
double player2Score = 0;
int player1Continue = 1;
int player2Continue = 1;
int player1Weapon;
int player2Weapon;
char read1Action[2];
char read2Action[2];
int read1Value;
int read2Value;
int winner = 0;
//create the pipes
player1InputPipeStatus = pipe(player1InputPipe);
if (player1InputPipeStatus == -1) {
perror("Player 1 input pipe not created");
exit(EXIT_FAILURE);
}
player1OutputPipeStatus = pipe(player1OutputPipe);
if (player1OutputPipeStatus == -1) {
perror("Player 1 output pipe not created");
exit(EXIT_FAILURE);
}
player2InputPipeStatus = pipe(player2InputPipe);
if (player2InputPipeStatus == -1) {
perror("Player 2 input pipe not created");
exit(EXIT_FAILURE);
}
player2OutputPipeStatus = pipe(player2OutputPipe);
if (player2OutputPipeStatus == -1) {
perror("Player 2 output pipe not created");
exit(EXIT_FAILURE);
}
player1Pid = fork();
switch (player1Pid) {
case -1:
perror("fork of player 1 failed");
exit(1);
case 0:
//inside child process
childGamePlayer(player1InputPipe, player1OutputPipe);
exit(EXIT_SUCCESS);
//never reached
default:
//inside parent process
player2Pid = fork();
switch (player2Pid) {
case -1:
perror("fork of player 2 failed");
exit(EXIT_FAILURE);
case 0:
//inside child process
childGamePlayer(player2InputPipe, player2OutputPipe);
exit(EXIT_SUCCESS);
//never reached
default:
//inside parent process
//both children processes have been forked now
//ask the children for their process number
write(player1InputPipe[1], actionGetProcessId, 2);
write(player2InputPipe[1], actionGetProcessId, 2);
player1Process = getProcessId(player1OutputPipe);
player2Process = getProcessId(player2OutputPipe);
player1Process = player1Pid;
player2Process = player2Pid;
while (player1Continue && player2Continue) {
//start by asking the children what they want to do
if (write(player1InputPipe[1], actionNextQuery, 2) == -1) {
perror("failed to write to player 1\n");
}
if (write(player2InputPipe[1], actionNextQuery, 2) == -1) {
perror("failed to write to player 2\n");
}
read1Value = getNextResponse(player1OutputPipe);
read2Value = getNextResponse(player2OutputPipe);
if (read1Value != atoi(roundResponseNext)) {
player1Continue = 0;
}
if (read2Value != atoi(roundResponseNext)) {
player2Continue = 0;
}
//if both want to play the game
if (player1Continue && player2Continue) {
printf("Round #%i\n", roundNumber);
roundNumber++;
write(player1InputPipe[1], actionGetWeapon, 2);
write(player2InputPipe[1], actionGetWeapon, 2);
player1Weapon = getWeapon(player1OutputPipe);
player2Weapon = getWeapon(player2OutputPipe);
printf("Player %d: %s\n", player1Process, getWeaponName(player1Weapon));
printf("Player %d: %s\n", player2Process, getWeaponName(player2Weapon));
winner = -1;
if (player1Weapon == weaponRock) {
if (player2Weapon == weaponScissors) winner = player1Process;
if (player2Weapon == weaponPaper) winner = player2Process;
}
if (player1Weapon == weaponScissors) {
if (player2Weapon == weaponRock) winner = player2Process;
if (player2Weapon == weaponPaper) winner = player1Process;
}
if (player1Weapon == weaponPaper) {
if (player2Weapon == weaponRock) winner = player1Process;
if (player2Weapon == weaponScissors) winner = player2Process;
}
write(player1InputPipe[1], actionRoundResult, 2);
write(player2InputPipe[1], actionRoundResult, 2);
if (winner == -1) {
printf("Draw\n");
player1Score += 0.5;
player2Score += 0.5;
write(player1InputPipe[1], roundResultDraw, 2);
write(player2InputPipe[1], roundResultDraw, 2);
}
else {
printf("Player %d Win\n", winner);
if (winner = player1Process) {
player1Score += 1;
write(player1InputPipe[1], roundResultWon, 2);
write(player2InputPipe[1], roundResultLost, 2);
}
else if (winner = player2Process) {
player2Score += 1;
write(player1InputPipe[1], roundResultLost, 2);
write(player2InputPipe[1], roundResultWon, 2);
}
}
printf("\n");
}
//else the while loop doesn't repeat
}
//printf("a child has requested to stop\n");
//tell the players to end
write(player1InputPipe[1], actionEnd, 2);
write(player2InputPipe[1], actionEnd, 2);
printf("Final Score:\n");
printf("Player %d: %.1f\n", player1Process, player1Score);
printf("Player %d: %.1f\n", player2Process, player2Score);
}
}
}
int getNextResponse(int inputPipe[]) {
char inputAction[2];
char inputValue[2];
while (read(inputPipe[0], inputAction, 2) > 0) {
if (strcmp(inputAction, actionNextResponse) == 0) {
while (read(inputPipe[0], inputValue, 2) > 0) {
return atoi(inputValue);
}
}
}
return -1;
}
int getProcessId(int inputPipe[]) {
char inputAction[2];
char inputValue[2];
while (read(inputPipe[0], inputAction, 2) > 0) {
if (strcmp(inputAction, actionProcessId) == 0) {
while (read(inputPipe[0], inputValue, 2) > 0) {
return atoi(inputValue);
}
}
}
return -1;
}
int getWeapon(int inputPipe[]) {
char inputAction[2];
char inputValue[2];
while (read(inputPipe[0], inputAction, 2) > 0) {
if (strcmp(inputAction, actionRoundSelection) == 0) {
while (read(inputPipe[0], inputValue, 2) > 0) {
return atoi(inputValue);
}
}
}
return -1;
}
char* getWeaponName(int Weapon) {
if (Weapon == weaponRock) {
return "rock";
}
else if (Weapon == weaponPaper) {
return "paper";
}
else if (Weapon == weaponScissors) {
return "scissors";
}
else {
return "UNKNOWN";
}
}
//inputPipe gets input from parent
//outputPipe writes to the parent
void childGamePlayer(int inputPipe[], int outputPipe[]) {
pid_t process;
char processString[16];
int readStatus;
int writeStatus;
//holds data from pipe (one byte larger than necessary)
char readAction[2];
char readValue[2];
int roundsToPlay = 0;
int roundsPlayed = 0;
int drawsPlayed = 0;
int chosenWeapon = 0;
char chosenWeaponString[16];
int lastRoundResult = 0;
int opponentWeapon = 0;
int opponentRockCount = 0;
int opponentPaperCount = 0;
int opponentScissorCount = 0;
int opponentRockFollowPaperCount = 0;
int opponentRockFollowScissorCount = 0;
int opponentRockFollowRockCount = 0;
int opponentPaperFollowPaperCount = 0;
int opponentPaperFollowScissorCount = 0;
int opponentPaperFollowRockCount = 0;
int opponentScissorFollowPaperCount = 0;
int opponentScissorFollowScissorCount = 0;
int opponentScissorFollowRockCount = 0;
int opponentSameFollowDrawCount = 0;
int opponentLastWeapon = 0;
int selectRock = 0;
int selectPaper = 0;
int selectScissors = 0;
process = getpid();
sprintf(processString, "%d", getpid());
//at most play 100 rounds
roundsToPlay = 10 + ((rand() * process) % 90);
//close uncessary part of pipes
close(inputPipe[1]);
close(outputPipe[0]);
printf("in player process\n");
//enter an infinite loop
while (1) {
//read the action code from the input pipe
while ((readStatus = read(inputPipe[0], readAction, 2)) > 0) {
//printf("Read action byte = %s\n", readAction);
//if the parent is telling us to stop execution
if (strcmp(readAction, actionEnd) == 0) {
//printf("Child terminating\n");
exit(EXIT_SUCCESS);
}
if (strcmp(readAction, actionNextQuery) == 0) {
//printf("parent asking what to do\n");
write(outputPipe[1], actionNextResponse, 2);
if (roundsPlayed < roundsToPlay) {
roundsPlayed++;
//printf("child wants to play more\n");
write(outputPipe[1], roundResponseNext, 2);
}
else {
//printf("we don't want to play anymore\n");
write(outputPipe[1], roundResponseEnd, 2);
}
}
if (strcmp(readAction, actionGetProcessId) == 0) {
//printf("parent asking for process id\n");
write(outputPipe[1], actionProcessId, 2);
write(outputPipe[1], processString, 2);
}
if (strcmp(readAction, actionGetWeapon) == 0) {
//printf("parent asking for our weapon\n");
//let's select a weapon based upon what our opponent has done
//we give points to a certain weapon based upon previous results
//the weapon with the most points wins the selection process
//reset the scores to 0
selectRock = 0;
selectPaper = 0;
selectScissors = 0;
//we assign 5 points to every weapon for each time it could have won a round
selectRock += 5 * (roundsPlayed - opponentScissorCount);
selectPaper += 5 * (roundsPlayed - opponentRockCount);
selectScissors += 5 * (roundsPlayed - opponentPaperCount);
//handle points based on the last weapon
if (opponentLastWeapon == weaponRock) {
//if there is a good chance that a certain weapon will follow the rock
if (opponentRockFollowRockCount / roundsPlayed > 0.2) {
selectPaper += 50 * opponentRockFollowRockCount / roundsPlayed;
}
if (opponentPaperFollowRockCount / roundsPlayed > 0.2) {
selectScissors += 50 * opponentPaperFollowRockCount / roundsPlayed;
}
if (opponentScissorFollowRockCount / roundsPlayed > 0.2) {
selectRock += 50 * opponentScissorFollowRockCount / roundsPlayed;
}
}
else if (opponentLastWeapon == weaponPaper) {
if (opponentRockFollowPaperCount / roundsPlayed > 0.2) {
selectPaper += 50 * opponentRockFollowPaperCount / roundsPlayed;
}
if (opponentPaperFollowPaperCount / roundsPlayed > 0.2) {
selectScissors += 50 * opponentPaperFollowPaperCount / roundsPlayed;
}
if (opponentScissorFollowPaperCount / roundsPlayed > 0.2) {
selectRock += 50 * opponentScissorFollowPaperCount / roundsPlayed;
}
}
else if (opponentLastWeapon == weaponScissors) {
if (opponentRockFollowScissorCount / roundsPlayed > 0.2) {
selectPaper += 50 * opponentRockFollowScissorCount / roundsPlayed;
}
if (opponentPaperFollowScissorCount / roundsPlayed > 0.2) {
selectScissors += 50 * opponentPaperFollowScissorCount / roundsPlayed > 0.2;
}
if (opponentScissorFollowScissorCount / roundsPlayed > 0.2) {
selectRock += 50 * opponentScissorFollowScissorCount / roundsPlayed;
}
}
//if the last round was a chosenWeapon = ((rand() * process) ^ 2 * process) % 3;draw
if (lastRoundResult == atoi(roundResultDraw)) {
//if the opponent is likely to repeat the same weapon on a draw
if (drawsPlayed && (opponentSameFollowDrawCount / drawsPlayed > 0.5)) {
if (opponentLastWeapon == weaponRock) {
selectPaper += 20 * drawsPlayed;
}
if (opponentLastWeapon == weaponPaper) {
selectScissors += 20 * drawsPlayed;
}
if (opponentLastWeapon == weaponScissors) {
selectRock += 20 * drawsPlayed;
}
}
}
//randomness is part of every game
selectRock += (rand() * process ^ (rand() % 10)) % (2 * roundsPlayed);
selectPaper += (rand() * process ^ (rand() % 10)) % (2 * roundsPlayed);
selectScissors += (rand() * process ^ (rand() % 10)) % (2 * roundsPlayed);
//printf("Rock: %d\nPaper: %d\nScissors: %d\n", selectRock, selectPaper, selectScissors);
//if rock is a clear winner
if (selectRock > selectPaper && selectRock > selectScissors) {
chosenWeapon = weaponRock;
}
//if paper is a clear winner
else if (selectPaper > selectRock && selectPaper > selectScissors) {
chosenWeapon = weaponPaper;
}
//if scissors is a clear winner
else if (selectScissors > selectRock && selectScissors > selectPaper) {
chosenWeapon = weaponScissors;
}
else {
//if there is a tie
//we just chose a random weapon
chosenWeapon = (process ^ (rand() % 10) * process) % 3;
}
sprintf(chosenWeaponString, "%d", chosenWeapon);
write(outputPipe[1], actionRoundSelection, 2);
write(outputPipe[1], chosenWeaponString, 2);
}
if (strcmp(readAction, actionRoundResult) == 0) {
read(inputPipe[0], readValue, 2);
lastRoundResult = atoi(readValue);
if (strcmp(readValue, roundResultWon) == 0) {
if (chosenWeapon == weaponRock) opponentWeapon = weaponScissors;
if (chosenWeapon == weaponPaper) opponentWeapon = weaponRock;
if (chosenWeapon == weaponScissors) opponentWeapon = weaponPaper;
}
else if (strcmp(readValue, roundResultLost) == 0) {
if (chosenWeapon == weaponRock) opponentWeapon = weaponPaper;
if (chosenWeapon == weaponPaper) opponentWeapon = weaponScissors;
if (chosenWeapon == weaponScissors) opponentWeapon = weaponRock;
}
else if (strcmp(readValue, roundResultDraw) == 0) {
opponentWeapon = chosenWeapon;
drawsPlayed++;
if (opponentWeapon == opponentLastWeapon) {
opponentSameFollowDrawCount++;
}
}
//now collect some statistics
if (opponentWeapon == weaponRock) {
opponentRockCount++;
}
if (opponentWeapon == weaponScissors) {
opponentScissorCount++;
}
if (opponentWeapon == weaponPaper) {
opponentPaperCount++;
}
if (opponentLastWeapon == weaponRock) {
if (opponentWeapon == weaponRock) {
opponentRockFollowRockCount++;
}
if (opponentWeapon == weaponPaper) {
opponentPaperFollowRockCount++;
}
if (opponentWeapon == weaponScissors) {
opponentScissorFollowRockCount++;
}
}
else if (opponentLastWeapon == weaponPaper) {
if (opponentWeapon == weaponRock) {
opponentRockFollowPaperCount++;
}
if (opponentWeapon == weaponPaper) {
opponentPaperFollowPaperCount++;
}
if (opponentWeapon == weaponScissors) {
opponentScissorFollowPaperCount++;
}
}
else if (opponentLastWeapon == weaponScissors) {
if (opponentWeapon == weaponRock) {
opponentRockFollowScissorCount++;
}
if (opponentWeapon == weaponPaper) {
opponentPaperFollowScissorCount++;
}
if (opponentWeapon == weaponScissors) {
opponentScissorFollowScissorCount++;
}
}
opponentLastWeapon = opponentWeapon;
}
/*
//data comes in pairs, so read the 2nd byte
while ((readStatus = read(inputPipe[0], readValue, 1)) > 0) {
//do our action
printf("Read value byte = %s\n", readValue);
}
*/
}
}
}