Untitled

 avatar
unknown
c_cpp
2 years ago
10 kB
5
Indexable
#include "status.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <poll.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <fcntl.h>
#include <ctype.h>
#define debug(args...) fprintf(stderr, args)

typedef enum {
    INIT,
	WAITING,
	PLAYING,
	PASSING,
} Battle_mode;

char buf[512];

int pid;
char pidstr[15];
int logfile_fd;

int parent_pid;
char* parent_id;

// [0]: left, [1]: right
int child_pid[2];
char* child_id[2];
Status child_status[2];
int waitchild[2] = {};
int diedchild[2] = {};

int pipe_fd[4][2]; // [0]: read left, [1]: write left, [2]: read right, [3]: write right
struct pollfd poll_fd[2];
int type; // 0: 2 battle, 1: 1 battle 1 player, 2: 2 player
int lose; // 0: left lose, 1: right lose
int* end;
int champion = 0;

void writelogfile(int target, char* id, int child){
	char buf[512];
	if(target == 0) // pipe from child
		sprintf(buf, "%s,%d pipe from %s,%d %d,%d,%s,%d\n", id, pid, child_id[child], child_pid[child], child_status[child].real_player_id, child_status[child].HP, child_status[child].current_battle_id, child_status[child].battle_ended_flag);
	else if(target == 1) // pipe to child
		sprintf(buf, "%s,%d pipe to %s,%d %d,%d,%s,%d\n", id, pid, child_id[child], child_pid[child], child_status[child].real_player_id, child_status[child].HP, child_status[child].current_battle_id, child_status[child].battle_ended_flag);
	else if(target == 2) // pipe from parent
		sprintf(buf, "%s,%d pipe from %s,%d %d,%d,%s,%d\n", id, pid, parent_id, parent_pid, child_status[child].real_player_id, child_status[child].HP, child_status[child].current_battle_id, child_status[child].battle_ended_flag);
	else if(target == 3) // pipe to parent
		sprintf(buf, "%s,%d pipe to %s,%d %d,%d,%s,%d\n", id, pid, parent_id, parent_pid, child_status[child].real_player_id, child_status[child].HP, child_status[child].current_battle_id, child_status[child].battle_ended_flag);
	
	write(logfile_fd, buf, strlen(buf));
	return;
}

void printchampion(int child){
	char buf[512];
	sprintf(buf, "Champion is P%d\n", child_status[child].real_player_id);
	write(STDOUT_FILENO, buf, strlen(buf));
	champion = 1;
	return;
}

int findid(char* id){
	switch(id[0]){
		case 'A':
			child_id[0] = "B"; child_id[1] = "C";
			parent_id = NULL;
			return 0;
		case 'B':
			child_id[0] = "D"; child_id[1] = "E";
			parent_id = "A";
			return 0;
		case 'D':
			child_id[0] = "G"; child_id[1] = "H";
			parent_id = "B";
			return 0;
		case 'E':
			child_id[0] = "I"; child_id[1] = "J";
			parent_id = "B";
			return 0;
		case 'F':
			child_id[0] = "K"; child_id[1] = "L";
			parent_id = "C";
			return 0;
		case 'C':
			child_id[0] = "F"; child_id[1] = "14";
			parent_id = "A";
			return 1;
		case 'K':
			child_id[0] = "M"; child_id[1] = "10";
			parent_id = "F";
			return 1;
		case 'L':
			child_id[0] = "N"; child_id[1] = "13";
			parent_id = "F";
			return 1;
		case 'G':
			child_id[0] = "0"; child_id[1] = "1";
			parent_id = "D";
			return 2;
		case 'H':
			child_id[0] = "2"; child_id[1] = "3";
			parent_id = "D";
			return 2;
		case 'I':
			child_id[0] = "4"; child_id[1] = "5";
			parent_id = "E";
			return 2;
		case 'J':
			child_id[0] = "6"; child_id[1] = "7";
			parent_id = "E";
			return 2;
		case 'M':
			child_id[0] = "8"; child_id[1] = "9";
			parent_id = "K";
			return 2;
		case 'N':
			child_id[0] = "11"; child_id[1] = "12";
			parent_id = "L";
			return 2;
	}
}

int zone(char* id){
	switch(id[0]){
		// zone A
		case 'B': case 'D': case 'E': case 'G': case 'H': case 'I': case 'J':
			return 1;
		// zone B
		case 'A': case 'C': case 'F': case 'K': case 'L': case 'M': case 'N':
			return 2;
	}
}

void openlogfile(char* s){
	char buf[20];
	sprintf(buf, "log_battle%s.txt", s);
	logfile_fd = open(buf, O_RDWR | O_CREAT | O_TRUNC | O_APPEND, S_IRWXU | S_IRWXG | S_IRWXO);
	if(logfile_fd < 0) debug("openlogfile error\n");
	return;
}

struct pollfd newPollfd(int fd, short events){
    struct pollfd a;
    a.fd = fd;
    a.events = events;
    a.revents = 0;
    return a;
}

void receieve(int target, int fd, char* id, int child){
	read(fd, &(child_status[child]), sizeof(Status));
	writelogfile(target, id, child);
	return;
}

void send(int target, int fd, char* id, int child){
	writelogfile(target, id, child);
	write(fd, &(child_status[child]), sizeof(Status));
	return;
}

int attribute(char* id, Attribute a){
	switch(id[0]){
		case 'A': case 'E': case 'F': case 'G': case 'M':
			return (a == FIRE) + 1;
		case 'B': case 'K': case 'L': case 'H': case 'J':
			return (a == GRASS) + 1;
		case 'C': case 'D': case 'I': case 'N':
			return (a == WATER) +1;
	}
}

int subround(char* id, int att, int oth){ // att attack
	child_status[oth].HP -= child_status[att].ATK * attribute(id, child_status[att].attr);
	if(child_status[oth].HP <= 0){
		child_status[att].battle_ended_flag = child_status[oth].battle_ended_flag = 1;
		return 1;
	}
	return 0;
}

int playround(char* id){
	if((child_status[0].HP < child_status[1].HP) || ((child_status[0].HP == child_status[1].HP) && (child_status[0].real_player_id < child_status[1].real_player_id))){ // left first
		if(subround(id, 0, 1)) return 1;
		else if(subround(id, 1, 0)) return 0;
	}else if(child_status[0].HP > child_status[1].HP || ((child_status[0].HP == child_status[1].HP) && (child_status[0].real_player_id > child_status[1].real_player_id))){ // right first
		if(subround(id, 1, 0)) return 0;
		else if(subround(id, 0, 1)) return 1;
	}
	return 2;
}

int main (int argc, char *argv[]) {
	
	pid = getpid();
	sprintf(pidstr, "%d", pid);

	Battle_mode mode = INIT;
	while(diedchild[0] != 1 || diedchild[1] != 1){
		switch (mode)
		{
		case INIT:
			openlogfile(argv[1]);
			type = findid(argv[1]);
			
			// pipe
			for(int i = 0; i < 4; i++)
				pipe(pipe_fd[i]);
			fprintf(stderr, "%s after pipe\n", argv[1]);
			// fork
			if((child_pid[0] = fork()) < 0) debug("fork error\n");
			else if(child_pid[0] == 0){ // left child
					close(pipe_fd[0][0]); close(pipe_fd[1][1]); close(pipe_fd[2][0]); close(pipe_fd[2][1]); close(pipe_fd[3][0]); close(pipe_fd[3][1]);
					if(dup2(pipe_fd[0][1], STDOUT_FILENO) != STDOUT_FILENO) debug("dup2 error to stdout\n");
					close(pipe_fd[0][1]);
					if(dup2(pipe_fd[1][0], STDIN_FILENO) != STDIN_FILENO) debug("dup2 error to stdin\n");
					close(pipe_fd[1][0]);
					
					// exec
					if(type == 0 || type == 1){ // battle
						execl("./battle", "./battle", child_id[0], pidstr, NULL);
					}else if(type == 2){ // player
						fprintf(stderr, "%s fork child %s\n", argv[1], child_id[0]);
						execl("./player", "./player", child_id[0], pidstr, NULL);
					}
			}else if(child_pid[0] > 0){ // parent fork right child
				if((child_pid[1] = fork()) < 0) debug("fork error\n");
				else if(child_pid[1] == 0){ // right child
					close(pipe_fd[0][0]); close(pipe_fd[0][1]); close(pipe_fd[1][0]); close(pipe_fd[1][1]); close(pipe_fd[2][0]); close(pipe_fd[3][1]);
					if(dup2(pipe_fd[2][1], STDOUT_FILENO) != STDOUT_FILENO) debug("dup2 error to stdout\n");
					close(pipe_fd[2][1]);
					if(dup2(pipe_fd[3][0], STDIN_FILENO) != STDIN_FILENO) debug("dup2 error to stdin\n");
					close(pipe_fd[3][0]);
					
					// exec
					if(type == 0){ // battle
						execl("./battle", "./battle", child_id[1], pidstr, NULL);
					}else if(type == 1 || type == 2){ // player
						fprintf(stderr, "%s fork player %s\n", argv[1], child_id[1]);
						execl("./player", "./player", child_id[1], pidstr, NULL);
					}
				}
			}
			
			// parent
			close(pipe_fd[0][1]); close(pipe_fd[1][0]); close(pipe_fd[2][1]); close(pipe_fd[3][0]);
			poll_fd[0] = newPollfd(pipe_fd[0][0], POLLIN);
			poll_fd[1] = newPollfd(pipe_fd[2][0], POLLIN);
			
			debug(argv[1], "after fork\n");
			mode = WAITING;
			break;
		case WAITING:
			poll(poll_fd, 2, -1);
			if((poll_fd[0].revents & poll_fd[0].events) == POLLIN){ // left child send
				// pipe from left child
				receieve(0, poll_fd[0].fd, argv[1], 0);
				fprintf(stderr, "%s read left child\n", argv[1]);
				child_status[0].current_battle_id = argv[1][0];
				waitchild[0] = 1; poll_fd[0].events = 0;
			}
			if((poll_fd[1].revents & poll_fd[1].events) == POLLIN){ // right child send
				// pipe from right child
				receieve(0, poll_fd[1].fd, argv[1], 1);
				fprintf(stderr, "%s read right child\n", argv[1]);
				child_status[1].current_battle_id = argv[1][0];
				waitchild[1] = 1; poll_fd[1].events = 0;
			}
			if(waitchild[0] == 1 && waitchild[1] == 1){
				waitchild[0] = waitchild[1] = 0;
				mode = PLAYING;
			}
			break;
		case PLAYING:
			debug(argv[1], " PLAYING\n");
			lose = playround(argv[1]);
			diedchild[lose] = 1;
			
			// pipe to left child
			send(1, pipe_fd[1][1], argv[1], 0);
			// pipe to right child
			send(1, pipe_fd[3][1], argv[1], 1);
			
			if(lose != 2){
				waitpid(child_pid[lose], end, 0);
				if(argv[1][0] == 'A'){
					// print champion message
					printchampion(!lose);
					exit(0);
				}
				mode = PASSING;
			}else{
				mode = WAITING;
			}
			
			break;
		case PASSING:
			if(lose == 0){ // left lose
				// pipe from right child
				receieve(0, pipe_fd[2][0], argv[1], 1);
				
				// pipe to parent
				send(3, STDOUT_FILENO, argv[1], 1);
				
				// pipe from parent
				receieve(2, STDIN_FILENO, argv[1], 1);
				
				// pipe to right child
				send(1, pipe_fd[3][1], argv[1], 1);
				
				if(child_status[1].HP <= 0){
					waitpid(child_pid[1], end, 0);
					exit(0);
				}
			}else if(lose == 1){ // receive left pssm
				// pipe from left child
				receieve(0, pipe_fd[0][0], argv[1], 0);
				
				// pipe to parent
				send(3, STDOUT_FILENO, argv[1], 0);
				
				// pipe from parent
				receieve(2, STDIN_FILENO, argv[1], 0);
				
				// pipe to left child
				send(1, pipe_fd[1][1], argv[1], 0);
				
				if(child_status[0].HP <= 0){
					waitpid(child_pid[0], end, 0);
					exit(0);
				}
			}
			
			
			break;
		}
	}
	return 0;
}
Editor is loading...