/*  misc.c

    Copyright (C) 1994	Lambert Klasen & Detlef Steuer
			klasen@asterix.uni-muenster.de
			steuer@amadeus.statistik.uni-dortmund.de

    This file is free source code; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation.

    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
    COPYING for more details.
 */



#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <pwd.h>
#include <sys/types.h>
#include <time.h>
#include <X11/Xlib.h>
#include <X11/Intrinsic.h>
#include <X11/Xaw/Label.h>
#include "xgammon.h"
#include "gammon.h"

extern Cursor	     gammon_cursor;
extern XColor	     fg_col, bg_col; /* gammon_cursor colors */

extern int	     from_pin;
extern int	     width, stone_width, height;
extern int  	     done_yet, done_hit, current_hit[4];
extern unsigned long delaytime;
extern FILE          *protokol_file;

int	moves_set = 0;
char    protokol_file_name[50];

/* for some irix */
#ifdef irix
#define usleep (a) sleep ((a/10))
#endif

extern void set_game_kind   ();

/* decision.c */
extern float evaluate       ();

/* popup.c */
extern void Info            ();

/* drawing.c */
extern void DrawDice        ();
extern void DrawDoubler     ();
extern void RedrawAllStones ();
extern void DrawEmptyBoard  ();
extern void DrawBoard       ();
extern void DrawDoubler     ();

struct _move_hist *move_hist = NULL;

long int NaufM[16][7];
long int Binomial[7][7];

void switch_turn (void)
{
	Display *dpy = Player[0].X11Set.dpy;

	if (turn==BLACK) {
		turn  = WHITE;
		other = BLACK;
		direction = -1;
		start_pin = 25;
		end_pin   = 0;	
	} 
	else {
		turn  =  BLACK;
		other = WHITE;
		direction = 1;
		start_pin = 0;
		end_pin   = 25;	
	}

	done_hit = 0;

	/* make the cursor look like the stones you move */
	if (Player[0].type == HUMAN && Player[1].type == HUMAN) {
		if (!gammon_resource.other_display) {
		        if (turn == BLACK)
				XRecolorCursor (dpy, Player[0].X11Set.cursor, &Player[0].X11Set.fg_col, &Player[0].X11Set.bg_col);
	        	else	XRecolorCursor (dpy, Player[0].X11Set.cursor, &Player[0].X11Set.bg_col, &Player[0].X11Set.fg_col);
		} /* else nothing to recolor */
	}
}

void RollDice (void)
{
	roll[0] = (rand ()%6 + 1) * direction;
	roll[1] = (rand ()%6 + 1) * direction;

        if (roll[0] != roll[1]) {
                roll[2] = 0;		/* sure and necessary */
                roll[3] = 0;
		to_move = 2;
		pash = 0;
	} else {
		roll[2] = roll[0];
		roll[3] = roll[1];
		to_move = 4;
		pash = 1;
	}

	sprintf (add_text, "%s rolls %d and %d.\n", Player[turn-1].name, abs (roll[0]), abs (roll[1]));

	AppendDialogText (LOWER, add_text);
}

int end_of_game_test (int color)
{
	int i, k;

	for (i=start_pin+direction*19; i!=start_pin+direction*25; i+=direction) {
		if (Pin[i].color == turn) return 0;
	}

	/* if we get here lookup if we have to count doubler two or three times */

	if (Pin[OTHER_BAR].count) {	/* a stone of the opponent on BAR */
		doubler.value *= 3;
		Player[turn-1].backgammons ++;
		return BACKGAMMON;
	}

	for (i = end_pin-direction; i != end_pin-direction*7; i-=direction) {	/* a stone in the opponents first quarter */
		if (Pin[i].color == other) {
			doubler.value *= 3;
			Player[turn-1].backgammons ++;
			return BACKGAMMON;
		}
	}

	/* other has no stone off */

	k = Pin[OTHER_BAR].count;
	for (i=1; i<25; i++) if (Pin[i].color == other) k += Pin[i].count;

	if (k == 15) {
		doubler.value *=2;
		Player[turn-1].gammons ++;
		return GAMMON;
	}

	return NORMAL; 
}

int complete_blockade (void)
{
	int i;

	for (i=start_pin+direction; i!=start_pin+direction*7; i+=direction) {
		if (Pin[i].count == 0 || Pin[i].color == turn ||
		   (Pin[i].color != turn && Pin[i].count < 2)) return 0;
	}
	return 1;
}

/* this function checkes, if you make a multible move, if you have to hit an
   opponents stone on the run */

int have_to_hit (int from, int to)
{
	if (!pash) {
		if (Pin[from + roll[0]].color == other && Pin[from + roll[1]].color == other) {
			if (Pin[from + roll[0]].count == 1 && Pin[from + roll[1]].count == 1) {
				Info ("Please decide witch stone you want to hit");
				return 1;
			}
			else if (Pin[from + roll[0]].count == 1) {
				RemoveStone  (from + roll[0]);
				PutStone  (other, OTHER_BAR);
				return 0;
			}
			else if (Pin[from + roll[1]].count == 1){
				RemoveStone  (from + roll[1]);
				PutStone  (other, OTHER_BAR);
				return 0;
			}
		}
		else return 0;	/* will not hit by default */
	} else {
		int i;
		for (i=1; i<4; i++) {	/* to_pin is checked by PlaceStone */
			if ((from + i*roll[0]) == to) break;
			if (Pin[from + i*roll[0]].color == other && ! ((turn==BLACK) ? from + i*roll[0] >= end_pin : from + i*roll[0] <= end_pin)) {
				RemoveStone  (from + i*roll[0]);
				PutStone  (other, OTHER_BAR);
			}
		}
	}
	return 0;
}

void free_move_hist (void)
{
	struct _move_hist *d, *h = move_hist;

	while (h) {
		d = h;
		h = h->next;
		free (d);
	}
}

void init_game (void)
{
	int i;

	from_pin = 0;
	done_yet = 0;
	done_hit = 0;

	if (initialize == NORMAL_GAME         ||
	    initialize == COMPUTER_TOURNAMENT) {
		for (i=0; i<29; i++) { Pin[i].count=0; Pin[i].color=0; }

		Pin[ 1].color = BLACK; Pin[ 1].count = 2;
		Pin[12].color = BLACK; Pin[12].count = 5;
		Pin[17].color = BLACK; Pin[17].count = 3;
		Pin[19].color = BLACK; Pin[19].count = 5;
		
		Pin[ 6].color = WHITE; Pin[ 6].count = 5;
		Pin[ 8].color = WHITE; Pin[ 8].count = 3;
		Pin[13].color = WHITE; Pin[13].count = 5;
		Pin[24].color = WHITE; Pin[24].count = 2;

		Pin[ (25+BLACK)].color = BLACK;		/* init BARS */
		Pin[ (25+WHITE)].color = WHITE;

		doubler.value = 1;
		doubler.owner = 0;

		tournament.game_number++;
		if      (Player[0].type == HUMAN    && Player[1].type == HUMAN)    sprintf (add_text,"Starting a new game with  %s, ", Player[0].name);
		else if (Player[0].type == COMPUTER && Player[1].type == COMPUTER) sprintf (add_text,"Starting a new game with xgammon (0)\n");
		else if (Player[0].type == HUMAN)  sprintf (add_text,"Starting a new game with %s\n", Player[0].name);
		else 				   sprintf (add_text,"Starting a new game with %s\n", Player[1].name);
		AppendDialogText (LOWER, add_text);


		direction = 1; 		/* get beginner of game */
		do {
			roll[0] = (rand ()%6 + 1);
			roll[1] = (rand ()%6 + 1);
		} while (roll[0] == roll[1]);

		roll[2] = 0;
		roll[3] = 0;
		to_move = 2;
		pash    = 0;

		if      (roll[1] > roll[0]) {		/* white begins */
			turn = BLACK;
			switch_turn ();		/* switch_turn sets turn to white and all the other vars */
			roll[0] *= direction;	/* must a be */
			roll[1] *= direction;
			roll[2] *= direction;
			roll[3] *= direction;
			Player[1].beginner_of_game = 1;
			Player[0].beginner_of_game = 0;
		}
		else if (roll[0] > roll[1]) {
			turn = WHITE;
			switch_turn ();
			Player[0].beginner_of_game = 1;
			Player[1].beginner_of_game = 0;
		}

		DrawEmptyBoard  ();
		DrawBoard       ();
		RedrawAllStones ();
		DrawDoubler (doubler.value, doubler.owner);


		sprintf (add_text, "%s rolled %d, %s rolled %d\n", Player[0].name, abs (roll[0]), Player[1].name, abs (roll[1]));
		AppendDialogText (LOWER, add_text);
		if (roll[0] < 0) sprintf (add_text, "%s makes the first move.\n",   Player[1].name);
		else		 sprintf (add_text, "%s makes the first move.\n\n", Player[0].name);
		AppendDialogText (LOWER, add_text);
		DrawDice (turn);

		break_loop = 0;
	} /* end initialize */

	if (move_hist) free_move_hist ();
	move_hist = NULL;
}

void AppendMoveString (MOVE *m)
{
	struct _move_hist *new;
	char f[5], t[5];
	int  i;

	if (!m || !(m->from || m->to)) {
		sprintf (add_text, "%s can't move.\n\n", Player[turn-1].name);
	} else {
		sprintf (add_text, "%s moves ", Player[turn-1].name);

		for (i=0; i<to_move; i++) {
			if ((m+i)->from != BAR) sprintf (f,"%d-", (m+i)->from);
			else strcpy (f,"bar-");
		        strcat  (add_text, f);

			if ((m+i)->to != end_pin) sprintf (t,"%d ", (m+i)->to);
			else strcpy (t,"off ");
		        strcat  (add_text, t);
		}
		strcat (add_text, ".\n\n");
	}

	AppendDialogText (LOWER, add_text);
	if (!m) {
		XSync  (Player[0].X11Set.dpy, 0);
		if (gammon_resource.other_display) {
			XSync  (Player[1].X11Set.dpy, 0);
		}
		usleep (delaytime);
	}

	moves_set ++;

	new = (struct _move_hist *) malloc (sizeof (struct _move_hist));
	new->next = move_hist;
	move_hist = new;

	if (m) {
		for (i=0; i<to_move; i++) {
			move_hist->from[i] = (m+i)->from;

			if ((m+i)->to != end_pin) 
				move_hist->from[i] = (m+i)->to;
			else	move_hist->to[i]   = FINISHED;
			move_hist->hit[i]          = current_hit[i];
		}
		for (i=to_move; i<4; i++) {
			move_hist->from[i] = 0;
			move_hist->to[i]   = 0;
			move_hist->hit[i]  = 0;
		}
	} else {
		for (i=0; i<4; i++) {
			move_hist->from[i] = 0;
			move_hist->to[i]   = 0;
			move_hist->hit[i]  = 0;
		}
	}
}

XPoint PinToPosition (int pin)
{
	XPoint p;

	if      (pin == BAR || pin == OTHER_BAR) p.x = width/2 - stone_width/2; 
	else if (pin == FINISHED)                p.x = width   - stone_width;
	else if (pin < 7)    p.x = width - (pin +  1) * stone_width;
	else if (pin < 13)   p.x = width - (pin +  1) * stone_width - stone_width;
	else if (pin < 19)   p.x = width - (26 - pin) * stone_width - stone_width;
	else if (pin < 25)   p.x = width - (26 - pin) * stone_width;

	if      (pin == FINISHED)     p.y =  Pin[FINISHED].count * height/2/15;
	else if (Pin[pin].count < 5)  p.y =  Pin[pin].count     * stone_width;
	else if (Pin[pin].count < 9)  p.y = (Pin[pin].count-5)  * stone_width + stone_width/2;
	else if (Pin[pin].count < 13) p.y = (Pin[pin].count-9)  * stone_width + stone_width/4;
	else			      p.y = (Pin[pin].count-13) * stone_width + stone_width*3/4;

	/* for upper half of board */
	if (((pin == BAR || pin == OTHER_BAR) && Pin[pin].color == WHITE) ||
	     (pin == FINISHED && turn == BLACK) ||
	     (pin > 12 && pin != FINISHED))      p.y = height - stone_width - p.y;

	return p;
}

int EventToPin (int x, int y)
{
	int p;

	p  = (width - x) / stone_width;

	switch (p) {
	case  0: return end_pin; break;
	case  7: return BAR;     break;
	case 14: return DOUBLER; break;
	}

	if ((y - height/2) < 0) {		/* upper part of the board */
		if (p > 6) return p-1;		/* left  of bar */
		else	   return p;		/* right of bar */
	} else { 				/* lower part of the board */
		p = 25 - p;
		if (p < 19) return p+1; 	/* left  of bar */
		else	    return p;		/* right of bar */
	}
}

void AddResult (int whom)
{
	char *gammon_str;

	Player[whom-1].points += doubler.value;

	switch (end_of_game) {
	case NORMAL:	  gammon_str = "";		break;
	case GAMMON:	  gammon_str = "gammon";	break;
	case BACKGAMMON:  gammon_str = "backgammon";	break;
	}

	sprintf (add_text, "%s wins the %d. game %s and gets %d points.\n", Player[whom-1].name, tournament.game_number, gammon_str, doubler.value);
	AppendDialogText (UPPER, add_text);
	sprintf (add_text, "%s wins the game %s and gets %d points.\n", Player[whom-1].name, gammon_str, doubler.value);
	AppendDialogText (LOWER, add_text);

	if      (gammon_resource.moneygame) sprintf (add_text, "score in moneygame match: %s-%d %s-%d\n\n",			     Player[0].name, Player[0].points, Player[1].name, Player[1].points);
	else if (gammon_resource.winat)     sprintf (add_text, "score in %d point match: %s-%d %s-%d\n\n",  tournament.winning_point, Player[0].name, Player[0].points, Player[1].name, Player[1].points);
	AppendDialogText (LOWER, add_text);
	AppendDialogText (UPPER, add_text);

	if      (gammon_resource.moneygame) return;
	else if (gammon_resource.winat && Player[whom-1].points >= tournament.winning_point)
		sprintf (add_text, "%s wins the %d point match %d-%d .\n\n", Player[whom-1].name, tournament.winning_point, Player[0].points, Player[1].points);

	AppendDialogText (LOWER, add_text);
	AppendDialogText (UPPER, add_text);
	AppendDialogText (UPPER, "end of tournament\n\n");
}

long int fak (int n)
{
	if (n <= 1) return (1);
	else	    return (n * fak (n - 1));
}


long int binomial (int n, int m)
{
	return (fak (n) / fak (m) / fak (n - m));
}

long int naufm (int n, int m)
{
	if (n < m)  return (0);
	if (m == 1) return (1);
	return (naufm (n - 1, m) + naufm (n - 1, m - 1));
}

void set_naufm ()
{
	int i, j;

	for (i = 1; i < 16; i++) {
	for (j = 1; j < 7;  j++) {
		NaufM[i][j] = naufm (i, j);
	}}
}

void set_binom ()
{
	int i, j;

	for (i = 1; i < 7; i++) {
	for (j = 1; j < 7; j++) {
		Binomial[i][j] = binomial (i, j);
	}}
}

/* PositionNumber:
   this function calculates out of a given endgame position the corresponding
   position number in the endgame database, in a running game pin 6 is set
   as aim for stones not in the homeboard */

long int PositionNumber (int STARTPIN, int color)
{
	int pin[7];
	int sum = 0, s, i, stones;
	int start, nextpin, local_direction, local_endpin;
	long int number = 0L;

	if (color == turn) {
		local_direction = direction;
		local_endpin    = end_pin;
	} else {
		local_direction = -1 * direction;
		local_endpin    = start_pin;
	}

	pin[0] = 0;

	for (i = 1; i < 7; i++) {
		if (Pin[local_endpin - i * local_direction].color == color)
			pin[i] = Pin[local_endpin - i * local_direction].count;
		else
			pin[i] = 0;
	}

	for (i = 1; i < 7; i++) sum += pin[i];

	/* put all stones on the 6. pin */
	pin[6] += 15 - sum - Pin[25 + color].count;
	sum = 0;

	for (i = STARTPIN + 1; i < 7; i++) sum += pin[i];

	if (sum == 0) return (0);
	i = STARTPIN + 1;


	while (pin[i] == 0 && i < 7) i++;

	nextpin = i - STARTPIN;
	number += nextpin;

	for (start = STARTPIN; start < STARTPIN + nextpin; start++) {
		for (stones = 1; stones < sum; stones++) {
			for (s = 1; s < 6 - start + 1; s++) {
				number += Binomial[6 - start][s] * NaufM[stones][s];

			}
		}
	}

	number += PositionNumber (STARTPIN + nextpin, color);

	return (number);
}

MOVE *find_best_move ()
{
	MOVE *move_return = NULL, *pm = possible_moves;
	int i, hit[4];
	float maxvalue = -10000.0, value;

	while (pm != list) {
	for (i = 0; i < to_move; i++) {		/* do move */
		if ((pm + i)->from + (pm + i)->to) {
			hit[i] = 0;
			Pin[ (pm + i)->from].count--;
			if (!Pin[ (pm + i)->from].count) Pin[ (pm + i)->from].color = 0;

			if ((pm + i)->to == end_pin) Pin[FINISHED].count++;
			else {
				if (Pin[ (pm + i)->to].color == other) {
					Pin[ (pm + i)->to].color = turn;
					hit[i] = 1;
					Pin[OTHER_BAR].count++;
					Pin[OTHER_BAR].color = other;
				} else {
					Pin[ (pm + i)->to].count++;
					Pin[ (pm + i)->to].color = turn;
				}
			}
		}
	}
#ifdef DEBUG_EVALUATE
{
	int k;
	MOVE *d = pm;
	printf ("\n");
	for (k = 0; k < 4; k++) {
		printf ("%2d -> %2d  ", d->from, d->to);
		d++;
	}
	printf ("\n");
}
#endif

	value = evaluate (turn);
	if (value > maxvalue) {
		maxvalue = value;
		move_return = pm;
	}

	for (i = to_move - 1; i > -1; i--) {		/* undo move */
		if ((pm + i)->from + (pm + i)->to) {
			Pin[ (pm + i)->from].count++;
			Pin[ (pm + i)->from].color = turn;

			if (hit[i]) {
				Pin[ (pm + i)->to].color = other;
				Pin[OTHER_BAR].count--;
				if (!Pin[OTHER_BAR].count) Pin[OTHER_BAR].color = 0;
			} else {
				if ((pm + i)->to == end_pin) Pin[FINISHED].count--;
				else {
					Pin[ (pm + i)->to].count--;
					if (!Pin[ (pm + i)->to].count) Pin[ (pm + i)->to].color = 0;
				}
			}
		}
	}
	pm += 4;
}

#ifdef DEBUG_EVALUATE
{
	int k;
	MOVE *d = move_return;
	for (k = 0; k < 4; k++) {
		printf ("%2d -> %2d  ", d->from, d->to);
		d++;
	}
	printf ("\n this is the best move with vlaue %f\n",maxvalue);
}
#endif
	return (move_return);
}

void maildump (void)
{
	FILE *maildumpfile;
	int i, j;

	maildumpfile = fopen ("xgammon.maildump", "w");

	if (!maildumpfile) {
		Info ("Couldn't open dump file!\nSorry.");
		return;
	}

	fprintf (maildumpfile, "\n\n");
	fprintf (maildumpfile, "    13 14 15 16 17 18       19 20 21 22 23 24\n   +------------------------------------------+ X: - score: %d\n", Player[1].points);
	for (i=0; i<4; i++) {
	fprintf (maildumpfile, "   |");
	for (j=12; j>6; j--) {
		if      (Pin[j].color == WHITE && Pin[j].count >= i+1) fprintf (maildumpfile, " X ");
		else if (Pin[j].color == BLACK && Pin[j].count >= i+1) fprintf (maildumpfile, " O ");
		else						       fprintf (maildumpfile, "   ");
	}
	fprintf (maildumpfile, "|   | ");
	for (j=6; j>0; j--) {
		if      (Pin[j].color == WHITE && Pin[j].count >= i+1) fprintf (maildumpfile, " X ");
		else if (Pin[j].color == BLACK && Pin[j].count >= i+1) fprintf (maildumpfile, " O ");
		else						       fprintf (maildumpfile, "   ");
	}
	fprintf (maildumpfile, "|\n");
	}

	fprintf (maildumpfile, "   |");
	for (j=12; j>6; j--) {
		if      (Pin[j].color == WHITE && Pin[j].count == 5) fprintf (maildumpfile, " X ");
		else if (Pin[j].color == WHITE && Pin[j].count >  5) fprintf (maildumpfile, "%2d ", Pin[j].count);
		else if (Pin[j].color == BLACK && Pin[j].count == 5) fprintf (maildumpfile, " O ");
		else if (Pin[j].color == BLACK && Pin[j].count >  5) fprintf (maildumpfile, "%2d ", Pin[j].count);
		else						     fprintf (maildumpfile, "   ");
	}
	fprintf (maildumpfile, "|   | ");
	for (j=6; j>0; j--) {
		if      (Pin[j].color == WHITE && Pin[j].count == 5) fprintf (maildumpfile, " X ");
		else if (Pin[j].color == WHITE && Pin[j].count > 5)  fprintf (maildumpfile, "%2d ", Pin[j].count);
		else if (Pin[j].color == BLACK && Pin[j].count == 5) fprintf (maildumpfile, " O ");
		else if (Pin[j].color == BLACK && Pin[j].count > 5)  fprintf (maildumpfile, "%2d ", Pin[j].count);
		else						     fprintf (maildumpfile, "   ");
	}
	fprintf (maildumpfile, "|\n");
	fprintf (maildumpfile, "  v|                  |BAR|                   |    ");

	if   (gammon_resource.moneygame) fprintf (maildumpfile, "money-game\n");
	else 				 fprintf (maildumpfile, "%d-point match\n", gammon_resource.winat);

	fprintf (maildumpfile, "   |");
	for (j=13; j<19; j++) {
		if      (Pin[j].color == WHITE && Pin[j].count == 5) fprintf (maildumpfile, " X ");
		else if (Pin[j].color == WHITE && Pin[j].count > 5)  fprintf (maildumpfile, "%2d ", Pin[j].count);
		else if (Pin[j].color == BLACK && Pin[j].count == 5) fprintf (maildumpfile, " O ");
		else if (Pin[j].color == BLACK && Pin[j].count > 5)  fprintf (maildumpfile, "%2d ", Pin[j].count);
		else						     fprintf (maildumpfile, "   ");
	}
	fprintf (maildumpfile, "|   | ");
	for (j=19; j<25; j++) {
		if      (Pin[j].color == WHITE && Pin[j].count == 5) fprintf (maildumpfile, " X ");
		else if (Pin[j].color == WHITE && Pin[j].count > 5)  fprintf (maildumpfile, "%2d ", Pin[j].count);
		else if (Pin[j].color == BLACK && Pin[j].count == 5) fprintf (maildumpfile, " O ");
		else if (Pin[j].color == BLACK && Pin[j].count > 5)  fprintf (maildumpfile, "%2d ", Pin[j].count);
		else						     fprintf (maildumpfile, "   ");
	}
	fprintf (maildumpfile, "|\n");

	for (i=4; i>0; i--) {
	fprintf (maildumpfile, "   |");
	for (j=13; j<19; j++) {
		if      (Pin[j].color == WHITE && Pin[j].count >= i) fprintf (maildumpfile, " X ");
		else if (Pin[j].color == BLACK && Pin[j].count >= i) fprintf (maildumpfile, " O ");
		else						     fprintf (maildumpfile, "   ");
	}
	fprintf (maildumpfile, "|   | ");
	for (j=19; j<25; j++) {
		if      (Pin[j].color == WHITE && Pin[j].count >= i) fprintf (maildumpfile, " X ");
		else if (Pin[j].color == BLACK && Pin[j].count >= i) fprintf (maildumpfile, " O ");
		else						     fprintf (maildumpfile, "   ");
	}
	fprintf (maildumpfile, "|\n");
	}

	fprintf (maildumpfile, "   +------------------------------------------+ O:  - score: %d\n", Player[0].points);
	fprintf (maildumpfile, "    12 11 10  9  8  7        6  5  4  3  2  1\n\n");
	if (turn == BLACK)
		fprintf (maildumpfile, "   BAR: O-%d X-%d", Pin[0].count, Pin[25].count);
	else
		fprintf (maildumpfile, "   BAR: O-%d X-%d", Pin[25].count, Pin[0].count);
	fprintf (maildumpfile, "   OFF: O-%d X-%d", Pin[26].count, Pin[27].count);
	fprintf (maildumpfile, "   Cube: %d ", doubler.value);
	if      (doubler.owner == BLACK) fprintf (maildumpfile, "(owned by Player O)\n");
	else if (doubler.owner == WHITE) fprintf (maildumpfile, "(owned by Player X)\n");
	else				fprintf (maildumpfile, "(owned by Player none)\n");
	fprintf (maildumpfile, "\n\n");

	fclose  (maildumpfile);

	Info (" position written to \n xgammon.maildump ");
}

void open_protokol (void)
{
	if (gammon_resource.protokol) {
		if (protokol_file) return; /* already open */
		sprintf (protokol_file_name,"xgammon.protokol.%d", getpid ());
		protokol_file = fopen (protokol_file_name, "w");
	}
}

char *UserName (void)
{
    return getpwuid (getuid ())->pw_name;
}

