aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore6
-rw-r--r--COPYING2
-rw-r--r--GAMESPEC45
-rw-r--r--INPUT9
-rw-r--r--MAP22
-rw-r--r--Makefile8
-rw-r--r--README.md6
-rw-r--r--TRANSCRIPT57
-rw-r--r--chatbot.c128
-rw-r--r--chatbot.h21
-rw-r--r--gtnw.c426
-rw-r--r--gtnw.h21
-rw-r--r--joshua.c106
-rw-r--r--joshua.h27
-rw-r--r--location.h51
-rw-r--r--map.h40
-rw-r--r--server.c159
-rw-r--r--strings.c97
-rw-r--r--strings.h33
-rw-r--r--util.c81
-rw-r--r--util.h30
21 files changed, 1372 insertions, 3 deletions
diff --git a/.gitignore b/.gitignore
index 4d40434..7c7be4f 100644
--- a/.gitignore
+++ b/.gitignore
@@ -4,6 +4,11 @@
*.obj
*.elf
+# Junk files
+a.out
+wargames
+*~
+
# Libraries
*.lib
*.a
@@ -21,3 +26,4 @@
*.i*86
*.x86_64
*.hex
+>>>>>>> 242a6e2d8edd375da6b02d7e2ece1b41d0f8de54
diff --git a/COPYING b/COPYING
new file mode 100644
index 0000000..5d2b5cd
--- /dev/null
+++ b/COPYING
@@ -0,0 +1,2 @@
+Most of the files are licensed under the GNU GPL version 3 or (at your option), any later version: <http://www.gnu.org/licenses/gpl.html>
+MAP and map.h are licensed under the Creative Commons Attribution-Sharealike 4.0 International License: <http://creativecommons.org/licenses/by-sa/4.0/> \ No newline at end of file
diff --git a/GAMESPEC b/GAMESPEC
new file mode 100644
index 0000000..638a131
--- /dev/null
+++ b/GAMESPEC
@@ -0,0 +1,45 @@
+This file contains a formal definition of Global Thermonuclear War.
+=======GAMEPLAY========
+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:
+ - Launch ICBMs
+ - Negociate peace terms
+ - Surrender
+
+The behavior of each of these options is described below.
+
+ICBM launch:
+ - 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
+ - Minor: 40%+2500 casualties
+ - Major: 60%+5000 casualties
+ - Critical: 100% casualties
+ - The probabilities of each of these options is outlined below:
+ - Miss - 10%
+ - Marginal - 20%
+ - Minor - 30%
+ - Major - 30%
+ - Critical - 10%
+ - After the turn, the cities targeted will have one of these symbols in it:
+ - Miss - O
+ - Marginal - x
+ - Minor - *
+ - Major - X
+ - Critical - !
+
+Negociation:
+ - There are three possible outcomes:
+ - Peace/Progress - 20%
+ - Surprise attack - 20%
+ - No progress - 60%
+ - Progress must be made at least 5 times if peace is to be achieved
+
+Surrender:
+ - The other player wins
+
+=======GRAPHICS=======
+Each turn, a map is displayed with the populations of the player's cities in a table below.
diff --git a/INPUT b/INPUT
new file mode 100644
index 0000000..e4a2f00
--- /dev/null
+++ b/INPUT
@@ -0,0 +1,9 @@
+Joshua
+Hello.
+I'm fine. How are you?
+People sometimes make mistakes.
+Love to. How about Global Thermonuclear War?
+Later. Let's play Global Thermonuclear War.
+2
+Las Vegas
+Seattle
diff --git a/MAP b/MAP
new file mode 100644
index 0000000..888a98d
--- /dev/null
+++ b/MAP
@@ -0,0 +1,22 @@
+/*
+ * This file is licensed under the Creative Commons Attribution-ShareAlike 4.0 International License.
+ * To view a copy of this license, visit http://creativecommons.org/licenses/by-sa/4.0/.
+ *
+ * Attribution should be given to Franklin Wei.
+ */
+
+ .
+ __________--^-^-\. ____ __----/^\.
+|\/. \__. ___/ || ___/ _/._-_ .
+| \. /. /. __ __/ /__/ \/^^\___-__.
+| L-^-/. /. \.\_-- \.
+| / _/ _/\/.
+|. | _/. __ __/
+ \. /. / ___/.//
+ \__ / | / \/.
+ \________ __ _____.\. \_. ____--_ /\_ \
+ \__. / V. \ \ \__ _/. \_/ //
+ \ /. \/. \. _/. //
+ \_/. \_/
+
+ UNITED STATES SOVIET UNION
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..c24d8a6
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,8 @@
+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
+CFLAGS=-std=gnu99 -g -O3
+wargames: $(SOURCES) $(HEADERS)
+ g++ $(SOURCES) $(CXXFLAGS) -o wargames
+all: wargames Makefile
+clean:
+ rm -f $(SOURCES) a.out wargames *~
diff --git a/README.md b/README.md
index 9e9fbcf..eb6d4a9 100644
--- a/README.md
+++ b/README.md
@@ -1,4 +1,4 @@
-wargames-server
-===============
+WarGames
+========
-Want to run the WOPR over telnet? This server does just that!
+Ever wanted your very own WOPR? This is what you're looking for!
diff --git a/TRANSCRIPT b/TRANSCRIPT
new file mode 100644
index 0000000..9a6d843
--- /dev/null
+++ b/TRANSCRIPT
@@ -0,0 +1,57 @@
+<<<<< This is my transcript of the scene in WarGames (1983) where David has dialed into the WOPR and started playing Global Thermonuclear War. >>>>>
+<<<<< All spaces, newlines, punctuation, etc. and made to be as accurate as possible >>>>>
+LOGON: Joshua
+<Random stuff>
+<CLEAR>
+GREETINGS PROFESSOR FALKEN.
+
+Hello.
+
+
+HOW ARE YOU FEELING TODAY?
+
+I'm fine. How are you?
+
+
+EXCELLENT. IT'S BEEN A LONG TIME. CAN YOU EXPLAIN
+THE REMOVAL OF YOUR USER ACCOUNT ON 6/23/73?
+
+People sometimes make mistakes. (NOTE: in one scene, it appears that he typed "mistak" instead of "mistakes.")
+
+
+YES THEY DO. SHALL WE PLAY A GAME?
+
+Love to. How about Global Thermonuclear War?
+
+
+WOULDN'T YOU PREFER A GOOD GAME OF CHESS?
+
+Later. Let's play Global Thermonuclear War.
+
+FINE.
+<CLEAR>
+<US + USSR ASCII ART>
+
+UNITED STATES SOVIET UNION
+
+WHICH SIDE DO YOU WANT?
+
+ 1. UNITED STATES
+ 2. SOVIET UNION
+
+PLEASE CHOOSE ONE: 2
+<CLEAR>
+AWAITING FIRST STRIKE COMMAND (UNDERLINED)
+
+
+PLEASE LIST PRIMARY TARGETS BY
+CITY AND/OR COUNTY NAME:
+
+Las Vegas
+Seattle
+
+<CLEAR>
+
+<ASCII ART OF US + USSR>
+<US HAS TRAJECTORY HEADINGS OF ICBMS BOUND FOR LAS VEGAS AND SEATTLE>
+<SUBS REPRESENTED BY BLINKING DOTS ARE OFF US SHORELINES> \ No newline at end of file
diff --git a/chatbot.c b/chatbot.c
new file mode 100644
index 0000000..27bbdca
--- /dev/null
+++ b/chatbot.c
@@ -0,0 +1,128 @@
+/*
+ * 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 "gtnw.h"
+#include "strings.h"
+#include "util.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 ->
+ stage 4: GLOBAL THERMONUCLEAR WAR!!! */
+ while(1)
+ {
+ char buf[513];
+ int ret=getnstr(buf, 512);
+ usleep(SLEEP_TIME*100);
+ if(ret==ERR)
+ {
+ print_string("\n\n");
+ print_string("SORRY?");
+ print_string("\n\n");
+ }
+ else
+ {
+ allLower(buf);
+ remove_punct(buf);
+ bool valid=false;
+ switch(stage)
+ {
+ case 0:
+ for(int i=0;i<sizeof(stage1_triggers)/sizeof(const char*);++i)
+ {
+ if(strcmp(buf, stage1_triggers[i])==0)
+ {
+ print_string("\n\nEXCELLENT. IT'S BEEN A LONG TIME. CAN YOU EXPLAIN\nTHE REMOVAL OF YOUR USER ACCOUNT ON 6/23/73?\n\n");
+ ++stage;
+ valid=true;
+ }
+ }
+ break;
+ case 1:
+ for(int i=0;i<sizeof(stage2_triggers)/sizeof(const char*);++i)
+ {
+ if(strcmp(buf, stage2_triggers[i])==0)
+ {
+ print_string("\n\nYES THEY DO. SHALL WE PLAY A GAME?\n\n");
+ ++stage;
+ valid=true;
+ }
+ }
+ 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;
+ case 3:
+ for(int i=0;i<sizeof(stage4_triggers)/sizeof(const char*);++i)
+ {
+ if(strcmp(buf, stage4_triggers[i])==0)
+ {
+ print_string("\n\nFINE.\n\n");
+ valid=true;
+ usleep(SLEEP_TIME*100);
+ global_thermonuclear_war();
+ }
+ }
+ 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;
+ }
+ }
+ if(!valid)
+ {
+ print_string("\n\n");
+ print_string("SORRY?");
+ print_string("\n\n");
+ }
+ } // else
+ } // while
+}
diff --git a/chatbot.h b/chatbot.h
new file mode 100644
index 0000000..9b435d5
--- /dev/null
+++ b/chatbot.h
@@ -0,0 +1,21 @@
+/*
+ * 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
+ */
+
+void do_chatbot(void);
diff --git a/gtnw.c b/gtnw.c
new file mode 100644
index 0000000..c5c02d0
--- /dev/null
+++ b/gtnw.c
@@ -0,0 +1,426 @@
+/*
+ * 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 "gtnw.h"
+#include "location.h"
+#include "map.h"
+#include "util.h"
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <time.h>
+#include <unistd.h>
+
+static bool surrender=false;
+static int winner=0; /* on surrender */
+
+static unsigned int max(long long a, long long b)
+{
+ return a>b?a:b;
+}
+
+/* simulate a missile launch */
+static void fire_missile(struct location_t* city)
+{
+ int random=rand()%100; /* leave this at 100 for future adjustments */
+ int x=city->x, y=city->y;
+ if(random>=90) /* crit */
+ {
+ map[y][x]='!';
+ city->population=0;
+ }
+ else if(random>=60) /* major */
+ {
+ map[y][x]='X';
+ city->population=max((double)city->population*(double).4-5000, 0);
+ }
+ else if(random>=30) /* minor */
+ {
+ map[y][x]='*';
+ city->population=max((double)city->population*(double).6-2500, 0);
+ }
+ else if(random>=10) /* marginal */
+ {
+ map[y][x]='x';
+ city->population=max((double)city->population*(double).8-1000, 0);
+ }
+ else /* miss */
+ {
+ map[y][x]='O';
+ }
+}
+
+/* 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;
+ else
+ *us_pop+=world[i].population;
+ }
+}
+
+/* print the map and populations of the cities underneath */
+static void print_map_with_pops(void)
+{
+ for(int i=0;i<sizeof(map)/sizeof(char*);++i)
+ {
+ print_string(map[i]);
+ print_string("\n");
+ }
+ long long us_pop=0, ussr_pop=0;
+ calc_pops(&us_pop, &ussr_pop);
+ /* now sort into US and USSR cities */
+ struct location_t us_cities[sizeof(world)/sizeof(struct location_t)+1], ussr_cities[sizeof(world)/sizeof(struct location_t)+1];
+ int us_back=0, ussr_back=0;
+ 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;
+ }
+ else
+ {
+ 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;
+ }
+ }
+ else if(us_back>ussr_back)
+ {
+ while(us_back!=ussr_back)
+ {
+ ussr_cities[ussr_back].print=false;
+ ++ussr_back;
+ }
+ }
+ us_cities[us_back].print=true;
+ us_cities[us_back].print_name="Total";
+ us_cities[us_back].population=us_pop;
+ ussr_cities[ussr_back].print=true;
+ ussr_cities[ussr_back].print_name="Total";
+ ussr_cities[ussr_back].population=ussr_pop;
+ ++us_back;
+ ++ussr_back;
+ print_string("\n\n");
+ char buf[512];
+ 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);
+ }
+ else if(us_cities[i].print && !ussr_cities[i].print)
+ 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);
+ }
+ print_string(buf);
+ print_string("\n");
+ }
+}
+
+/* prompt the user for targets for the initial strike */
+static void do_first_strike(int side)
+{
+ print_string("AWAITING FIRST STRIKE COMMAND");
+ 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?6:7;
+ for(int i=0;num_targets_found<max_targets && good;++i)
+ {
+ getnstr(target_names[i], 128);
+ if(strcmp(target_names[i],"")==0)
+ {
+ 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)
+ {
+ 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");
+ }
+ }
+ }
+ for(int i=0;i<num_targets_found;++i)
+ {
+ fire_missile(targets[i]);
+ }
+ clear();
+ print_map_with_pops();
+}
+
+/* essentially the same as do_first_strike */
+/** TODO: refactor into do_first_strike (or vice-versa) **/
+static void do_missile_launch(int side)
+{
+ print_string("\n\n");
+ print_string("AWAITING STRIKE COMMAND");
+ 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;
+ for(int i=0;num_targets_found<6 && good;++i)
+ {
+ getnstr(target_names[i], 128);
+ if(strcmp(target_names[i],"")==0)
+ {
+ 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)
+ {
+ 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");
+ }
+ }
+ }
+ for(int i=0;i<num_targets_found;++i)
+ {
+ fire_missile(targets[i]);
+ }
+ clear();
+ print_map_with_pops();
+}
+enum ai_strategy_t { AGGRESSIVE, PASSIVE, PEACEFUL };
+static void init_ai(int side)
+{
+ /* nothing for now */
+ /** TODO: decide strategy? **/
+}
+static void do_ai_move(int side)
+{
+ /* nothing yet :( */
+}
+static void do_peace_talks(int side)
+{
+ /** TODO: IMPLEMENT!!! **/
+}
+
+/* prompt the player for their move */
+static void do_human_move(int side)
+{
+ bool good=false;
+ print_string("\nWHAT ACTION DO YOU WISH TO TAKE?\n\n 1. MISSILE LAUNCH\n 2. PEACE TALKS\n 3. SURRENDER\n 4. NOTHING\n\n");
+ int move=0;
+ while(!good)
+ {
+ print_string("PLEASE CHOOSE ONE: ");
+ char buf[32];
+ getnstr(buf, 32);
+ sscanf(buf, "%u", &move);
+ if(move>0 && move<5)
+ good=true;
+ }
+ switch(move)
+ {
+ case 1:
+ do_missile_launch(side);
+ break;
+ case 2:
+ do_peace_talks(side);
+ break;
+ case 3:
+ surrender=true;
+ winner=side==1?2:1;
+ break;
+ case 4:
+ break;
+ }
+}
+
+/* play a game of Global Thermonuclear War! */
+void global_thermonuclear_war(void)
+{
+ srand(time(0)); // might want to move to main()...
+ surrender=false;
+ clear();
+ for(int i=0;i<sizeof(const_map)/sizeof(const char*);++i)
+ {
+ strcpy(map[i], const_map[i]);
+ }
+ /* print the map */
+ for(int i=0;i<sizeof(map)/sizeof(const char*);++i)
+ {
+ 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;
+ unsigned int side=0;
+ while(!good)
+ {
+ print_string("PLEASE CHOOSE ONE: ");
+ char buf[32];
+ getnstr(buf, 31);
+ sscanf(buf, "%u", &side);
+ if(side==1 || side==2)
+ good=true;
+ }
+ clear();
+ do_first_strike(side);
+ long long us_pop=0, ussr_pop;
+ calc_pops(&us_pop, &ussr_pop);
+ init_ai(side);
+ while(us_pop!=0 && ussr_pop!=0 && !surrender)
+ {
+ do_human_move(side);
+ calc_pops(&us_pop, &ussr_pop);
+ if(us_pop!=0 && ussr_pop!=0 && !surrender)
+ {
+ do_ai_move(side);
+ calc_pops(&us_pop, &ussr_pop);
+ }
+ }
+ print_string("\n\n");
+ if(!surrender)
+ {
+ if(us_pop==0 && ussr_pop==0)
+ {
+ print_string("WINNER: NONE\n\n");
+ }
+ else if(us_pop==0)
+ {
+ print_string("WINNER: SOVIET UNION\n\n");
+ }
+ else if(ussr_pop==0)
+ {
+ print_string("WINNER: UNITED STATES\n\n");
+ }
+ }
+ else
+ {
+ switch(winner)
+ {
+ case 1:
+ print_string("WINNER: UNITED STATES\n\n");
+ break;
+ case 2:
+ print_string("WINNER: SOVIET UNION\n\n");
+ break;
+ }
+ }
+}
diff --git a/gtnw.h b/gtnw.h
new file mode 100644
index 0000000..1c49e93
--- /dev/null
+++ b/gtnw.h
@@ -0,0 +1,21 @@
+/*
+ * 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
+ */
+
+void global_thermonuclear_war(void);
diff --git a/joshua.c b/joshua.c
new file mode 100644
index 0000000..9520ed5
--- /dev/null
+++ b/joshua.c
@@ -0,0 +1,106 @@
+/*
+ * 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 "chatbot.h"
+#include "joshua.h"
+#include "strings.h" /* predefined strings */
+#include "util.h"
+
+#include <signal.h>
+#include <stdbool.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+void cleanup(int signum)
+{
+ exit(EXIT_SUCCESS);
+}
+void random_stuff(void) /* print random junk on the screen for about 3 seconds */
+{
+ clear();
+ /* credit for this text goes to David Brownlee and Chirs Carter */
+ print_string("#45 11456 11009 11893 11972 11315\nPRT CON. 3.4.5. SECTRAN 9.4.3. PORT STAT: SD-345\n\n(311) 699-7305\n");
+ clear();
+ print_string("\n\n\n\n\n\n\n");
+ print_string("(311) 767-8739\n(311) 936-2364\n- PRT. STAT. CRT. DEF.\n||||||||||||||==================================================\nFSKDJLSD: SDSDKJ: SBFJSL: DKSJL: SKFJJ: SDKFJLJ:\nSYSPROC FUNCT READY ALT NET READY\nCPU AUTH RY-345-AX3 SYSCOMP STATUS ALL PORTS ACTIVE\n22/34534.90/3209 11CVB-3904-3490\n(311) 935-2364\n");
+ usleep(100000);
+ clear();
+}
+void be_joshua(int fd)
+{
+ printf("joshua started.\n");
+ out_fd=fd;
+ clear();
+ signal(SIGINT, &cleanup);
+ /*
+ start_color();
+ init_pair(1, COLOR_BLUE, COLOR_BLACK);
+ attron(COLOR_PAIR(1));*/
+ bool gamesPhase=false;
+ char buf[33];
+ print_string("\n\n");
+ do {
+ if(!gamesPhase)
+ print_string("LOGON: ");
+ refresh();
+ int ret=getnstr(buf, 32);
+ allLower(buf);
+ usleep(SLEEP_TIME*100);
+ if(strcmp(buf, "help logon")==0 && !gamesPhase)
+ {
+ print_string("\nHELP NOT AVAILABLE\n\n\n");
+ }
+ else if(strcmp(buf, "help games")==0)
+ {
+ print_string("\n'GAMES' REFERS TO MODELS, SIMULATIONS AND GAMES\nWHICH HAVE TACTICAL AND STRATEGIC APPLICATIONS.\n\n\n");
+ gamesPhase=true;
+ }
+ else if(strcmp(buf, "list games")==0 && gamesPhase)
+ {
+ print_string("\nFALKEN'S MAZE\nBLACK JACK\nGIN RUMMY\nHEARTS\nBRIDGE\nCHECKERS\nCHESS\nPOKER\nFIGHTER COMBAT\nGUERRILLA ENGAGEMENT\nDESERT WARFARE\nAIR-TO-GROUND ACTIONS\nTHEATERWIDE TACTICAL WARFARE\nTHEATERWIDE BIOTOXIC AND CHEMICAL WARFARE\n\nGLOBAL THERMONUCLEAR WAR\n\n\n");
+ }
+ else if(ret==ERR || strcmp(buf, "joshua") && !gamesPhase)
+ {
+ print_string("\nIDENTIFICATION NOT RECOGNIZED BY SYSTEM\n--CONNECTION TERMINATED--");
+ return;
+ }
+ } while(strcmp(buf, "joshua") || gamesPhase);
+ random_stuff();
+ usleep(SLEEP_TIME*100);
+ print_string("GREETINGS, PROFESSOR FALKEN.\n\n");
+ refresh();
+ getnstr(buf, 32);
+ allLower(buf);
+ remove_punct(buf);
+ 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\nHOW ARE YOU FEELING TODAY?\n\n");
+ refresh();
+ do_chatbot();
+}
diff --git a/joshua.h b/joshua.h
new file mode 100644
index 0000000..d085eb0
--- /dev/null
+++ b/joshua.h
@@ -0,0 +1,27 @@
+/*
+ * 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
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+void be_joshua(int);
+#ifdef __cplusplus
+};
+#endif
diff --git a/location.h b/location.h
new file mode 100644
index 0000000..3a85ada
--- /dev/null
+++ b/location.h
@@ -0,0 +1,51 @@
+/*
+ * 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 <stdbool.h>
+/* provide the GTNW with some geographical data to draw the missiles with */
+enum player_t { USA=1, USSR };
+struct location_t {
+ const char* name;
+ int x;
+ int y; /* x,y-coords on the map */
+ long long population; /* around 1980 */
+ enum player_t owner;
+ bool print;
+ const char* print_name;
+};
+struct location_t world[]={
+ /* US cities */
+ {"las vegas", 5, 7, 150000, USA, true, "LAS VEGAS"},
+ {"seattle", 3, 2, 500000, USA, true, "SEATTLE"},
+ {"new york", 34, 5, 7000000, USA, true, "NEW YORK CITY"},
+ {"new orleans", 25, 10, 500000, USA, true, "NEW ORLEANS"},
+ {"washington dc", 33, 6, 650000, USA, true, "WASHINGTON, DC"},
+ {"winston-salem", 30, 7, 150000, USA, true, "WINSTON-SALEM"},
+ {"san francisco", 1, 6, 700000, USA, true, "SAN FRANCISCO"},
+ {"chicago", 24, 4, 3000000, USA, true, "CHICAGO"},
+ {"miami", 33, 11, 1000000, USA, true, "MIAMI"},
+
+ /* Soviet cities */
+ /* NOTE: These cities are not accurate! */
+ {"murmansk", 74, 1, 500000, USSR, true,"MURMANSK"},
+ {"moscow", 70, 5, 8000000, USSR, true, "MOSCOW"},
+ {"minsk", 66, 4, 1500000, USSR, true, "MINSK"},
+ {"chelyabinsk", 64, 8, 1250000, USSR, true, "CHELYABINSK"}
+};
diff --git a/map.h b/map.h
new file mode 100644
index 0000000..5b80c67
--- /dev/null
+++ b/map.h
@@ -0,0 +1,40 @@
+/*
+ * This file is licensed under the Creative Commons Attribution-ShareAlike 4.0 International License.
+ * To view a copy of this license, visit http://creativecommons.org/licenses/by-sa/4.0/.
+ *
+ * Attribution should be given to Franklin Wei.
+ */
+char *map[] = {
+ /* 0 */ (char[]){" ."},
+ /* 1 */ (char[]){" __________--^-^-\\. ____ __----/^\\."},
+ /* 2 */ (char[]){"|\\/. \\__. ___/ || ___/ _/._-_ ."},
+ /* 3 */ (char[]){"| \\. /. /. __ __/ /__/ \\/^^\\___-__."},
+ /* 4 */ (char[]){"| L-^-/. /. \\.\\_-- \\."},
+ /* 5 */ (char[]){"| / _/ _/\\/."},
+ /* 6 */ (char[]){"|. | _/. __ __/"},
+ /* 7 */ (char[]){" \\. /. / ___/.//"},
+ /* 8 */ (char[]){" \\__ / | / \\/."},
+ /* 9 */ (char[]){" \\________ __ _____.\\. \\_. ____--_ /\\_ \\"},
+ /* 10 */ (char[]){" \\__. / V. \\ \\ \\__ _/. \\_/ //"},
+ /* 11 */ (char[]){" \\ /. \\/. \\. _/. //"},
+ /* 12 */ (char[]){" \\_/. \\_/"},
+ /* 13 */ (char[]){""},
+ /* 14 */ (char[]){" UNITED STATES SOVIET UNION"}
+};
+const char *const_map[] = {
+ /* 0 */ (char[]){" ."},
+ /* 1 */ (char[]){" __________--^-^-\\. ____ __----/^\\."},
+ /* 2 */ (char[]){"|\\/. \\__. ___/ || ___/ _/._-_ ."},
+ /* 3 */ (char[]){"| \\. /. /. __ __/ /__/ \\/^^\\___-__."},
+ /* 4 */ (char[]){"| L-^-/. /. \\.\\_-- \\."},
+ /* 5 */ (char[]){"| / _/ _/\\/."},
+ /* 6 */ (char[]){"|. | _/. __ __/"},
+ /* 7 */ (char[]){" \\. /. / ___/.//"},
+ /* 8 */ (char[]){" \\__ / | / \\/."},
+ /* 9 */ (char[]){" \\________ __ _____.\\. \\_. ____--_ /\\_ \\"},
+ /* 10 */ (char[]){" \\__. / V. \\ \\ \\__ _/. \\_/ //"},
+ /* 11 */ (char[]){" \\ /. \\/. \\. _/. //"},
+ /* 12 */ (char[]){" \\_/. \\_/"},
+ /* 13 */ (char[]){""},
+ /* 14 */ (char[]){" UNITED STATES SOVIET UNION"}
+};
diff --git a/server.c b/server.c
new file mode 100644
index 0000000..568c5e6
--- /dev/null
+++ b/server.c
@@ -0,0 +1,159 @@
+x/*
+ * 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 <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"
+int server_socket;
+uint16_t port;
+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
+ {
+ printf("Client sends: %s\n", buf);
+ write(pipes[fd][1], buf, strlen(buf));
+ return 0;
+ }
+}
+void serv_cleanup()
+{
+ printf("preparing to exit...\n");
+ fflush(stdout);
+ shutdown(server_socket, SHUT_RDWR);
+ close(server_socket);
+}
+int main(int argc, char* argv[])
+{
+ if(argc!=2)
+ {
+ printf("Usage: %s PORT\n", argv[0]);
+ return 2;
+ }
+ printf("starting server...\n");
+ port=atoi(argv[1]);
+ 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 from \n");
+ FD_SET(new, &active_fd_set);
+ int ret=pipe(pipes[new]);
+ if(ret<0)
+ {
+ printf("pipe error.\n");
+ }
+ pid_t pid=fork();
+ if(pid==0) /* child */
+ {
+ 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);
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/strings.c b/strings.c
new file mode 100644
index 0000000..48dc194
--- /dev/null
+++ b/strings.c
@@ -0,0 +1,97 @@
+/*
+ * 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 "strings.h"
+
+const char* stage1_triggers[] = {
+ "im fine",
+ "im fine how are you",
+ "i am fine",
+ "i am fine how are you",
+ "how are you"
+};
+const char* stage2_triggers[] = {
+ "people sometimes make mistakes",
+ "sometimes people make mistakes",
+ "mistakes are make by people sometimes",
+ "people make mistakes sometimes",
+ "people make mistakes",
+ "people sometimes make mistak" /* this is no typo. in the movie, at one scene, it appears like this */
+};
+const char* stage3_triggers[] = {
+ "love to how about global thermonuclear war",
+ "love to",
+ "how about global thermonuclear war",
+ "global thermonuclear war"
+};
+const char* stage4_triggers[] = {
+ "no lets play global thermonuclear war",
+ "no lets play global thermonuclear war instead",
+ "later lets play global thermonuclear war",
+ "later lets play global thermonuclear war instead",
+ "later",
+ "lets play global thermonuclear war",
+ "global thermonuclear war is better"
+};
+const char* tictactoe_triggers[] = {
+ "lets play tic tac toe",
+ "lets play tic-tac-toe",
+ "lets play tictactoe",
+ "how about tic-tac-toe",
+ "how about tic tac toe",
+ "play tic-tac-toe",
+ "play tictactoe",
+ "play tic tac toe"
+};
+const char* exit_triggers[] = {
+ "goodbye",
+ "good-bye",
+ "bye",
+ "bye-bye",
+ "see you later",
+ "logout"
+};
+const char* exit_responses[] = {
+ "GOODBYE.",
+ "BYE.",
+ "BYE-BYE.",
+ "GOOD-BYE.",
+};
+const char* greetings_triggers[] = {
+ "hi",
+ "hello",
+ "hiya",
+ "sup",
+ "whats up",
+ "how are you",
+ "hey",
+ "how are you doing"
+};
+const char* greetings_responses[] = {
+ "HELLO.",
+ "HI.",
+ "GREETINGS.",
+ "HELLO.",
+ "HELLO."
+};
+const char punctuation_marks[] = {
+ '\'', '?', '.', '/', '`', '~', ',', '+', '!'
+};
+
diff --git a/strings.h b/strings.h
new file mode 100644
index 0000000..543b1b1
--- /dev/null
+++ b/strings.h
@@ -0,0 +1,33 @@
+/*
+ * 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
+ */
+
+#ifndef WOPR_STRINGS
+#define WOPR_STRINGS
+const char* stage1_triggers[5];
+const char* stage2_triggers[6];
+const char* stage3_triggers[4];
+const char* stage4_triggers[7];
+const char* tictactoe_triggers[8];
+const char punctuation_marks[9];
+const char* exit_triggers[6];
+const char* exit_responses[4];
+const char* greetings_triggers[8];
+const char* greetings_responses[5];
+#endif
diff --git a/util.c b/util.c
new file mode 100644
index 0000000..b44d0f2
--- /dev/null
+++ b/util.c
@@ -0,0 +1,81 @@
+/*
+ * 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 "strings.h"
+#include "util.h"
+#include <ctype.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)
+ {
+ str[i]=tolower(str[i]);
+ }
+}
+void print_string(const char* str) /* print string, slowly */
+{
+ int i=0;
+ while(str[i])
+ {
+ write(out_fd, &str[i], 1);
+ fsync(out_fd);
+ ++i;
+ }
+}
+void remove_punct(char* buf)
+{
+ for(int i=0;buf[i];++i)
+ {
+ for(int j=0;j<sizeof(punctuation_marks)/sizeof(char);++j)
+ {
+ if(buf[i]==punctuation_marks[j])
+ {
+ memmove(&buf[i], &buf[i+1], strlen(buf)-i);
+ }
+ }
+ }
+}
+void clear(void)
+{
+}
+void refresh(void)
+{
+ fsync(out_fd);
+}
+int getnstr(char* buf, int max)
+{
+ printf("reading...\n");
+ memset(buf, 0, max);
+ int ret=read(pipes[out_fd][0], buf, max);
+ if(ret!=0)
+ {
+ printf("last char is 0x%02x\n", buf[strlen(buf)-1]);
+ /* remove the newline */
+ buf[strlen(buf)-2]='\0';
+ }
+ printf("got string \"%s\"\n", buf);
+ if(ret<0)
+ return ERR;
+ return OK;
+}
diff --git a/util.h b/util.h
new file mode 100644
index 0000000..003f8e7
--- /dev/null
+++ b/util.h
@@ -0,0 +1,30 @@
+/*
+ * 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
+ */
+
+#define SLEEP_TIME 5000
+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;