/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\
* This is GNU Go, a Go program. Contact gnugo@gnu.org, or see *
* http://www.gnu.org/software/gnugo/ for more information. *
* Copyright 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, *
* 2008 and 2009 by the Free Software Foundation. *
* 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 - version 3 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 in file COPYING for more details. *
* You should have received a copy of the GNU General Public *
* License along with this program; if not, write to the Free *
* Software Foundation, Inc., 51 Franklin Street, Fifth Floor, *
* Boston, MA 02111, USA. *
\* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
/* Avoid compiler warnings with unused parameters */
#define UNUSED(x) (void)x
/* Define TERMINFO or ANSI_COLOR to enable coloring of pieces.
* This is normally done in config.h.
#elif HAVE_NCURSES_CURSES_H
#include <ncurses/curses.h>
#elif HAVE_NCURSES_TERM_H
#include <ncurses/term.h>
/* terminfo attributes */
static char *setaf
; /* terminfo string to set color */
static char *op
; /* terminfo string to reset colors */
/* compiler is set to make string literals const char *
* But system header files dont prototype things correctly.
* These are equivalent to a non-const string literals
static char setaf_literal
[] = "setaf";
static char op_literal
[] = "op";
static char empty_literal
[] = "";
setupterm(NULL
, 2, NULL
);
setaf
= tigetstr(setaf_literal
);
op
= tigetstr(op_literal
);
_ASSERTE(0 && "Win32 Error");
fprintf(stderr
, "Win32 Err: %ld\n", GetLastError());
/* mingw32 lacks crtdbg.h and _ASSERTE */
fprintf(stderr
, "Win32 Err: %ld\n", GetLastError());
write_color_char_no_space(int c
, int x
)
fprintf(stderr
, "%s%c", tparm(setaf
, c
, 0, 0, 0, 0, 0, 0, 0, 0), x
);
fputs(tparm(op
, 0, 0, 0, 0, 0, 0, 0, 0, 0), stderr
);
#elif defined(ANSI_COLOR)
fprintf(stderr
, "\033[%dm%c\033[0m", 30+c
, x
);
static HANDLE hStdErr
= 0;
CONSOLE_SCREEN_BUFFER_INFO bufInfo
;
hStdErr
= GetStdHandle(STD_ERROR_HANDLE
);
if (hStdErr
== INVALID_HANDLE_VALUE
) {
fprintf(stderr
, "Unable to open stderr.\n");
/* Red & Blue are switched from what MS-Windows wants:
* FOREGROUND_BLUE 0x0001 // text color contains blue.
* FOREGROUND_GREEN 0x0002 // text color contains green.
* FOREGROUND_RED 0x0004 // text color contains red
* This magic switches the bits back:
c
= (c
& 1) * 4 + (c
& 2) + (c
& 4) / 4;
c
+= FOREGROUND_INTENSITY
;
succeed32
= GetConsoleScreenBufferInfo(hStdErr
, &bufInfo
);
if (!succeed32
) { /* Probably redirecting output, just give plain text. */
fprintf(stderr
, "%c", x
);
verifyW32(SetConsoleTextAttribute(hStdErr
, (WORD
) c
));
verifyW32(WriteConsole(hStdErr
, &x
, 1, &iCharsWritten
, 0));
verifyW32(SetConsoleTextAttribute(hStdErr
, bufInfo
.wAttributes
));
fprintf(stderr
, "%c", x
);
write_color_string(int c
, const char *str
)
write_color_char_no_space(c
, *str
++);
write_color_char(int c
, int x
)
write_color_char_no_space(c
, x
);
* A wrapper around vsnprintf.
gg_vsnprintf(char *dest
, unsigned long len
, const char *fmt
, va_list args
)
vsnprintf(dest
, len
, fmt
, args
);
g_vsnprintf(dest
, len
, fmt
, args
);
_vsnprintf(dest
, len
, fmt
, args
);
vsprintf(dest
, fmt
, args
);
gg_snprintf(char *dest
, unsigned long len
, const char *fmt
, ...)
gg_vsnprintf(dest
, len
, fmt
, args
);
/* Get the time of day, calling gettimeofday from sys/time.h
* if available, otherwise substituting a workaround for portability.
return tv
.tv_sec
+ 1.e
-6 * tv
.tv_usec
;
/* return cputime used in secs */
#if HAVE_SYS_TIMES_H && HAVE_TIMES && HAVE_UNISTD_H
return (t
.tms_utime
+ t
.tms_stime
+ t
.tms_cutime
+ t
.tms_cstime
)
/ ((double) sysconf(_SC_CLK_TCK
));
FILETIME creationTime
, exitTime
, kernelTime
, userTime
;
ULARGE_INTEGER uKernelTime
, uUserTime
, uElapsedTime
;
GetProcessTimes(GetCurrentProcess(), &creationTime
, &exitTime
,
uKernelTime
.LowPart
= kernelTime
.dwLowDateTime
;
uKernelTime
.HighPart
= kernelTime
.dwHighDateTime
;
uUserTime
.LowPart
= userTime
.dwLowDateTime
;
uUserTime
.HighPart
= userTime
.dwHighDateTime
;
uElapsedTime
.QuadPart
= uKernelTime
.QuadPart
+ uUserTime
.QuadPart
;
/*_ASSERTE(0 && "Debug Times");*/
/* convert from multiples of 100nanosecs to seconds: */
return (signed __int64
)(uElapsedTime
.QuadPart
) * 1.e
-7;
fprintf(stderr
, "CPU timing unavailable - returning wall time.");
/* return wall clock seconds */
return gg_gettimeofday();
/* Before we sort floating point values (or just compare them) we
* may need to normalize them. This may sound cryptic but is
* required to avoid an obscure platform dependency.
* The underlying problem is that most fractional decimal numbers
* can't be represented exactly in a floating point number with base
* two. The error may be small but it is there. When such numbers
* are added or subtracted, the errors accumulate and even if the
* result (counting exactly) should be a number which can be
* represented exactly, this cannot be assumed to be the case.
* To give an example of this, the computation 0.3 + 0.05 - 0.35 may
* sum to 0, a small negative value, or a small positive value.
* Moreover, which case we encounter depends on the number of
* mantissa bits in the floating point type used and the exact
* details of the floating point arithmetic on the platform.
* In the context of sorting, assume that two values both should be
* 0.35, but one has been computed as 0.3 + 0.05 and the other
* directly assigned 0.35. Then it depends on the platform whether
* they compare as equal or one of them is larger than the other.
* This code normalizes the values to avoid this problem. It is
* assumed that all values encountered are integer multiples of a.
gg_normalize_float(float x
, float a
)
return a
* ((int) (0.5 + x
/ a
));
gg_normalize_float2int(float x
, float a
)
return ((int) (0.5 + x
/ a
));
/* A sorting algorithm, call-compatible with the libc qsort() function.
* The reason to prefer this to standard qsort() is that quicksort is
* an unstable sorting algorithm, i.e. the relative ordering of
* elements with the same comparison value may change. Exactly how the
* ordering changes depends on implementation specific details like
* the strategy for choosing the pivot element. Thus a list with
* "equal" values may be sorted differently between platforms, which
* potentially can lead to significant differences in the move
* This is an implementation of the combsort algorithm.
* Testing shows that it is faster than the GNU libc qsort() function
* on small data sets and within a factor of two slower for large
* random data sets. Its performance does not degenerate for common
* special cases (i.e. sorted or reversed data) but it seems to be
* susceptible to O(N^2) behavior for repetitive data with specific
* Like qsort() this algorithm is unstable, but since the same
* implementation (this one) is used on all platforms, the reordering
* of equal elements will be consistent.
gg_sort(void *base
, size_t nel
, size_t width
,
int (*cmp
)(const void *, const void *))
char *end
= (char *) base
+ width
* (nel
- 1);
gap
= (10 * gap
+ 3) / 13;
for (a
= base
, b
= a
+ gap
* width
; b
<= end
; a
+= width
, b
+= width
) {
if (cmp((void *) a
, (void *) b
) > 0) {
} while (gap
> 1 || swap_made
);
/* Linearly interpolate f(x) from the data given in interpolation_data. */
gg_interpolate(struct interpolation_data
*f
, float x
)
if (x
< f
->range_lowerbound
)
else if (x
> f
->range_upperbound
)
return f
->values
[f
->sections
];
ratio
= ((float) f
->sections
) * (x
- f
->range_lowerbound
)
/ (f
->range_upperbound
- f
->range_lowerbound
);
diff
= ratio
- ((float) i
);
fprintf(stderr
, "Floating point Ratio: %f, integer: %d, diff %f",
return ((1 - diff
) * f
->values
[i
] + diff
* f
->values
[i
+1]);
/* This is the simplest function that returns appr. a when a is small,
* and approximately b when a is large.
soft_cap(float a
, float b
)
return ((a
* b
) / (a
+ b
));
/* Reorientation of point (i, j) into (*ri, *rj) */
rotate(int i
, int j
, int *ri
, int *rj
, int bs
, int rot
)
assert(ri
!= NULL
&& rj
!= NULL
);
assert(rot
>= 0 && rot
< 8);
if (i
== -1 && j
== -1) {
assert(i
>= 0 && i
< bs
);
assert(j
>= 0 && j
< bs
);
/* rotation over 90 degrees */
/* rotation over 180 degrees */
/* rotation over 270 degrees */
/* flip along diagonal */
/* flip along diagonal */
/* inverse reorientation of reorientation rot */
inv_rotate(int i
, int j
, int *ri
, int *rj
, int bs
, int rot
)
/* every reorientation is it's own inverse except rotations
over 90 and 270 degrees */
rotate(i
, j
, ri
, rj
, bs
, 3);
rotate(i
, j
, ri
, rj
, bs
, 1);
rotate(i
, j
, ri
, rj
, bs
, rot
);
/* Intermediate layer to random.c. gg_srand() should only be called via the
/* Private variable remembering the random seed. */
static unsigned int random_seed
;
set_random_seed(unsigned int seed
)
/* Update the random seed. This should be called at the start of each
* We reset the random seed before obtaining a new one, to make the
* next random seed depend deterministically on the old one.
/* Since random seed 0 has a special interpretation when given as
* command line argument with the -r option, we make sure to avoid
/* Restart the pseudo-random sequence with the initialization given
* by the random seed. Should be called at each move.