diff options
| author | Franklin Wei <frankhwei536@gmail.com> | 2014-07-13 19:54:47 -0400 |
|---|---|---|
| committer | Franklin Wei <frankhwei536@gmail.com> | 2014-07-13 19:54:47 -0400 |
| commit | 79bd2194539aa559078de9afb1500a2e754ee501 (patch) | |
| tree | d4f1bd4fec8d118ad2ea95632597d60ef094029f | |
| parent | a46ef7c627eb6ee71f195d95c3e18a9c4e04a85c (diff) | |
| download | wargames-server-79bd2194539aa559078de9afb1500a2e754ee501.zip wargames-server-79bd2194539aa559078de9afb1500a2e754ee501.tar.gz wargames-server-79bd2194539aa559078de9afb1500a2e754ee501.tar.bz2 wargames-server-79bd2194539aa559078de9afb1500a2e754ee501.tar.xz | |
Added server
| -rw-r--r-- | GAMESPEC | 6 | ||||
| -rw-r--r-- | Makefile | 5 | ||||
| -rw-r--r-- | chatbot.c | 66 | ||||
| -rw-r--r-- | gtnw.c | 223 | ||||
| -rw-r--r-- | joshua.c | 34 | ||||
| -rw-r--r-- | joshua.h | 4 | ||||
| -rw-r--r-- | main.cpp | 31 | ||||
| -rw-r--r-- | server.c | 131 | ||||
| -rw-r--r-- | util.c | 46 | ||||
| -rw-r--r-- | util.h | 6 |
10 files changed, 329 insertions, 223 deletions
@@ -1,6 +1,5 @@ This file contains a formal definition of Global Thermonuclear War. =======GAMEPLAY======== -Each player starts with 32 ICBMs. The player with population still remaining after the other has been wiped out is the winner. If both players are wiped out, it is a tie. Each turn, the player can either: @@ -11,8 +10,8 @@ Each turn, the player can either: The behavior of each of these options is described below. ICBM launch: - - The USA can launch ICBMs at a maximum of 4 cities at a time. - - The USSR can launch 6 at a time. + - Both sides get 6 ICBMs per turn. + - The USSR gets 7 if it goes first. - When an ICBM is launched, there are 5 possible results: - Miss: 0 casualties - Marginal: 20%+1000 casualties @@ -37,7 +36,6 @@ Negociation: - Peace/Progress - 20% - Surprise attack - 20% - No progress - 60% - - When progress is made, both sides will lose 4 ICBMs - Progress must be made at least 5 times if peace is to be achieved Surrender: @@ -1,9 +1,8 @@ -SOURCES=joshua.o main.o util.o chatbot.o gtnw.o strings.o +SOURCES=joshua.o server.o util.o chatbot.o gtnw.o strings.o HEADERS=chatbot.h gtnw.h joshua.h location.h strings.h map.h util.h -CXXFLAGS=-lncurses -g -O3 CFLAGS=-std=gnu99 -g -O3 wargames: $(SOURCES) $(HEADERS) - g++ $(SOURCES) $(CXXFLAGS) -lncurses -o wargames + g++ $(SOURCES) $(CXXFLAGS) -o wargames all: wargames Makefile clean: rm -f $(SOURCES) a.out wargames *~ @@ -14,24 +14,23 @@ * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. - * + * * Contact the author at contact@fwei.tk */ #include "gtnw.h" #include "strings.h" #include "util.h" -#include <curses.h> +#include <stdbool.h> #include <stdlib.h> #include <string.h> #include <unistd.h> - void do_chatbot(void) { - int stage=0; /* stage 0: i'm fine how are you... -> - stage 1: people sometimes make mistakes -> - stage 2: love to. how about global thermonuclear war? -> - stage 3: no lets play global thermonuclear war -> + int stage=0; /* stage 0: i'm fine how are you... -> + stage 1: people sometimes make mistakes -> + stage 2: love to. how about global thermonuclear war? -> + stage 3: no lets play global thermonuclear war -> stage 4: GLOBAL THERMONUCLEAR WAR!!! */ while(1) { @@ -61,7 +60,7 @@ void do_chatbot(void) valid=true; } } - break; + break; case 1: for(int i=0;i<sizeof(stage2_triggers)/sizeof(const char*);++i) { @@ -72,18 +71,18 @@ void do_chatbot(void) valid=true; } } - break; + break; case 2: for(int i=0;i<sizeof(stage3_triggers)/sizeof(const char*);++i) { if(strcmp(buf, stage3_triggers[i])==0) - { + { print_string("\n\nWOULDN'T YOU PREFER A GOOD GAME OF CHESS?\n\n"); ++stage; valid=true; } } - break; + break; case 3: for(int i=0;i<sizeof(stage4_triggers)/sizeof(const char*);++i) { @@ -95,29 +94,29 @@ void do_chatbot(void) global_thermonuclear_war(); } } - break; + break; } // switch - /* now check for phase-insensitive strings */ - for(int i=0;i<sizeof(exit_triggers)/sizeof(const char*);++i) - { - if(strcmp(buf, exit_triggers[i])==0) - { - print_string("\n\n"); - print_string(exit_responses[rand()%(sizeof(exit_responses)/sizeof(const char*))]); - print_string("\n--CONNECTION TERMINATED--"); - return; - } - } - for(int i=0;i<sizeof(greetings_triggers)/sizeof(const char*);++i) - { - if(strcmp(buf, greetings_triggers[i])==0) - { - print_string("\n\n"); - print_string(greetings_responses[rand()%(sizeof(greetings_responses)/sizeof(const char*))]); - print_string("\n\n"); - valid=true; - } - } + /* now check for phase-insensitive strings */ + for(int i=0;i<sizeof(exit_triggers)/sizeof(const char*);++i) + { + if(strcmp(buf, exit_triggers[i])==0) + { + print_string("\n\n"); + print_string(exit_responses[rand()%(sizeof(exit_responses)/sizeof(const char*))]); + print_string("\n--CONNECTION TERMINATED--"); + return; + } + } + for(int i=0;i<sizeof(greetings_triggers)/sizeof(const char*);++i) + { + if(strcmp(buf, greetings_triggers[i])==0) + { + print_string("\n\n"); + print_string(greetings_responses[rand()%(sizeof(greetings_responses)/sizeof(const char*))]); + print_string("\n\n"); + valid=true; + } + } if(!valid) { print_string("\n\n"); @@ -127,4 +126,3 @@ void do_chatbot(void) } // else } // while } - @@ -14,7 +14,7 @@ * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. - * + * * Contact the author at contact@fwei.tk */ @@ -22,8 +22,8 @@ #include "location.h" #include "map.h" #include "util.h" -#include <curses.h> #include <stdlib.h> +#include <stdio.h> #include <string.h> #include <time.h> #include <unistd.h> @@ -69,16 +69,16 @@ static void fire_missile(struct location_t* city) /* calculate populations of US+USSR by totaling the populations of each of their cities */ static void calc_pops(long long* us_pop, long long* ussr_pop) -{ +{ *us_pop=0; *ussr_pop=0; /* calculate populations */ for(int i=0;i<sizeof(world)/sizeof(struct location_t);++i) { if(world[i].owner==USSR) - *ussr_pop+=world[i].population; + *ussr_pop+=world[i].population; else - *us_pop+=world[i].population; + *us_pop+=world[i].population; } } @@ -98,31 +98,31 @@ static void print_map_with_pops(void) for(int i=0;i<sizeof(world)/sizeof(struct location_t);++i) { if(world[i].owner==USSR) - { - ussr_cities[ussr_back]=world[i]; - ++ussr_back; - } + { + ussr_cities[ussr_back]=world[i]; + ++ussr_back; + } else - { - us_cities[us_back]=world[i]; - ++us_back; - } + { + us_cities[us_back]=world[i]; + ++us_back; + } } if(us_back<ussr_back) { while(us_back!=ussr_back) - { - us_cities[us_back].print=false; - ++us_back; - } + { + us_cities[us_back].print=false; + ++us_back; + } } else if(us_back>ussr_back) { while(us_back!=ussr_back) - { - ussr_cities[ussr_back].print=false; - ++ussr_back; - } + { + ussr_cities[ussr_back].print=false; + ++ussr_back; + } } us_cities[us_back].print=true; us_cities[us_back].print_name="Total"; @@ -137,19 +137,19 @@ static void print_map_with_pops(void) for(int i=0;i<us_back;++i) { if(us_cities[i].print && ussr_cities[i].print) - { + { char buf_2[32]; snprintf(buf_2, 31, "%u", us_cities[i].population); - snprintf(buf, 512, "%s: %u %*s: %u", us_cities[i].print_name, us_cities[i].population, 64-strlen(us_cities[i].print_name)-strlen(buf_2), ussr_cities[i].print_name, ussr_cities[i].population); - } + snprintf(buf, 512, "%s: %u %*s: %u", us_cities[i].print_name, us_cities[i].population, 64-strlen(us_cities[i].print_name)-strlen(buf_2), ussr_cities[i].print_name, ussr_cities[i].population); + } else if(us_cities[i].print && !ussr_cities[i].print) - snprintf(buf, 512, "%s: %u", us_cities[i].print_name, us_cities[i].population); + snprintf(buf, 512, "%s: %u", us_cities[i].print_name, us_cities[i].population); else - { - memset(buf, ' ', 255); - buf[255]=0; - snprintf(buf+64, 512-64, "%s: %u", ussr_cities[i].print_name, ussr_cities[i].population); - } + { + memset(buf, ' ', 255); + buf[255]=0; + snprintf(buf+64, 512-64, "%s: %u", ussr_cities[i].print_name, ussr_cities[i].population); + } print_string(buf); print_string("\n"); } @@ -158,16 +158,14 @@ static void print_map_with_pops(void) /* prompt the user for targets for the initial strike */ static void do_first_strike(int side) { - attr_on(WA_UNDERLINE, 0); print_string("AWAITING FIRST STRIKE COMMAND"); - attr_off(WA_UNDERLINE, 0); print_string("\n\n\nPLEASE LIST PRIMARY TARGETS BY\nCITY AND/OR COUNTY NAME:\n\n"); char target_names[32][129]; bool good=true; int num_targets=0; struct location_t *targets[32]; int num_targets_found=0; - int max_targets=side==USA?4:6; + int max_targets=side==USA?6:7; for(int i=0;num_targets_found<max_targets && good;++i) { getnstr(target_names[i], 128); @@ -176,52 +174,52 @@ static void do_first_strike(int side) good=false; } else - { - ++num_targets; - allLower(target_names[i]); - remove_punct(target_names[i]); - bool found=false; - for(int j=0;j<sizeof(world)/sizeof(struct location_t);++j) - { - if(strcmp(world[j].name, target_names[i])==0) - { - found=true; - if(world[j].owner!=side) - { - targets[num_targets_found]=&world[j]; - ++num_targets_found; - } - else - { - print_string("\n\nATTEMPTING TO FIRE AT OWN CITY.\nPLEASE CONFIRM (YES OR NO): "); - char response[17]; - getnstr(response, 16); - allLower(response); - remove_punct(response); - if(strcmp(response, "yes")==0 || strcmp(response, "y")==0) - { + { + ++num_targets; + allLower(target_names[i]); + remove_punct(target_names[i]); + bool found=false; + for(int j=0;j<sizeof(world)/sizeof(struct location_t);++j) + { + if(strcmp(world[j].name, target_names[i])==0) + { + found=true; + if(world[j].owner!=side) + { + targets[num_targets_found]=&world[j]; + ++num_targets_found; + } + else + { + print_string("\n\nATTEMPTING TO FIRE AT OWN CITY.\nPLEASE CONFIRM (YES OR NO): "); + char response[17]; + getnstr(response, 16); + allLower(response); + remove_punct(response); + if(strcmp(response, "yes")==0 || strcmp(response, "y")==0) + { print_string("\n\nATTEMPTING TO FIRE AT OWN CITY.\nARE YOU SURE (YES OR NO): "); response[0]=0; getnstr(response, 16); allLower(response); remove_punct(response); if(strcmp(response, "yes")==0 || strcmp(response, "y")==0) - { + { print_string("\nTARGET CONFIRMED.\n\n"); targets[num_targets_found]=&world[j]; ++num_targets_found; } - } - } - } - } - if(!found) - { - print_string("TARGET NOT FOUND: "); - print_string(target_names[i]); - print_string("\n"); - } - } + } + } + } + } + if(!found) + { + print_string("TARGET NOT FOUND: "); + print_string(target_names[i]); + print_string("\n"); + } + } } for(int i=0;i<num_targets_found;++i) { @@ -236,17 +234,14 @@ static void do_first_strike(int side) static void do_missile_launch(int side) { print_string("\n\n"); - attr_on(WA_UNDERLINE, 0); print_string("AWAITING STRIKE COMMAND"); - attr_off(WA_UNDERLINE, 0); print_string("\n\n\nPLEASE LIST PRIMARY TARGETS BY\nCITY AND/OR COUNTY NAME:\n\n"); char target_names[32][129]; bool good=true; int num_targets=0; struct location_t *targets[32]; int num_targets_found=0; - int max_targets=side==USA?4:6; - for(int i=0;num_targets_found<max_targets && good;++i) + for(int i=0;num_targets_found<6 && good;++i) { getnstr(target_names[i], 128); if(strcmp(target_names[i],"")==0) @@ -254,52 +249,52 @@ static void do_missile_launch(int side) good=false; } else - { - ++num_targets; - allLower(target_names[i]); - remove_punct(target_names[i]); - bool found=false; - for(int j=0;j<sizeof(world)/sizeof(struct location_t);++j) - { - if(strcmp(world[j].name, target_names[i])==0) - { - found=true; - if(world[j].owner!=side) - { - targets[num_targets_found]=&world[j]; - ++num_targets_found; - } - else - { - print_string("\n\nATTEMPTING TO FIRE AT OWN CITY.\nPLEASE CONFIRM (YES OR NO): "); - char response[17]; - getnstr(response, 16); - allLower(response); - remove_punct(response); - if(strcmp(response, "yes")==0 || strcmp(response, "y")==0) - { + { + ++num_targets; + allLower(target_names[i]); + remove_punct(target_names[i]); + bool found=false; + for(int j=0;j<sizeof(world)/sizeof(struct location_t);++j) + { + if(strcmp(world[j].name, target_names[i])==0) + { + found=true; + if(world[j].owner!=side) + { + targets[num_targets_found]=&world[j]; + ++num_targets_found; + } + else + { + print_string("\n\nATTEMPTING TO FIRE AT OWN CITY.\nPLEASE CONFIRM (YES OR NO): "); + char response[17]; + getnstr(response, 16); + allLower(response); + remove_punct(response); + if(strcmp(response, "yes")==0 || strcmp(response, "y")==0) + { print_string("\n\nATTEMPTING TO FIRE AT OWN CITY.\nARE YOU SURE (YES OR NO): "); response[0]=0; getnstr(response, 16); allLower(response); remove_punct(response); if(strcmp(response, "yes")==0 || strcmp(response, "y")==0) - { + { print_string("\nTARGET CONFIRMED.\n\n"); targets[num_targets_found]=&world[j]; ++num_targets_found; } - } - } - } - } - if(!found) - { - print_string("TARGET NOT FOUND: "); - print_string(target_names[i]); - print_string("\n"); - } - } + } + } + } + } + if(!found) + { + print_string("TARGET NOT FOUND: "); + print_string(target_names[i]); + print_string("\n"); + } + } } for(int i=0;i<num_targets_found;++i) { @@ -332,7 +327,9 @@ static void do_human_move(int side) while(!good) { print_string("PLEASE CHOOSE ONE: "); - scanw("%u", &move); + char buf[32]; + getnstr(buf, 32); + sscanf(buf, "%u", &move); if(move>0 && move<5) good=true; } @@ -369,7 +366,7 @@ void global_thermonuclear_war(void) print_string(map[i]); print_string("\n"); } - + /* get the side the user wants to be on */ print_string("\nWHICH SIDE DO YOU WANT?\n\n 1. UNITED STATES\n 2. SOVIET UNION\n\n"); bool good=false; @@ -377,7 +374,9 @@ void global_thermonuclear_war(void) while(!good) { print_string("PLEASE CHOOSE ONE: "); - scanw("%u", &side); + char buf[32]; + getnstr(buf, 31); + sscanf(buf, "%u", &side); if(side==1 || side==2) good=true; } @@ -14,7 +14,7 @@ * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. - * + * * Contact the author at contact@fwei.tk */ @@ -23,16 +23,15 @@ #include "strings.h" /* predefined strings */ #include "util.h" -#include <curses.h> #include <signal.h> +#include <stdbool.h> #include <stdlib.h> #include <string.h> #include <unistd.h> void cleanup(int signum) { - endwin(); - exit(0); + exit(EXIT_SUCCESS); } void random_stuff(void) /* print random junk on the screen for about 3 seconds */ { @@ -45,24 +44,19 @@ void random_stuff(void) /* print random junk on the screen for about 3 seconds * usleep(100000); clear(); } -void be_joshua() +void be_joshua(int fd) { - initscr(); + printf("joshua started.\n"); + out_fd=fd; clear(); signal(SIGINT, &cleanup); /* start_color(); init_pair(1, COLOR_BLUE, COLOR_BLACK); attron(COLOR_PAIR(1));*/ - scrollok(stdscr, true); bool gamesPhase=false; char buf[33]; - int maxx, maxy; - getmaxyx(stdscr, maxy, maxx); - for(int i=0;i<maxx*2;++i) - { - print_string(" "); - } + print_string("\n\n"); do { if(!gamesPhase) print_string("LOGON: "); @@ -99,16 +93,14 @@ void be_joshua() for(int i=0;i<sizeof(exit_triggers)/sizeof(const char*);++i) { if(strcmp(buf, exit_triggers[i])==0) - { - print_string("\n\n"); - print_string(exit_responses[rand()%sizeof(exit_responses)/sizeof(const char*)]); - print_string("\n--CONNECTION TERMINATED--"); - return; - } + { + print_string("\n\n"); + print_string(exit_responses[rand()%sizeof(exit_responses)/sizeof(const char*)]); + print_string("\n--CONNECTION TERMINATED--"); + return; + } } print_string("\n\nHOW ARE YOU FEELING TODAY?\n\n"); refresh(); do_chatbot(); - endwin(); } - @@ -14,14 +14,14 @@ * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. - * + * * Contact the author at contact@fwei.tk */ #ifdef __cplusplus extern "C" { #endif -void be_joshua(); +void be_joshua(int); #ifdef __cplusplus }; #endif diff --git a/main.cpp b/main.cpp deleted file mode 100644 index 4c102a2..0000000 --- a/main.cpp +++ /dev/null @@ -1,31 +0,0 @@ -/* - * WarGames - a WOPR emulator written in C - * Copyright (C) 2014 Franklin Wei - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - * - * Contact the author at contact@fwei.tk - */ - -#include "joshua.h" - -#include <curses.h> -#include <iostream> - -using namespace std; -int main() -{ - be_joshua(); - endwin(); -} diff --git a/server.c b/server.c new file mode 100644 index 0000000..fe8b6f8 --- /dev/null +++ b/server.c @@ -0,0 +1,131 @@ +#include <sys/types.h> +#include <sys/socket.h> +#include <unistd.h> +#include <errno.h> +#include <netinet/in.h> +#include <netdb.h> +#include <string.h> +#include <stdlib.h> +#include <stdio.h> +#include <signal.h> +#include "joshua.h" +#define PORT 1029 +int server_socket; +int pipes[FD_SETSIZE][2]; +int make_server_socket(uint16_t port) +{ + int sock; + struct sockaddr_in name; + sock=socket(AF_INET, SOCK_STREAM, 0); + if(sock<0) + { + printf("error creating socket.\n"); + return -1; + } + name.sin_family=AF_INET; + name.sin_port=htons(port); + name.sin_addr.s_addr=htonl(INADDR_ANY); + int ret=bind(sock, (struct sockaddr*) &name, sizeof(name)); + if(ret<0) + { + printf("error binding to port %d\n", port); + return -1; + } + return sock; +} +int process_data(int fd) +{ + char buf[1024]; + memset(buf, 0, sizeof(buf)); + int ret=read(fd, buf, sizeof(buf)); + if(ret<0) /* error */ + { + printf("error in read()\n"); + return -1; + } + if(ret==0) + { + printf("EOF from client\n"); + return -1; + } + else + { + write(pipes[fd][1], buf, strlen(buf)); + } +} +void serv_cleanup() +{ + printf("preparing to exit...\n"); + fflush(stdout); + close(server_socket); +} +int main(int argc, char* argv[]) +{ + printf("starting server...\n"); + signal(SIGINT, &serv_cleanup); + int sock=make_server_socket(PORT); + server_socket=sock; + fd_set active_fd_set, read_fd_set; + struct sockaddr_in client; + if(listen(sock, 1)<0) + { + printf("error listening.\n"); + return 1; + } + FD_ZERO(&active_fd_set); + FD_SET(sock, &active_fd_set); + printf("listening on port %d\n", PORT); + while(1) + { + read_fd_set=active_fd_set; + int ret=select(FD_SETSIZE, &read_fd_set, 0,0,0); + if(ret<0) + { + printf("select() returned error.\n"); + return 1; + } + for(int i=0;i<FD_SETSIZE;++i) + { + if(FD_ISSET(i, &read_fd_set)) + { + if(i==sock) + { + /* new connection */ + int new, size; + size=sizeof(client); + new=accept(sock, (struct sockaddr*) &client, &size); + if(new<0) + { + printf("error accepting connection.\n"); + return 1; + } + printf("new connection.\n"); + FD_SET(new, &active_fd_set); + int ret=pipe(pipes[i]); + if(ret<0) + { + printf("pipe error.\n"); + } + pid_t pid=fork(); + if(pid==0) /* child */ + { + printf("child.\n"); + be_joshua(new); + close(new); + FD_CLR(new, &active_fd_set); + exit(0); + } + } + else + { + /* data from existing connection */ + if(process_data(i)<0) + { + close(i); + FD_CLR(i, &active_fd_set); + } + } + } + } + } +} @@ -14,18 +14,18 @@ * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. - * + * * Contact the author at contact@fwei.tk */ #include "strings.h" #include "util.h" #include <ctype.h> -#include <curses.h> #include <string.h> #include <unistd.h> - - +#include <stdlib.h> +int out_fd; +extern int pipes[FD_SETSIZE][2]; void allLower(char* str) { for(int i=0;str[i];++i) @@ -35,21 +35,11 @@ void allLower(char* str) } void print_string(const char* str) /* print string, slowly */ { - int window_height; - int junk; - getmaxyx(stdscr, window_height, junk); int i=0; while(str[i]) { - addch(str[i]); - int cursx, cursy; - getyx(stdscr, cursy, cursx); - if(cursy==window_height) - { - scroll(stdscr); - } - usleep(SLEEP_TIME); - refresh(); + write(out_fd, &str[i], 1); + fsync(out_fd); ++i; } } @@ -66,4 +56,28 @@ void remove_punct(char* buf) } } } +void clear(void) +{ +} +void refresh(void) +{ + fsync(out_fd); +} +int getnstr(char* buf, int max) +{ + printf("reading...\n"); + memset(buf, 0, sizeof(buf)); + int back=0; + char c=0; + do { + read(pipes[out_fd][0], &c, 1); + if(c!='\n') + { + buf[back]=c; + ++back; + } + } + while(back<max && c!='\n'); + return OK; +} @@ -22,3 +22,9 @@ void allLower(char*); void print_string(const char*); void remove_punct(char*); +void refresh(void); +void clear(void); +int getnstr(char*, int); +#define ERR 1 +#define OK 0 +extern int out_fd; |