#include "chess.h"
#include "data.h"
/* last modified 02/26/14 */
/*
*******************************************************************************
* *
* "annotate" command is used to search through the game in a pgn file, and *
* provide a qualitative analysis of each move played and then creating a *
* new output file (xxx.can) containing the original game + new commentary. *
* *
* The normal output of this command is a file, in PGN format, that contains *
* the moves of the game, along with analysis when Crafty does not think *
* that move was the best choice. The definition of "best choice" is *
* somewhat vague, because if the move played is "close" to the best move *
* available, Crafty will not comment on the move. "Close" is defined by *
* the <margin> option explained below. This basic type of annotation works *
* by first using the normal tree search algorithm to find the best move. *
* If this move was the move played, no output is produced. If a different *
* move is considered best, then the actual move played is searched to the *
* same depth and if the best move and actual move scores are within *
* <margin> of each other, no comment is produced, otherwise Crafty inserts *
* the evaluation for the move played, followed by the eval and PV for the *
* best continuation it found. You can enter suggested moves for Crafty to *
* analyze at any point by simply entering a move as an analysis-type *
* comment using (move) or {move}. Crafty will search that move in addition *
* to the move actually played and the move it thinks is best. *
* *
* The format of the command is as follows: *
* *
* annotate filename b|w|bw|name moves margin time [n] *
* *
* Filename is the input file where Crafty will obtain the moves to *
* annotate, and output will be written to file "filename.can". *
* *
* annotateh filename b|w|bw|name moves margin time [n] *
* *
* Can be used to produce an HTML-compatible file that includes bitmapped *
* diagrams of the positions where Crafty provides analysis. This file can *
* be opened by a browser to provide much easier 'reading'. *
* *
* annotatet filename b|w|bw|name moves margin time [n] *
* *
* Can be used to produce a LaTeX-compatible file that includes LaTeX chess *
* fonts. This file can be read/printed by any program that can handle *
* LaTeX input. *
* *
* Where b/w/bw indicates whether to annotate only the white side (w), the *
* black side (b) or both (bw). You can also specify a name (or part of a *
* name, just be sure it is unique in the name tags for clarity in who you *
* mean). *
* *
* Moves indicates the move or moves to annotate. It can be a single move, *
* which indicates the starting move number to annotate, or it can be a *
* range, which indicates a range of move (1-999 gets the whole game.) *
* *
* Margin is the difference between Crafty's evaluation for the move *
* actually played and for the move Crafty thinks is best, before Crafty *
* will generate a comment in the annotation file. 1.0 is a pawn, and will *
* only generate comments if the move played is 1.000 (1 pawn) worse than *
* the best move found by doing a complete search. *
* *
* Time is time per move to search, in seconds. *
* *
* [n] is optional and tells Crafty to produce the PV/score for the "n" best *
* moves. Crafty stops when the best move reaches the move played in the *
* game or after displaying n moves, whichever comes first. If you use -n, *
* then it will display n moves regardless of where the game move ranks. *
* *
*******************************************************************************
*/
#define MIN_DECISIVE_ADV 150
#define MIN_MODERATE_ADV 70
#define MIN_SLIGHT_ADV 30
void Annotate() {
FILE *annotate_in, *annotate_out;
char text[128], tbuffer[4096], colors[32] = { "" }, pname[128] = {
""};
int annotate_margin, annotate_score[100], player_score, best_moves,
annotate_wtm;
int annotate_search_time_limit, search_player;
int twtm, path_len, analysis_printed = 0;
int wtm, move_num, line1, line2, move, suggested, i;
int searches_done, read_status;
PATH temp[100], player_pv;
int temp_search_depth;
TREE *const tree = block[0];
char html_br[5] = { "" };
int save_swindle_mode;
int html_mode = 0;
int latex = 0;
/*
************************************************************
* *
* First, extract the options from the command line to *
* determine what the user wanted us to do. *
* *
************************************************************
*/
save_swindle_mode = swindle_mode;
if (!strcmp(args
[0], "annotateh")) {
html_mode = 1;
}
if (!strcmp(args
[0], "annotatet")) {
latex = 1;
}
nargs = ReadParse(tbuffer, args, " \t;");
if (nargs < 6) {
("usage: annotate <file> <color> <moves> <margin> <time> [nmoves]\n");
return;
}
annotate_in
= fopen(args
[1], "r");
if (annotate_in == NULL) {
Print(4095, "unable to open %s for input\n", args[1]);
return;
}
nargs = ReadParse(tbuffer, args, " \t;");
if (html_mode == 1)
else if (latex == 1)
else
annotate_out
= fopen(text
, "w");
if (annotate_out == NULL) {
Print(4095, "unable to open %s for output\n", text);
return;
}
if (html_mode == 1)
AnnotateHeaderHTML(text, annotate_out);
if (latex == 1)
AnnotateHeaderTeX(annotate_out);
else
line1 = 1;
line2 = 999;
line2 = -1;
sscanf(args
[3], "%d-%d", &line1
, &line2
);
else {
sscanf(args
[3], "%d", &line1
);
line2 = 999;
}
annotate_margin
= (int) (atof(args
[4]) * PieceValues
(white
, pawn
)); // Pierre-Marie Baty -- added type cast
annotate_search_time_limit
= (int) (atof(args
[5]) * 100); // Pierre-Marie Baty -- added type cast
if (nargs > 6)
best_moves
= atoi(args
[6]);
else
best_moves = 1;
/*
************************************************************
* *
* Reset the game to "square 0" to start the annotation *
* procedure. Then we read moves from the input file, *
* make them on the game board, and annotate if the move *
* is for the correct side. If we haven't yet reached the *
* starting move to annotate, we skip the Search() stuff *
* and read another move. *
* *
************************************************************
*/
annotate_mode = 1;
swindle_mode = 0;
ponder = 0;
temp_search_depth = search_depth;
read_status = ReadPGN(0, 0);
read_status = ReadPGN(annotate_in, 0);
player_pv.path[1] = 0;
while (read_status != -1) {
ponder_move = 0;
last_pv.pathd = 0;
last_pv.pathl = 0;
player_pv.pathd = 0;
player_pv.pathl = 0;
tree->pv[0].pathl = 0;
tree->pv[0].pathd = 0;
analysis_printed = 0;
InitializeChessBoard(tree);
tree->status[1] = tree->status[0];
wtm = 1;
move_number = 1;
/*
************************************************************
* *
* Now grab the PGN tag values so they can be copied to *
* the .can file for reference. *
* *
************************************************************
*/
do
read_status = ReadPGN(annotate_in, 0);
while (read_status == 1);
if (read_status == -1)
break;
if (latex == 0) {
fprintf(annotate_out
, "[Event \"%s\"]%s\n", pgn_event
, html_br
);
fprintf(annotate_out
, "[Site \"%s\"]%s\n", pgn_site
, html_br
);
fprintf(annotate_out
, "[Date \"%s\"]%s\n", pgn_date
, html_br
);
fprintf(annotate_out
, "[Round \"%s\"]%s\n", pgn_round
, html_br
);
fprintf(annotate_out
, "[White \"%s\"]%s\n", pgn_white
, html_br
);
fprintf(annotate_out
, "[WhiteElo \"%s\"]%s\n", pgn_white_elo
, html_br
);
fprintf(annotate_out
, "[Black \"%s\"]%s\n", pgn_black
, html_br
);
fprintf(annotate_out
, "[BlackElo \"%s\"]%s\n", pgn_black_elo
, html_br
);
fprintf(annotate_out
, "[Result \"%s\"]%s\n", pgn_result
, html_br
);
fprintf(annotate_out
, "[Annotator \"Crafty v%s\"]%s\n", version
,
html_br);
"{annotating both black and white moves.}%s\n", html_br);
fprintf(annotate_out
, "{annotating only black moves.}%s\n",
html_br);
fprintf(annotate_out
, "{annotating only white moves.}%s\n",
html_br);
} else
fprintf(annotate_out
, "{annotating for player %s}%s\n", pname
,
html_br);
fprintf(annotate_out
, "{using a scoring margin of %s pawns.}%s\n",
DisplayEvaluationKibitz(annotate_margin, wtm), html_br);
fprintf(annotate_out
, "{search time limit is %s}%s\n%s\n",
DisplayTimeKibitz(annotate_search_time_limit), html_br, html_br);
} else {
fprintf(annotate_out
, "\\textbf{\\sc %s %s -- %s %s}%s\n", pgn_white
,
pgn_white_elo, pgn_black, pgn_black_elo, html_br);
fprintf(annotate_out
, "{\\em %s, %s}%s\n", pgn_site
, pgn_date
, html_br
);
fprintf(annotate_out
, "{\\small %s, Round: %s}%s\n", pgn_event
,
pgn_round, html_br);
fprintf(annotate_out
, "\\begin{mainline}{%s}{Crafty v%s}\n", pgn_result
,
version);
}
annotate_wtm = 1;
else if (!strcmp(colors
, "b"))
annotate_wtm = 0;
else if (!strcmp(colors
, "wb"))
annotate_wtm = 2;
else if (!strcmp(colors
, "bw"))
annotate_wtm = 2;
else {
Print(4095, "invalid color specification, retry\n");
return;
}
} else {
annotate_wtm = 1;
else if (strstr(pgn_black
, pname
))
annotate_wtm = 0;
else {
Print(4095, "Player name doesn't match any PGN name tag, retry\n");
return;
}
}
do {
move = ReadNextMove(tree, buffer, 0, wtm);
if (move <= 0)
break;
strcpy(text
, OutputMove
(tree
, 0, wtm
, move
));
if (history_file) {
fseek(history_file
, ((move_number
- 1) * 2 + 1 - wtm
) * 10, SEEK_SET
);
fprintf(history_file
, "%9s\n", text
);
}
if (wtm)
Print(4095, "White(%d): %s\n", move_number, text);
else
Print(4095, "Black(%d): %s\n", move_number, text);
if (analysis_printed)
fprintf(annotate_out
, "%3d.%s%8s\n", move_number
,
(wtm ? "" : " ..."), text);
else {
if (wtm)
fprintf(annotate_out
, "%3d.%8s", move_number
, text
);
else
fprintf(annotate_out
, "%8s\n", text
);
}
analysis_printed = 0;
if (move_number >= line1 && move_number <= line2) {
if (annotate_wtm == 2 || annotate_wtm == wtm) {
last_pv.pathd = 0;
last_pv.pathl = 0;
thinking = 1;
RootMoveList(wtm);
/*
************************************************************
* *
* Search the position to see if the move played is the *
* best move possible. If not, then search just the move *
* played to get a score for it as well, so we can *
* determine if annotated output is appropriate. *
* *
************************************************************
*/
search_time_limit = annotate_search_time_limit;
search_depth = temp_search_depth;
player_score = -999999;
search_player = 1;
for (searches_done = 0; searches_done < Abs(best_moves);
searches_done++) {
if (searches_done > 0) {
search_time_limit = 3 * annotate_search_time_limit;
search_depth = temp[0].pathd;
}
Print(4095, "\n Searching all legal moves.");
Print(4095, "----------------------------------\n");
tree->status[1] = tree->status[0];
InitializeHashTables(0);
annotate_score[searches_done] = Iterate(wtm, annotate, 1);
if (tree->pv[0].path[1] == move) {
player_score = annotate_score[searches_done];
player_pv = tree->pv[0];
search_player = 0;
}
temp[searches_done] = tree->pv[0];
for (i = 0; i < n_root_moves; i++) {
if (root_moves[i].move == tree->pv[0].path[1]) {
for (; i < n_root_moves; i++)
root_moves[i] = root_moves[i + 1];
n_root_moves--;
break;
}
}
if (n_root_moves == 0 || (annotate_margin >= 0 &&
player_score + annotate_margin >
annotate_score[searches_done]
&& best_moves > 0)) {
if (n_root_moves == 0)
searches_done++;
break;
}
}
if (search_player) {
Print(4095,
"\n Searching only the move played in game.");
Print(4095, "--------------------\n");
tree->status[1] = tree->status[0];
search_move = move;
root_moves[0].move = move;
root_moves[0].status = 0;
n_root_moves = 1;
search_time_limit = 3 * annotate_search_time_limit;
search_depth = temp[0].pathd;
if (search_depth == temp_search_depth)
search_time_limit = annotate_search_time_limit;
InitializeHashTables(0);
player_score = Iterate(wtm, annotate, 1);
player_pv = tree->pv[0];
search_depth = temp_search_depth;
search_time_limit = annotate_search_time_limit;
search_move = 0;
}
/*
************************************************************
* *
* Output the score/pv for the move played unless it *
* matches what Crafty would have played. If it doesn't *
* then output the pv for what Crafty thinks is best. *
* *
************************************************************
*/
thinking = 0;
if (player_pv.pathd > 1 && player_pv.pathl >= 1 &&
player_score + annotate_margin < annotate_score[0]
&& (temp[0].path[1] != player_pv.path[1]
|| annotate_margin < 0 || best_moves != 1)) {
if (wtm) {
analysis_printed = 1;
fprintf(annotate_out
, "%s\n", html_br
);
}
if (html_mode == 1)
AnnotatePositionHTML(tree, wtm, annotate_out);
if (latex == 1) {
AnnotatePositionTeX(tree, wtm, annotate_out);
fprintf(annotate_out
, " \\begin{variation}\\{%d:%s\\}",
player_pv.pathd, DisplayEvaluationKibitz(player_score,
wtm));
} else
player_pv.pathd, DisplayEvaluationKibitz(player_score,
wtm));
path_len = player_pv.pathl;
fprintf(annotate_out
, " %s", FormatPV
(tree
, wtm
, player_pv
));
if (latex == 1)
fprintf(annotate_out
, " %s\n \\end{variation}\n",
AnnotateVtoNAG(player_score, wtm, html_mode, latex));
else
fprintf(annotate_out
, " %s)%s\n", AnnotateVtoNAG
(player_score
,
wtm, html_mode, latex), html_br);
for (move_num = 0; move_num < searches_done; move_num++) {
if (move != temp[move_num].path[1]) {
if (latex == 1)
fprintf(annotate_out
, " \\begin{variation}\\{%d:%s\\}",
temp[move_num].pathd,
DisplayEvaluationKibitz(annotate_score[move_num], wtm));
else
temp[move_num].pathd,
DisplayEvaluationKibitz(annotate_score[move_num], wtm));
path_len = temp[move_num].pathl;
fprintf(annotate_out
, " %s", FormatPV
(tree
, wtm
,
temp[move_num]));
if (latex == 1)
fprintf(annotate_out
, " %s\n \\end{variation}\n",
AnnotateVtoNAG(annotate_score[move_num], wtm, html_mode,
latex));
else
AnnotateVtoNAG(annotate_score[move_num], wtm, html_mode,
latex), html_br);
}
}
if (html_mode == 1)
if (line2 < 0)
line2--;
}
}
}
/*
************************************************************
* *
* Before going on to the next move, see if the user has *
* included a set of other moves that require a search. *
* If so, search them one at a time and produce the ana- *
* lysis for each one. *
* *
************************************************************
*/
read_status = ReadPGN(annotate_in, 1);
while (read_status == 2) {
suggested = InputMove(tree, 0, wtm, 1, 0, buffer);
if (suggested > 0) {
thinking = 1;
Print(4095, "\n Searching only the move suggested.");
Print(4095, "--------------------\n");
tree->status[1] = tree->status[0];
search_move = suggested;
search_time_limit = 3 * annotate_search_time_limit;
search_depth = temp[0].pathd;
InitializeHashTables(0);
annotate_score[0] = Iterate(wtm, annotate, 0);
search_depth = temp_search_depth;
search_time_limit = annotate_search_time_limit;
search_move = 0;
thinking = 0;
twtm = wtm;
path_len = tree->pv[0].pathl;
if (tree->pv[0].pathd > 1 && path_len >= 1) {
if (wtm && !analysis_printed) {
analysis_printed = 1;
fprintf(annotate_out
, "%s\n", html_br
);
}
fprintf(annotate_out
, " ({suggested %d:%s}",
tree->pv[0].pathd, DisplayEvaluationKibitz(annotate_score[0],
wtm));
for (i = 1; i <= path_len; i++) {
fprintf(annotate_out
, " %s", OutputMove
(tree
, i
, twtm
,
tree->pv[0].path[i]));
MakeMove(tree, i, twtm, tree->pv[0].path[i]);
twtm = Flip(twtm);
}
for (i = path_len; i > 0; i--) {
twtm = Flip(twtm);
UnmakeMove(tree, i, twtm, tree->pv[0].path[i]);
}
AnnotateVtoNAG(annotate_score[0], wtm, html_mode, latex),
html_br);
}
}
read_status = ReadPGN(annotate_in, 1);
if (read_status != 2)
break;
}
if ((analysis_printed) && (latex == 0))
fprintf(annotate_out
, "%s\n", html_br
);
MakeMoveRoot(tree, wtm, move);
wtm = Flip(wtm);
if (wtm)
move_number++;
if (read_status != 0)
break;
if (line2 < -1)
break;
} while (1);
fprintf(annotate_out
, " %s %s\n\n", pgn_result
, html_br
);
if (html_mode == 1) {
fprintf(annotate_out
, "%s\n", html_br
);
AnnotateFooterHTML(annotate_out);
}
if (latex == 1) {
AnnotatePositionTeX(tree, wtm, annotate_out);
fprintf(annotate_out
, "\\end{mainline}\n");
fprintf(annotate_out
, "\\begin{flushright}{\\small ");
fprintf(annotate_out
, "annotating both black and white moves.%s\n",
html_br);
fprintf(annotate_out
, "annotating only black moves.%s\n", html_br
);
fprintf(annotate_out
, "annotating only white moves.%s\n", html_br
);
} else
fprintf(annotate_out
, "annotating for player %s%s\n", pname
, html_br
);
fprintf(annotate_out
, "using a scoring margin of %s pawns.%s\n",
DisplayEvaluationKibitz(annotate_margin, wtm), html_br);
fprintf(annotate_out
, "search time limit is %s%s\n",
DisplayTimeKibitz(annotate_search_time_limit), html_br);
fprintf(annotate_out
, " } \\end{flushright}");
AnnotateFooterTeX(annotate_out);
}
}
if (annotate_out)
if (annotate_in)
search_time_limit = 0;
annotate_mode = 0;
swindle_mode = save_swindle_mode;
}
/*
*******************************************************************************
* *
* These functions provide HTML output support interfaces. *
* *
*******************************************************************************
*/
void AnnotateHeaderHTML(char *title_text, FILE * annotate_out) {
"<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.0 Transitional//EN\"\n");
" \"http://www.w3.org/TR/REC-html40/loose.dtd\">\n");
fprintf(annotate_out
, "<HEAD><TITLE>%s</TITLE>\n", title_text
);
"<LINK rev=\"made\" href=\"hyatt@cis.uab.edu\"></HEAD>\n");
"<BODY BGColor=\"#ffffff\" text=\"#000000\" link=\"#0000ee\""
" vlink=\"#551a8b\">\n");
}
void AnnotateFooterHTML(FILE * annotate_out) {
fprintf(annotate_out
, "</BODY>\n");
fprintf(annotate_out
, "</HTML>\n");
}
void AnnotatePositionHTML(TREE * RESTRICT tree, int wtm, FILE * annotate_out) {
char filename[32], html_piece;
char alt[32];
int rank, file;
/* Display the board in HTML using table of images. */
fprintf(annotate_out
, "<TABLE Border=1 CellSpacing=0 CellPadding=0>\n\n");
for (rank = RANK8; rank >= RANK1; rank--) {
for (file = FILEA; file <= FILEH; file++) {
if ((rank + file) % 2)
else
html_piece = translate[PcOnSq((rank << 3) + file) + 6];
switch (html_piece) {
case 'p':
break;
case 'r':
break;
case 'n':
break;
case 'b':
break;
case 'q':
break;
case 'k':
break;
case 'P':
break;
case 'R':
break;
case 'N':
break;
case 'B':
break;
case 'Q':
break;
case 'K':
break;
default:
break;
}
fprintf(annotate_out
, "<TD><IMG ALT=\"%s\" SRC=\"%s\"></TD>\n", alt
,
filename);
}
fprintf(annotate_out
, "</TR>\n\n");
}
fprintf(annotate_out
, "</TABLE>\n");
if (wtm)
fprintf(annotate_out
, "<H2>White to move.</H2>\n");
else
fprintf(annotate_out
, "<H2>Black to move.</H2>\n");
}
/*
*******************************************************************************
* Author : Alexander Wagner *
* University of Michigan *
* Date : 03.01.04 *
* *
* Last Modified : 03.01.04 *
* *
* Based upon the HTML-Code above *
* *
* These functions provide LaTeX output capability to Crafty. *
* *
*******************************************************************************
*/
void AnnotateHeaderTeX(FILE * annotate_out) {
fprintf(annotate_out
, "\\documentclass[12pt,twocolumn]{article}\n");
fprintf(annotate_out
, "%% This is a LaTeX file generated by Crafty \n");
"%% You must have the \"chess12\" package to typeset this file.\n");
fprintf(annotate_out
, "\\usepackage{times}\n");
fprintf(annotate_out
, "\\usepackage{a4wide}\n");
fprintf(annotate_out
, "\\usepackage{chess}\n");
fprintf(annotate_out
, "\\usepackage{bdfchess}\n");
fprintf(annotate_out
, "\\usepackage[T1]{fontenc}\n");
fprintf(annotate_out
, "\\setlength{\\columnsep}{7mm}\n");
fprintf(annotate_out
, "\\setlength{\\parindent}{0pt}\n");
fprintf(annotate_out
, "%% Macros for variations and diagrams:\n");
"\\newenvironment{mainline}[2]{\\bf\\newcommand{\\result}{#1}%%\n");
fprintf(annotate_out
, "\\newcommand{\\commentator}{#2}\\begin{chess}}%%\n");
fprintf(annotate_out
, "{\\end{chess}\\finito{\\result}{\\commentator}}\n");
"\\newenvironment{variation}{[\\begingroup\\rm\\ignorespaces}%%\n");
fprintf(annotate_out
, "{\\endgroup]\\ignorespaces\\newline}\n");
"\\newcommand{\\finito}[2]{{\\bf\\hfill#1\\hfill[#2]\\par}}\n");
fprintf(annotate_out
, "\\setlength{\\parindent}{0pt}\n");
"\\newenvironment{diagram}{\\begin{nochess}}"
"{$$\\showboard$$\\end{nochess}}\n");
fprintf(annotate_out
, "\n\n\\begin{document}\n\n");
}
void AnnotateFooterTeX(FILE * annotate_out) {
fprintf(annotate_out
, "\n\n\\end{document}\n");
}
void AnnotatePositionTeX(TREE * tree, int wtm, FILE * annotate_out) {
char filename[32], html_piece;
int rank, file;
/* Display the board in LaTeX using picture notation, similar to html */
fprintf(annotate_out
, "\\begin{diagram}\n\\board\n");
for (rank = RANK8; rank >= RANK1; rank--) {
for (file = FILEA; file <= FILEH; file++) {
if ((rank + file) % 2)
else
html_piece = translate[PcOnSq((rank << 3) + file) + 6];
switch (html_piece) {
case 'p':
break;
case 'r':
break;
case 'n':
break;
case 'b':
break;
case 'q':
break;
case 'k':
break;
case 'P':
break;
case 'R':
break;
case 'N':
break;
case 'B':
break;
case 'Q':
break;
case 'K':
break;
default:
break;
}
fprintf(annotate_out
, "%s", filename
);
}
}
fprintf(annotate_out
, "\\end{diagram}\n");
fprintf(annotate_out
, "\\begin{center} \\begin{nochess}\n {\\small ");
if (wtm)
fprintf(annotate_out
, "White to move.\n");
else
fprintf(annotate_out
, "Black to move.\n");
fprintf(annotate_out
, "}\n \\end{nochess}\\end{center} \n\n");
}
char *AnnotateVtoNAG(int value, int wtm, int html_mode, int latex) {
static char buf[64];
if (!wtm)
value = -value;
if (value > MIN_DECISIVE_ADV)
strcpy(buf
, html_mode
? "+-" : "$18");
else if (value > MIN_MODERATE_ADV)
strcpy(buf
, html_mode
? "+/-" : "$16");
else if (value > MIN_SLIGHT_ADV)
strcpy(buf
, html_mode
? "+=" : "$14");
else if (value < -MIN_DECISIVE_ADV)
strcpy(buf
, html_mode
? "-+" : "$19");
else if (value < -MIN_MODERATE_ADV)
strcpy(buf
, html_mode
? "-/+" : "$17");
else if (value < -MIN_SLIGHT_ADV)
strcpy(buf
, html_mode
? "=+" : "$15");
else
strcpy(buf
, html_mode
? "=" : "$10");
if (latex == 1) {
if (value > MIN_DECISIVE_ADV)
else if (value > MIN_MODERATE_ADV)
else if (value > MIN_SLIGHT_ADV)
else if (value < -MIN_DECISIVE_ADV)
else if (value < -MIN_MODERATE_ADV)
else if (value < -MIN_SLIGHT_ADV)
else
}
return buf;
}