The C-Source

/*
 * game.c
 * Copyright: Oliver Kirchkamp
 * Date: 15. 1. 1998
 * Project: A simple coordination game
 * Purpose: Demonstration for WWW experiments
 * 
 */

#include <stdio.h>
#include <time.h>
#include <unistd.h>
#include <signal.h>
#include <sys/types.h>
#include <sys/file.h>
#include "gd.h"
#include "gdfonts.h"
#include "cgi-lib.h"
#include "html-lib.h"
#include <math.h>
#include <sys/stat.h>

#define PUSH_HEADER "HTTP/1.0 200 OK\nServer: Apache/1.2b6\n\
        MIME-Version: 1.0\n\
        Content-Type: multipart/x-mixed-replace;boundary=EOM\n\n\
        --EOM\nContent-Type: text/html\n\n"
#define PUSH_HEADER_SANS_CONT "HTTP/1.0 200 OK\n\
        Server: Apache/1.2b6\nMIME-Version: 1.0\n\
        Content-Type: multipart/x-mixed-replace;boundary=EOM\n\n\
        --EOM\n"
#define PUSH_BOUNDARY "\n--EOM\n"
#define PUSH_CONT "Content-Type: text/html\n\n"
#define PUSH_END "\n--EOM"
#define push_header printf(PUSH_HEADER_SANS_CONT)
#define push_start_page printf(PUSH_CONT)
#define push_end_page printf(PUSH_BOUNDARY);fflush(stdout)
#define myfile "../dat/file"

llist cgi_entries;
int number;

/***********************************/
/*        goodbye                  */
/***********************************/
void goodbye (char *message) {
  push_start_page;
  h4 (message);
  push_end_page;
  exit (0);
}

/***********************************/
/*        call for strategy        */
/***********************************/
int call_for_strategy () {
  
  /* start with a heading: */
  h1 ("Welcome to the game");
  printf ("You will play a game against a single opponent. ");
  printf ("Both of you will enter a number between 0 and 100. ");
  printf ("Your payoff will be twice the minimal number ");
  printf ("minus the number that you have chosen. The same holds ");
  printf ("for your opponent.<p>");

  /* we want to transmit some data, this can best be done with a form,
   * METHOD can either be POST or GET, we take POST, since it may
   * send more data,
   * ACTION is the script that we want to call with the form,
   */
  printf ("<FORM METHOD=POST  ACTION=nph-game  \
           ENCTYPE=application/x-www-form-urlencoded>");
  printf ("Please enter a number between 0 and 100: ");
  printf ("<INPUT TYPE=TEXT NAME=Number>");
  printf ("<INPUT TYPE=SUBMIT NAME=I_DID_IT VALUE=Continue>");
  printf ("</FORM>");
  push_end_page;
  exit (0);
}

/***********************************/
/*       read_the_file             */
/***********************************/
void read_the_file (int *lines, int *smallest_number,
  long int* opponent) {
  FILE *number_file;
  int any_number;
  long int other_process;

  *opponent = 0; /* we do not know her yet */
  *lines = 0;/* no lines read at all */  

  /* attempt to open a file for reading */
  number_file = fopen (myfile,"r");
  
  /* if we could not open the file, say goodbye */
  if (! number_file) 
    goodbye ("could not read from my file");


  /* read all entries in the file */
  while (EOF != fscanf(number_file,"%d,%ld",&any_number,
    &other_process)) {
    /* initialise with the highest possible value */
    if (*lines % 2 == 0)
      *smallest_number = 100;

    if (any_number < *smallest_number)
      *smallest_number = any_number;
    
    /* if we find our opponent's pid, remember her */
    if (other_process != getpid())
      *opponent = other_process;
    ++(*lines);

  }
  fclose (number_file);

}

/***********************************/
/*        print_results        */
/***********************************/
void print_results () {
  int lines;
  int smallest_number;
  long int opponent;
  
  read_the_file (&lines,&smallest_number,&opponent);
  push_start_page;
  printf ("The smallest number was %d<P>",smallest_number);
  printf ("Your number was %d<P>",number);
  printf ("Your Payoff is, thus, <B>%d</B><p><hr>",
                                 2*smallest_number-number);

  call_for_strategy () ;
  exit (0);
}

/***********************************/
/*        wait for the other        */
/***********************************/
void wait_for_the_other () {
  push_start_page;
  h4("Please wait for your opponent");
  printf ("%ld",(long int) getpid());
  push_end_page;

  /* wait for a signal... */
  signal (SIGUSR1, &print_results);

  /* in the meantime, first have a nap */
  sleep (3600);

  /* if nothing happens, exit */
  exit (0);
}


/***********************************/
/*        write_number_into_a_file */
/***********************************/
void write_number_into_a_file () {
  FILE *number_file;

  /* translate the string "Number" into an integer "number" */
  sscanf (cgi_val(cgi_entries,"Number"),"%d",&number);

  /* check whether number is within 0 and 100 */
  if (number>100)
    number = 100;
  if (number<0)
    number = 0;

  /* attempt to open a file for writing 
     (append to the end of the file) */
  number_file = fopen (myfile,"a");
  
  /* if we could not open the file, say goodbye */
  if (! number_file)
    goodbye ("could not write into my file");

  /* wait until we are the only ones to write into that file */
    flock (fileno (number_file),LOCK_EX);
  
  /* write our number, and our identity into the file
   * as identity we take our pid */

  fprintf (number_file,"%d,%ld\n",number,(long int) getpid());
  
  /* unlock and close the file, such that others
     will be able to write there */
  fflush (number_file);
  flock (fileno (number_file),LOCK_UN);
  fclose(number_file);

}


/***********************************/
/*        evaluate_strategy        */
/***********************************/
void evaluate_strategy () {
  /* define some variables that we will use lateron */
  int lines;
  int smallest_number;
  long int opponent;

  write_number_into_a_file ();

  /* now read, what is actually in the file, in order to determine
     whether I am the first or the last */
  
  read_the_file (&lines,&smallest_number,&opponent);
  
  if (lines % 2 == 1) 
    wait_for_the_other ();
  else {
    /* send her a signal, as long as she exists */
    if (opponent)
      kill (opponent,SIGUSR1);

    print_results ();
  }
}


/***********************************/
/*            main                 */
/***********************************/
int main () {
  push_header;

  /* read, whatever was sent to us from a form */
  read_cgi_input (&cgi_entries);

  /* check, whether somebody sent us a number */
  if (cgi_val(cgi_entries,"Number"))
    evaluate_strategy ();

  /* otherwise, invite playing a game */
  else {
    push_start_page;
    call_for_strategy ();
  }
 
  return (0);
}



Oliver Kirchkamp 2013-04-15