fruit-2.1.dfsg-1.orig/0000755000175000017500000000000010435653137014115 5ustar oliveroliverfruit-2.1.dfsg-1.orig/src/0000700000175000017500000000000010435652665014677 5ustar oliveroliverfruit-2.1.dfsg-1.orig/src/pv.h0000600000175000017500000000074010402400155015453 0ustar oliveroliver // pv.h #ifndef PV_H #define PV_H // includes #include "board.h" #include "move.h" #include "util.h" // macros #define PV_CLEAR(pv) (*(pv)=MoveNone) // functions extern bool pv_is_ok (const mv_t pv[]); extern void pv_copy (mv_t dst[], const mv_t src[]); extern void pv_cat (mv_t dst[], const mv_t src[], int move); extern bool pv_to_string (const mv_t pv[], char string[], int size); #endif // !defined PV_H // end of pv.h fruit-2.1.dfsg-1.orig/src/move_do.h0000600000175000017500000000150010402400155016451 0ustar oliveroliver // move_do.h #ifndef MOVE_DO_H #define MOVE_DO_H // includes #include "board.h" #include "util.h" // types struct undo_t { bool capture; int capture_square; int capture_piece; int capture_pos; int pawn_pos; int turn; int flags; int ep_square; int ply_nb; int cap_sq; int opening; int endgame; uint64 key; uint64 pawn_key; uint64 material_key; }; // functions extern void move_do_init (); extern void move_do (board_t * board, int move, undo_t * undo); extern void move_undo (board_t * board, int move, const undo_t * undo); extern void move_do_null (board_t * board, undo_t * undo); extern void move_undo_null (board_t * board, const undo_t * undo); #endif // !defined MOVE_DO_H // end of move_do.h fruit-2.1.dfsg-1.orig/src/search_full.cpp0000600000175000017500000007051710402400155017661 0ustar oliveroliver // search_full.cpp // includes #include "attack.h" #include "board.h" #include "colour.h" #include "eval.h" #include "list.h" #include "move.h" #include "move_check.h" #include "move_do.h" #include "option.h" #include "piece.h" #include "pst.h" #include "pv.h" #include "recog.h" #include "search.h" #include "search_full.h" #include "see.h" #include "sort.h" #include "trans.h" #include "util.h" #include "value.h" // constants and variables // main search static const bool UseDistancePruning = true; // transposition table static const bool UseTrans = true; static const int TransDepth = 1; static const bool UseMateValues = true; // use mate values from shallower searches? // null move static /* const */ bool UseNull = true; static /* const */ bool UseNullEval = true; // true static const int NullDepth = 2; static /* const */ int NullReduction = 3; static /* const */ bool UseVer = true; static /* const */ bool UseVerEndgame = true; // true static /* const */ int VerReduction = 5; // was 3 // move ordering static const bool UseIID = true; static const int IIDDepth = 3; static const int IIDReduction = 2; // extensions static const bool ExtendSingleReply = true; // true // history pruning static /* const */ bool UseHistory = true; static const int HistoryDepth = 3; static const int HistoryMoveNb = 3; static /* const */ int HistoryValue = 9830; // 60% static const bool HistoryReSearch = true; // futility pruning static /* const */ bool UseFutility = false; // false static /* const */ int FutilityMargin = 100; // quiescence search static /* const */ bool UseDelta = false; // false static /* const */ int DeltaMargin = 50; static /* const */ int CheckNb = 1; static /* const */ int CheckDepth = 0; // 1 - CheckNb // misc static const int NodeAll = -1; static const int NodePV = 0; static const int NodeCut = +1; // macros #define NODE_OPP(type) (-(type)) #define DEPTH_MATCH(d1,d2) ((d1)>=(d2)) // prototypes static int full_root (list_t * list, board_t * board, int alpha, int beta, int depth, int height, int search_type); static int full_search (board_t * board, int alpha, int beta, int depth, int height, mv_t pv[], int node_type); static int full_no_null (board_t * board, int alpha, int beta, int depth, int height, mv_t pv[], int node_type, int trans_move, int * best_move); static int full_quiescence (board_t * board, int alpha, int beta, int depth, int height, mv_t pv[]); static int full_new_depth (int depth, int move, board_t * board, bool single_reply, bool in_pv); static bool do_null (const board_t * board); static bool do_ver (const board_t * board); static void pv_fill (const mv_t pv[], board_t * board); static bool move_is_dangerous (int move, const board_t * board); static bool capture_is_dangerous (int move, const board_t * board); static bool simple_stalemate (const board_t * board); // functions // search_full_init() void search_full_init(list_t * list, board_t * board) { const char * string; int trans_move, trans_min_depth, trans_max_depth, trans_min_value, trans_max_value; ASSERT(list_is_ok(list)); ASSERT(board_is_ok(board)); // null-move options string = option_get_string("NullMove Pruning"); if (false) { } else if (my_string_equal(string,"Always")) { UseNull = true; UseNullEval = false; } else if (my_string_equal(string,"Fail High")) { UseNull = true; UseNullEval = true; } else if (my_string_equal(string,"Never")) { UseNull = false; UseNullEval = false; } else { ASSERT(false); UseNull = true; UseNullEval = true; } NullReduction = option_get_int("NullMove Reduction"); string = option_get_string("Verification Search"); if (false) { } else if (my_string_equal(string,"Always")) { UseVer = true; UseVerEndgame = false; } else if (my_string_equal(string,"Endgame")) { UseVer = true; UseVerEndgame = true; } else if (my_string_equal(string,"Never")) { UseVer = false; UseVerEndgame = false; } else { ASSERT(false); UseVer = true; UseVerEndgame = true; } VerReduction = option_get_int("Verification Reduction"); // history-pruning options UseHistory = option_get_bool("History Pruning"); HistoryValue = (option_get_int("History Threshold") * 16384 + 50) / 100; // futility-pruning options UseFutility = option_get_bool("Futility Pruning"); FutilityMargin = option_get_int("Futility Margin"); // delta-pruning options UseDelta = option_get_bool("Delta Pruning"); DeltaMargin = option_get_int("Delta Margin"); // quiescence-search options CheckNb = option_get_int("Quiescence Check Plies"); CheckDepth = 1 - CheckNb; // standard sort list_note(list); list_sort(list); // basic sort trans_move = MoveNone; if (UseTrans) trans_retrieve(Trans,board->key,&trans_move,&trans_min_depth,&trans_max_depth,&trans_min_value,&trans_max_value); note_moves(list,board,0,trans_move); list_sort(list); } // search_full_root() int search_full_root(list_t * list, board_t * board, int depth, int search_type) { int value; ASSERT(list_is_ok(list)); ASSERT(board_is_ok(board)); ASSERT(depth_is_ok(depth)); ASSERT(search_type==SearchNormal||search_type==SearchShort); ASSERT(list==SearchRoot->list); ASSERT(!LIST_IS_EMPTY(list)); ASSERT(board==SearchCurrent->board); ASSERT(board_is_legal(board)); ASSERT(depth>=1); value = full_root(list,board,-ValueInf,+ValueInf,depth,0,search_type); ASSERT(value_is_ok(value)); ASSERT(LIST_VALUE(list,0)==value); return value; } // full_root() static int full_root(list_t * list, board_t * board, int alpha, int beta, int depth, int height, int search_type) { int old_alpha; int value, best_value; int i, move; int new_depth; undo_t undo[1]; mv_t new_pv[HeightMax]; ASSERT(list_is_ok(list)); ASSERT(board_is_ok(board)); ASSERT(range_is_ok(alpha,beta)); ASSERT(depth_is_ok(depth)); ASSERT(height_is_ok(height)); ASSERT(search_type==SearchNormal||search_type==SearchShort); ASSERT(list==SearchRoot->list); ASSERT(!LIST_IS_EMPTY(list)); ASSERT(board==SearchCurrent->board); ASSERT(board_is_legal(board)); ASSERT(depth>=1); // init SearchCurrent->node_nb++; SearchInfo->check_nb--; for (i = 0; i < LIST_SIZE(list); i++) list->value[i] = ValueNone; old_alpha = alpha; best_value = ValueNone; // move loop for (i = 0; i < LIST_SIZE(list); i++) { move = LIST_MOVE(list,i); SearchRoot->depth = depth; SearchRoot->move = move; SearchRoot->move_pos = i; SearchRoot->move_nb = LIST_SIZE(list); search_update_root(); new_depth = full_new_depth(depth,move,board,board_is_check(board)&&LIST_SIZE(list)==1,true); move_do(board,move,undo); if (search_type == SearchShort || best_value == ValueNone) { // first move value = -full_search(board,-beta,-alpha,new_depth,height+1,new_pv,NodePV); } else { // other moves value = -full_search(board,-alpha-1,-alpha,new_depth,height+1,new_pv,NodeCut); if (value > alpha) { // && value < beta SearchRoot->change = true; SearchRoot->easy = false; SearchRoot->flag = false; search_update_root(); value = -full_search(board,-beta,-alpha,new_depth,height+1,new_pv,NodePV); } } move_undo(board,move,undo); if (value <= alpha) { // upper bound list->value[i] = old_alpha; } else if (value >= beta) { // lower bound list->value[i] = beta; } else { // alpha < value < beta => exact value list->value[i] = value; } if (value > best_value && (best_value == ValueNone || value > alpha)) { SearchBest->move = move; SearchBest->value = value; if (value <= alpha) { // upper bound SearchBest->flags = SearchUpper; } else if (value >= beta) { // lower bound SearchBest->flags = SearchLower; } else { // alpha < value < beta => exact value SearchBest->flags = SearchExact; } SearchBest->depth = depth; pv_cat(SearchBest->pv,new_pv,move); search_update_best(); } if (value > best_value) { best_value = value; if (value > alpha) { if (search_type == SearchNormal) alpha = value; if (value >= beta) break; } } } ASSERT(value_is_ok(best_value)); list_sort(list); ASSERT(SearchBest->move==LIST_MOVE(list,0)); ASSERT(SearchBest->value==best_value); if (UseTrans && best_value > old_alpha && best_value < beta) { pv_fill(SearchBest->pv,board); } return best_value; } // full_search() static int full_search(board_t * board, int alpha, int beta, int depth, int height, mv_t pv[], int node_type) { bool in_check; bool single_reply; int trans_move, trans_depth, trans_min_depth, trans_max_depth, trans_min_value, trans_max_value; int min_value, max_value; int old_alpha; int value, best_value; int move, best_move; int new_depth; int played_nb; int i; int opt_value; bool reduced; attack_t attack[1]; sort_t sort[1]; undo_t undo[1]; mv_t new_pv[HeightMax]; mv_t played[256]; ASSERT(board!=NULL); ASSERT(range_is_ok(alpha,beta)); ASSERT(depth_is_ok(depth)); ASSERT(height_is_ok(height)); ASSERT(pv!=NULL); ASSERT(node_type==NodePV||node_type==NodeCut||node_type==NodeAll); ASSERT(board_is_legal(board)); // horizon? if (depth <= 0) return full_quiescence(board,alpha,beta,0,height,pv); // init SearchCurrent->node_nb++; SearchInfo->check_nb--; PV_CLEAR(pv); if (height > SearchCurrent->max_depth) SearchCurrent->max_depth = height; if (SearchInfo->check_nb <= 0) { SearchInfo->check_nb += SearchInfo->check_inc; search_check(); } // draw? if (board_is_repetition(board) || recog_draw(board)) return ValueDraw; // mate-distance pruning if (UseDistancePruning) { // lower bound value = VALUE_MATE(height+2); // does not work if the current position is mate if (value > alpha && board_is_mate(board)) value = VALUE_MATE(height); if (value > alpha) { alpha = value; if (value >= beta) return value; } // upper bound value = -VALUE_MATE(height+1); if (value < beta) { beta = value; if (value <= alpha) return value; } } // transposition table trans_move = MoveNone; if (UseTrans && depth >= TransDepth) { if (trans_retrieve(Trans,board->key,&trans_move,&trans_min_depth,&trans_max_depth,&trans_min_value,&trans_max_value)) { // trans_move is now updated if (node_type != NodePV) { if (UseMateValues) { if (trans_min_value > +ValueEvalInf && trans_min_depth < depth) { trans_min_depth = depth; } if (trans_max_value < -ValueEvalInf && trans_max_depth < depth) { trans_max_depth = depth; } } min_value = -ValueInf; if (DEPTH_MATCH(trans_min_depth,depth)) { min_value = value_from_trans(trans_min_value,height); if (min_value >= beta) return min_value; } max_value = +ValueInf; if (DEPTH_MATCH(trans_max_depth,depth)) { max_value = value_from_trans(trans_max_value,height); if (max_value <= alpha) return max_value; } if (min_value == max_value) return min_value; // exact match } } } // height limit if (height >= HeightMax-1) return eval(board); // more init old_alpha = alpha; best_value = ValueNone; best_move = MoveNone; played_nb = 0; attack_set(attack,board); in_check = ATTACK_IN_CHECK(attack); // null-move pruning if (UseNull && depth >= NullDepth && node_type != NodePV) { if (!in_check && !value_is_mate(beta) && do_null(board) && (!UseNullEval || depth <= NullReduction+1 || eval(board) >= beta)) { // null-move search new_depth = depth - NullReduction - 1; move_do_null(board,undo); value = -full_search(board,-beta,-beta+1,new_depth,height+1,new_pv,NODE_OPP(node_type)); move_undo_null(board,undo); // verification search if (UseVer && depth > VerReduction) { if (value >= beta && (!UseVerEndgame || do_ver(board))) { new_depth = depth - VerReduction; ASSERT(new_depth>0); value = full_no_null(board,alpha,beta,new_depth,height,new_pv,NodeCut,trans_move,&move); if (value >= beta) { ASSERT(move==new_pv[0]); played[played_nb++] = move; best_move = move; best_value = value; pv_copy(pv,new_pv); goto cut; } } } // pruning if (value >= beta) { if (value > +ValueEvalInf) value = +ValueEvalInf; // do not return unproven mates ASSERT(!value_is_mate(value)); // pv_cat(pv,new_pv,MoveNull); best_move = MoveNone; best_value = value; goto cut; } } } // Internal Iterative Deepening if (UseIID && depth >= IIDDepth && node_type == NodePV && trans_move == MoveNone) { new_depth = depth - IIDReduction; ASSERT(new_depth>0); value = full_search(board,alpha,beta,new_depth,height,new_pv,node_type); if (value <= alpha) value = full_search(board,-ValueInf,beta,new_depth,height,new_pv,node_type); trans_move = new_pv[0]; } // move generation sort_init(sort,board,attack,depth,height,trans_move); single_reply = false; if (in_check && LIST_SIZE(sort->list) == 1) single_reply = true; // HACK // move loop opt_value = +ValueInf; while ((move=sort_next(sort)) != MoveNone) { // extensions new_depth = full_new_depth(depth,move,board,single_reply,node_type==NodePV); // history pruning reduced = false; if (UseHistory && depth >= HistoryDepth && node_type != NodePV) { if (!in_check && played_nb >= HistoryMoveNb && new_depth < depth) { ASSERT(best_value!=ValueNone); ASSERT(played_nb>0); ASSERT(sort->pos>0&&move==LIST_MOVE(sort->list,sort->pos-1)); value = sort->value; // history score if (value < HistoryValue) { ASSERT(value>=0&&value<16384); ASSERT(move!=trans_move); ASSERT(!move_is_tactical(move,board)); ASSERT(!move_is_check(move,board)); new_depth--; reduced = true; } } } // futility pruning if (UseFutility && depth == 1 && node_type != NodePV) { if (!in_check && new_depth == 0 && !move_is_tactical(move,board) && !move_is_dangerous(move,board)) { ASSERT(!move_is_check(move,board)); // optimistic evaluation if (opt_value == +ValueInf) { opt_value = eval(board) + FutilityMargin; ASSERT(opt_value<+ValueInf); } value = opt_value; // pruning if (value <= alpha) { if (value > best_value) { best_value = value; PV_CLEAR(pv); } continue; } } } // recursive search move_do(board,move,undo); if (node_type != NodePV || best_value == ValueNone) { // first move value = -full_search(board,-beta,-alpha,new_depth,height+1,new_pv,NODE_OPP(node_type)); } else { // other moves value = -full_search(board,-alpha-1,-alpha,new_depth,height+1,new_pv,NodeCut); if (value > alpha) { // && value < beta value = -full_search(board,-beta,-alpha,new_depth,height+1,new_pv,NodePV); } } // history-pruning re-search if (HistoryReSearch && reduced && value >= beta) { ASSERT(node_type!=NodePV); new_depth++; ASSERT(new_depth==depth-1); value = -full_search(board,-beta,-alpha,new_depth,height+1,new_pv,NODE_OPP(node_type)); } move_undo(board,move,undo); played[played_nb++] = move; if (value > best_value) { best_value = value; pv_cat(pv,new_pv,move); if (value > alpha) { alpha = value; best_move = move; if (value >= beta) goto cut; } } if (node_type == NodeCut) node_type = NodeAll; } // ALL node if (best_value == ValueNone) { // no legal move if (in_check) { ASSERT(board_is_mate(board)); return VALUE_MATE(height); } else { ASSERT(board_is_stalemate(board)); return ValueDraw; } } cut: ASSERT(value_is_ok(best_value)); // move ordering if (best_move != MoveNone) { good_move(best_move,board,depth,height); if (best_value >= beta && !move_is_tactical(best_move,board)) { ASSERT(played_nb>0&&played[played_nb-1]==best_move); for (i = 0; i < played_nb-1; i++) { move = played[i]; ASSERT(move!=best_move); history_bad(move,board); } history_good(best_move,board); } } // transposition table if (UseTrans && depth >= TransDepth) { trans_move = best_move; trans_depth = depth; trans_min_value = (best_value > old_alpha) ? value_to_trans(best_value,height) : -ValueInf; trans_max_value = (best_value < beta) ? value_to_trans(best_value,height) : +ValueInf; trans_store(Trans,board->key,trans_move,trans_depth,trans_min_value,trans_max_value); } return best_value; } // full_no_null() static int full_no_null(board_t * board, int alpha, int beta, int depth, int height, mv_t pv[], int node_type, int trans_move, int * best_move) { int value, best_value; int move; int new_depth; attack_t attack[1]; sort_t sort[1]; undo_t undo[1]; mv_t new_pv[HeightMax]; ASSERT(board!=NULL); ASSERT(range_is_ok(alpha,beta)); ASSERT(depth_is_ok(depth)); ASSERT(height_is_ok(height)); ASSERT(pv!=NULL); ASSERT(node_type==NodePV||node_type==NodeCut||node_type==NodeAll); ASSERT(trans_move==MoveNone||move_is_ok(trans_move)); ASSERT(best_move!=NULL); ASSERT(board_is_legal(board)); ASSERT(!board_is_check(board)); ASSERT(depth>=1); // init SearchCurrent->node_nb++; SearchInfo->check_nb--; PV_CLEAR(pv); if (height > SearchCurrent->max_depth) SearchCurrent->max_depth = height; if (SearchInfo->check_nb <= 0) { SearchInfo->check_nb += SearchInfo->check_inc; search_check(); } attack_set(attack,board); ASSERT(!ATTACK_IN_CHECK(attack)); *best_move = MoveNone; best_value = ValueNone; // move loop sort_init(sort,board,attack,depth,height,trans_move); while ((move=sort_next(sort)) != MoveNone) { new_depth = full_new_depth(depth,move,board,false,false); move_do(board,move,undo); value = -full_search(board,-beta,-alpha,new_depth,height+1,new_pv,NODE_OPP(node_type)); move_undo(board,move,undo); if (value > best_value) { best_value = value; pv_cat(pv,new_pv,move); if (value > alpha) { alpha = value; *best_move = move; if (value >= beta) goto cut; } } } // ALL node if (best_value == ValueNone) { // no legal move => stalemate ASSERT(board_is_stalemate(board)); best_value = ValueDraw; } cut: ASSERT(value_is_ok(best_value)); return best_value; } // full_quiescence() static int full_quiescence(board_t * board, int alpha, int beta, int depth, int height, mv_t pv[]) { bool in_check; int old_alpha; int value, best_value; int best_move; int move; int opt_value; attack_t attack[1]; sort_t sort[1]; undo_t undo[1]; mv_t new_pv[HeightMax]; ASSERT(board!=NULL); ASSERT(range_is_ok(alpha,beta)); ASSERT(depth_is_ok(depth)); ASSERT(height_is_ok(height)); ASSERT(pv!=NULL); ASSERT(board_is_legal(board)); ASSERT(depth<=0); // init SearchCurrent->node_nb++; SearchInfo->check_nb--; PV_CLEAR(pv); if (height > SearchCurrent->max_depth) SearchCurrent->max_depth = height; if (SearchInfo->check_nb <= 0) { SearchInfo->check_nb += SearchInfo->check_inc; search_check(); } // draw? if (board_is_repetition(board) || recog_draw(board)) return ValueDraw; // mate-distance pruning if (UseDistancePruning) { // lower bound value = VALUE_MATE(height+2); // does not work if the current position is mate if (value > alpha && board_is_mate(board)) value = VALUE_MATE(height); if (value > alpha) { alpha = value; if (value >= beta) return value; } // upper bound value = -VALUE_MATE(height+1); if (value < beta) { beta = value; if (value <= alpha) return value; } } // more init attack_set(attack,board); in_check = ATTACK_IN_CHECK(attack); if (in_check) { ASSERT(depth<0); depth++; // in-check extension } // height limit if (height >= HeightMax-1) return eval(board); // more init old_alpha = alpha; best_value = ValueNone; best_move = MoveNone; /* if (UseDelta) */ opt_value = +ValueInf; if (!in_check) { // lone-king stalemate? if (simple_stalemate(board)) return ValueDraw; // stand pat value = eval(board); ASSERT(value>best_value); best_value = value; if (value > alpha) { alpha = value; if (value >= beta) goto cut; } if (UseDelta) { opt_value = value + DeltaMargin; ASSERT(opt_value<+ValueInf); } } // move loop sort_init_qs(sort,board,attack,depth>=CheckDepth); while ((move=sort_next_qs(sort)) != MoveNone) { // delta pruning if (UseDelta && beta == old_alpha+1) { if (!in_check && !move_is_check(move,board) && !capture_is_dangerous(move,board)) { ASSERT(move_is_tactical(move,board)); // optimistic evaluation value = opt_value; int to = MOVE_TO(move); int capture = board->square[to]; if (capture != Empty) { value += VALUE_PIECE(capture); } else if (MOVE_IS_EN_PASSANT(move)) { value += ValuePawn; } if (MOVE_IS_PROMOTE(move)) value += ValueQueen - ValuePawn; // pruning if (value <= alpha) { if (value > best_value) { best_value = value; PV_CLEAR(pv); } continue; } } } move_do(board,move,undo); value = -full_quiescence(board,-beta,-alpha,depth-1,height+1,new_pv); move_undo(board,move,undo); if (value > best_value) { best_value = value; pv_cat(pv,new_pv,move); if (value > alpha) { alpha = value; best_move = move; if (value >= beta) goto cut; } } } // ALL node if (best_value == ValueNone) { // no legal move ASSERT(board_is_mate(board)); return VALUE_MATE(height); } cut: ASSERT(value_is_ok(best_value)); return best_value; } // full_new_depth() static int full_new_depth(int depth, int move, board_t * board, bool single_reply, bool in_pv) { int new_depth; ASSERT(depth_is_ok(depth)); ASSERT(move_is_ok(move)); ASSERT(board!=NULL); ASSERT(single_reply==true||single_reply==false); ASSERT(in_pv==true||in_pv==false); ASSERT(depth>0); new_depth = depth - 1; if ((single_reply && ExtendSingleReply) || (in_pv && MOVE_TO(move) == board->cap_sq // recapture && see_move(move,board) > 0) || (in_pv && PIECE_IS_PAWN(MOVE_PIECE(move,board)) && PAWN_RANK(MOVE_TO(move),board->turn) == Rank7 && see_move(move,board) >= 0) || move_is_check(move,board)) { new_depth++; } ASSERT(new_depth>=0&&new_depth<=depth); return new_depth; } // do_null() static bool do_null(const board_t * board) { ASSERT(board!=NULL); // use null move if the side-to-move has at least one piece return board->piece_size[board->turn] >= 2; // king + one piece } // do_ver() static bool do_ver(const board_t * board) { ASSERT(board!=NULL); // use verification if the side-to-move has at most one piece return board->piece_size[board->turn] <= 2; // king + one piece } // pv_fill() static void pv_fill(const mv_t pv[], board_t * board) { int move; int trans_move, trans_depth, trans_min_value, trans_max_value; undo_t undo[1]; ASSERT(pv!=NULL); ASSERT(board!=NULL); ASSERT(UseTrans); move = *pv; if (move != MoveNone && move != MoveNull) { move_do(board,move,undo); pv_fill(pv+1,board); move_undo(board,move,undo); trans_move = move; trans_depth = -127; // HACK trans_min_value = -ValueInf; trans_max_value = +ValueInf; trans_store(Trans,board->key,trans_move,trans_depth,trans_min_value,trans_max_value); } } // move_is_dangerous() static bool move_is_dangerous(int move, const board_t * board) { int piece; ASSERT(move_is_ok(move)); ASSERT(board!=NULL); ASSERT(!move_is_tactical(move,board)); piece = MOVE_PIECE(move,board); if (PIECE_IS_PAWN(piece) && PAWN_RANK(MOVE_TO(move),board->turn) >= Rank7) { return true; } return false; } // capture_is_dangerous() static bool capture_is_dangerous(int move, const board_t * board) { int piece, capture; ASSERT(move_is_ok(move)); ASSERT(board!=NULL); ASSERT(move_is_tactical(move,board)); piece = MOVE_PIECE(move,board); if (PIECE_IS_PAWN(piece) && PAWN_RANK(MOVE_TO(move),board->turn) >= Rank7) { return true; } capture = move_capture(move,board); if (PIECE_IS_QUEEN(capture)) return true; if (PIECE_IS_PAWN(capture) && PAWN_RANK(MOVE_TO(move),board->turn) <= Rank2) { return true; } return false; } // simple_stalemate() static bool simple_stalemate(const board_t * board) { int me, opp; int king; int opp_flag; int from, to; int capture; const inc_t * inc_ptr; int inc; ASSERT(board!=NULL); ASSERT(board_is_legal(board)); ASSERT(!board_is_check(board)); // lone king? me = board->turn; if (board->piece_size[me] != 1 || board->pawn_size[me] != 0) return false; // no // king in a corner? king = KING_POS(board,me); if (king != A1 && king != H1 && king != A8 && king != H8) return false; // no // init opp = COLOUR_OPP(me); opp_flag = COLOUR_FLAG(opp); // king can move? from = king; for (inc_ptr = KingInc; (inc=*inc_ptr) != IncNone; inc_ptr++) { to = from + inc; capture = board->square[to]; if (capture == Empty || FLAG_IS(capture,opp_flag)) { if (!is_attacked(board,to,opp)) return false; // legal king move } } // no legal move ASSERT(board_is_stalemate((board_t*)board)); return true; } // end of search_full.cpp fruit-2.1.dfsg-1.orig/src/list.cpp0000600000175000017500000000561010402400155016335 0ustar oliveroliver // list.cpp // includes #include "board.h" #include "list.h" #include "move.h" #include "util.h" #include "value.h" // constants static const bool UseStrict = true; // functions // list_is_ok() bool list_is_ok(const list_t * list) { if (list == NULL) return false; if (list->size < 0 || list->size >= ListSize) return false; return true; } // list_remove() void list_remove(list_t * list, int pos) { int i; ASSERT(list_is_ok(list)); ASSERT(pos>=0&&possize); for (i = pos; i < list->size-1; i++) { list->move[i] = list->move[i+1]; list->value[i] = list->value[i+1]; } list->size--; } // list_copy() void list_copy(list_t * dst, const list_t * src) { int i; ASSERT(dst!=NULL); ASSERT(list_is_ok(src)); dst->size = src->size; for (i = 0; i < src->size; i++) { dst->move[i] = src->move[i]; dst->value[i] = src->value[i]; } } // list_sort() void list_sort(list_t * list) { int size; int i, j; int move, value; ASSERT(list_is_ok(list)); // init size = list->size; list->value[size] = -32768; // HACK: sentinel // insert sort (stable) for (i = size-2; i >= 0; i--) { move = list->move[i]; value = list->value[i]; for (j = i; value < list->value[j+1]; j++) { list->move[j] = list->move[j+1]; list->value[j] = list->value[j+1]; } ASSERT(jmove[j] = move; list->value[j] = value; } // debug if (DEBUG) { for (i = 0; i < size-1; i++) { ASSERT(list->value[i]>=list->value[i+1]); } } } // list_contain() bool list_contain(const list_t * list, int move) { int i; ASSERT(list_is_ok(list)); ASSERT(move_is_ok(move)); for (i = 0; i < list->size; i++) { if (list->move[i] == move) return true; } return false; } // list_note() void list_note(list_t * list) { int i, move; ASSERT(list_is_ok(list)); for (i = 0; i < list->size; i++) { move = list->move[i]; ASSERT(move_is_ok(move)); list->value[i] = -move_order(move); } } // list_filter() void list_filter(list_t * list, board_t * board, move_test_t test, bool keep) { int pos; int i, move, value; ASSERT(list!=NULL); ASSERT(board!=NULL); ASSERT(test!=NULL); ASSERT(keep==true||keep==false); pos = 0; for (i = 0; i < LIST_SIZE(list); i++) { ASSERT(pos>=0&&pos<=i); move = LIST_MOVE(list,i); value = LIST_VALUE(list,i); if ((*test)(move,board) == keep) { list->move[pos] = move; list->value[pos] = value; pos++; } } ASSERT(pos>=0&&pos<=LIST_SIZE(list)); list->size = pos; // debug ASSERT(list_is_ok(list)); } // end of list.cpp fruit-2.1.dfsg-1.orig/src/Makefile0000600000175000017500000000152110402400155016313 0ustar oliveroliver # files EXE = fruit OBJS = attack.o board.o book.o eval.o fen.o hash.o list.o main.o material.o \ move.o move_check.o move_do.o move_evasion.o move_gen.o move_legal.o \ option.o pawn.o piece.o posix.o protocol.o pst.o pv.o random.o recog.o \ search.o search_full.o see.o sort.o square.o trans.o util.o value.o \ vector.o # rules all: $(EXE) .depend clean: $(RM) *.o .depend gmon.out # general CXX = g++ CXXFLAGS = -pipe LDFLAGS = -lm # C++ CXXFLAGS += -fno-exceptions -fno-rtti # optimisation CXXFLAGS += -O3 -fstrict-aliasing CXXFLAGS += -fomit-frame-pointer # CXXFLAGS += -march=athlon-xp # SELECT ME # strip LDFLAGS += -s # dependencies $(EXE): $(OBJS) $(CXX) $(LDFLAGS) -o $@ $(OBJS) .depend: $(CXX) -MM $(OBJS:.o=.cpp) > $@ include .depend fruit-2.1.dfsg-1.orig/src/random.cpp0000600000175000017500000005031410402400155016643 0ustar oliveroliver // random.cpp // includes #include "random.h" #include "util.h" // "constants" const uint64 Random64[RandomNb] = { U64(0x9D39247E33776D41), U64(0x2AF7398005AAA5C7), U64(0x44DB015024623547), U64(0x9C15F73E62A76AE2), U64(0x75834465489C0C89), U64(0x3290AC3A203001BF), U64(0x0FBBAD1F61042279), U64(0xE83A908FF2FB60CA), U64(0x0D7E765D58755C10), U64(0x1A083822CEAFE02D), U64(0x9605D5F0E25EC3B0), U64(0xD021FF5CD13A2ED5), U64(0x40BDF15D4A672E32), U64(0x011355146FD56395), U64(0x5DB4832046F3D9E5), U64(0x239F8B2D7FF719CC), U64(0x05D1A1AE85B49AA1), U64(0x679F848F6E8FC971), U64(0x7449BBFF801FED0B), U64(0x7D11CDB1C3B7ADF0), U64(0x82C7709E781EB7CC), U64(0xF3218F1C9510786C), U64(0x331478F3AF51BBE6), U64(0x4BB38DE5E7219443), U64(0xAA649C6EBCFD50FC), U64(0x8DBD98A352AFD40B), U64(0x87D2074B81D79217), U64(0x19F3C751D3E92AE1), U64(0xB4AB30F062B19ABF), U64(0x7B0500AC42047AC4), U64(0xC9452CA81A09D85D), U64(0x24AA6C514DA27500), U64(0x4C9F34427501B447), U64(0x14A68FD73C910841), U64(0xA71B9B83461CBD93), U64(0x03488B95B0F1850F), U64(0x637B2B34FF93C040), U64(0x09D1BC9A3DD90A94), U64(0x3575668334A1DD3B), U64(0x735E2B97A4C45A23), U64(0x18727070F1BD400B), U64(0x1FCBACD259BF02E7), U64(0xD310A7C2CE9B6555), U64(0xBF983FE0FE5D8244), U64(0x9F74D14F7454A824), U64(0x51EBDC4AB9BA3035), U64(0x5C82C505DB9AB0FA), U64(0xFCF7FE8A3430B241), U64(0x3253A729B9BA3DDE), U64(0x8C74C368081B3075), U64(0xB9BC6C87167C33E7), U64(0x7EF48F2B83024E20), U64(0x11D505D4C351BD7F), U64(0x6568FCA92C76A243), U64(0x4DE0B0F40F32A7B8), U64(0x96D693460CC37E5D), U64(0x42E240CB63689F2F), U64(0x6D2BDCDAE2919661), U64(0x42880B0236E4D951), U64(0x5F0F4A5898171BB6), U64(0x39F890F579F92F88), U64(0x93C5B5F47356388B), U64(0x63DC359D8D231B78), U64(0xEC16CA8AEA98AD76), U64(0x5355F900C2A82DC7), U64(0x07FB9F855A997142), U64(0x5093417AA8A7ED5E), U64(0x7BCBC38DA25A7F3C), U64(0x19FC8A768CF4B6D4), U64(0x637A7780DECFC0D9), U64(0x8249A47AEE0E41F7), U64(0x79AD695501E7D1E8), U64(0x14ACBAF4777D5776), U64(0xF145B6BECCDEA195), U64(0xDABF2AC8201752FC), U64(0x24C3C94DF9C8D3F6), U64(0xBB6E2924F03912EA), U64(0x0CE26C0B95C980D9), U64(0xA49CD132BFBF7CC4), U64(0xE99D662AF4243939), U64(0x27E6AD7891165C3F), U64(0x8535F040B9744FF1), U64(0x54B3F4FA5F40D873), U64(0x72B12C32127FED2B), U64(0xEE954D3C7B411F47), U64(0x9A85AC909A24EAA1), U64(0x70AC4CD9F04F21F5), U64(0xF9B89D3E99A075C2), U64(0x87B3E2B2B5C907B1), U64(0xA366E5B8C54F48B8), U64(0xAE4A9346CC3F7CF2), U64(0x1920C04D47267BBD), U64(0x87BF02C6B49E2AE9), U64(0x092237AC237F3859), U64(0xFF07F64EF8ED14D0), U64(0x8DE8DCA9F03CC54E), U64(0x9C1633264DB49C89), U64(0xB3F22C3D0B0B38ED), U64(0x390E5FB44D01144B), U64(0x5BFEA5B4712768E9), U64(0x1E1032911FA78984), U64(0x9A74ACB964E78CB3), U64(0x4F80F7A035DAFB04), U64(0x6304D09A0B3738C4), U64(0x2171E64683023A08), U64(0x5B9B63EB9CEFF80C), U64(0x506AACF489889342), U64(0x1881AFC9A3A701D6), U64(0x6503080440750644), U64(0xDFD395339CDBF4A7), U64(0xEF927DBCF00C20F2), U64(0x7B32F7D1E03680EC), U64(0xB9FD7620E7316243), U64(0x05A7E8A57DB91B77), U64(0xB5889C6E15630A75), U64(0x4A750A09CE9573F7), U64(0xCF464CEC899A2F8A), U64(0xF538639CE705B824), U64(0x3C79A0FF5580EF7F), U64(0xEDE6C87F8477609D), U64(0x799E81F05BC93F31), U64(0x86536B8CF3428A8C), U64(0x97D7374C60087B73), U64(0xA246637CFF328532), U64(0x043FCAE60CC0EBA0), U64(0x920E449535DD359E), U64(0x70EB093B15B290CC), U64(0x73A1921916591CBD), U64(0x56436C9FE1A1AA8D), U64(0xEFAC4B70633B8F81), U64(0xBB215798D45DF7AF), U64(0x45F20042F24F1768), U64(0x930F80F4E8EB7462), U64(0xFF6712FFCFD75EA1), U64(0xAE623FD67468AA70), U64(0xDD2C5BC84BC8D8FC), U64(0x7EED120D54CF2DD9), U64(0x22FE545401165F1C), U64(0xC91800E98FB99929), U64(0x808BD68E6AC10365), U64(0xDEC468145B7605F6), U64(0x1BEDE3A3AEF53302), U64(0x43539603D6C55602), U64(0xAA969B5C691CCB7A), U64(0xA87832D392EFEE56), U64(0x65942C7B3C7E11AE), U64(0xDED2D633CAD004F6), U64(0x21F08570F420E565), U64(0xB415938D7DA94E3C), U64(0x91B859E59ECB6350), U64(0x10CFF333E0ED804A), U64(0x28AED140BE0BB7DD), U64(0xC5CC1D89724FA456), U64(0x5648F680F11A2741), U64(0x2D255069F0B7DAB3), U64(0x9BC5A38EF729ABD4), U64(0xEF2F054308F6A2BC), U64(0xAF2042F5CC5C2858), U64(0x480412BAB7F5BE2A), U64(0xAEF3AF4A563DFE43), U64(0x19AFE59AE451497F), U64(0x52593803DFF1E840), U64(0xF4F076E65F2CE6F0), U64(0x11379625747D5AF3), U64(0xBCE5D2248682C115), U64(0x9DA4243DE836994F), U64(0x066F70B33FE09017), U64(0x4DC4DE189B671A1C), U64(0x51039AB7712457C3), U64(0xC07A3F80C31FB4B4), U64(0xB46EE9C5E64A6E7C), U64(0xB3819A42ABE61C87), U64(0x21A007933A522A20), U64(0x2DF16F761598AA4F), U64(0x763C4A1371B368FD), U64(0xF793C46702E086A0), U64(0xD7288E012AEB8D31), U64(0xDE336A2A4BC1C44B), U64(0x0BF692B38D079F23), U64(0x2C604A7A177326B3), U64(0x4850E73E03EB6064), U64(0xCFC447F1E53C8E1B), U64(0xB05CA3F564268D99), U64(0x9AE182C8BC9474E8), U64(0xA4FC4BD4FC5558CA), U64(0xE755178D58FC4E76), U64(0x69B97DB1A4C03DFE), U64(0xF9B5B7C4ACC67C96), U64(0xFC6A82D64B8655FB), U64(0x9C684CB6C4D24417), U64(0x8EC97D2917456ED0), U64(0x6703DF9D2924E97E), U64(0xC547F57E42A7444E), U64(0x78E37644E7CAD29E), U64(0xFE9A44E9362F05FA), U64(0x08BD35CC38336615), U64(0x9315E5EB3A129ACE), U64(0x94061B871E04DF75), U64(0xDF1D9F9D784BA010), U64(0x3BBA57B68871B59D), U64(0xD2B7ADEEDED1F73F), U64(0xF7A255D83BC373F8), U64(0xD7F4F2448C0CEB81), U64(0xD95BE88CD210FFA7), U64(0x336F52F8FF4728E7), U64(0xA74049DAC312AC71), U64(0xA2F61BB6E437FDB5), U64(0x4F2A5CB07F6A35B3), U64(0x87D380BDA5BF7859), U64(0x16B9F7E06C453A21), U64(0x7BA2484C8A0FD54E), U64(0xF3A678CAD9A2E38C), U64(0x39B0BF7DDE437BA2), U64(0xFCAF55C1BF8A4424), U64(0x18FCF680573FA594), U64(0x4C0563B89F495AC3), U64(0x40E087931A00930D), U64(0x8CFFA9412EB642C1), U64(0x68CA39053261169F), U64(0x7A1EE967D27579E2), U64(0x9D1D60E5076F5B6F), U64(0x3810E399B6F65BA2), U64(0x32095B6D4AB5F9B1), U64(0x35CAB62109DD038A), U64(0xA90B24499FCFAFB1), U64(0x77A225A07CC2C6BD), U64(0x513E5E634C70E331), U64(0x4361C0CA3F692F12), U64(0xD941ACA44B20A45B), U64(0x528F7C8602C5807B), U64(0x52AB92BEB9613989), U64(0x9D1DFA2EFC557F73), U64(0x722FF175F572C348), U64(0x1D1260A51107FE97), U64(0x7A249A57EC0C9BA2), U64(0x04208FE9E8F7F2D6), U64(0x5A110C6058B920A0), U64(0x0CD9A497658A5698), U64(0x56FD23C8F9715A4C), U64(0x284C847B9D887AAE), U64(0x04FEABFBBDB619CB), U64(0x742E1E651C60BA83), U64(0x9A9632E65904AD3C), U64(0x881B82A13B51B9E2), U64(0x506E6744CD974924), U64(0xB0183DB56FFC6A79), U64(0x0ED9B915C66ED37E), U64(0x5E11E86D5873D484), U64(0xF678647E3519AC6E), U64(0x1B85D488D0F20CC5), U64(0xDAB9FE6525D89021), U64(0x0D151D86ADB73615), U64(0xA865A54EDCC0F019), U64(0x93C42566AEF98FFB), U64(0x99E7AFEABE000731), U64(0x48CBFF086DDF285A), U64(0x7F9B6AF1EBF78BAF), U64(0x58627E1A149BBA21), U64(0x2CD16E2ABD791E33), U64(0xD363EFF5F0977996), U64(0x0CE2A38C344A6EED), U64(0x1A804AADB9CFA741), U64(0x907F30421D78C5DE), U64(0x501F65EDB3034D07), U64(0x37624AE5A48FA6E9), U64(0x957BAF61700CFF4E), U64(0x3A6C27934E31188A), U64(0xD49503536ABCA345), U64(0x088E049589C432E0), U64(0xF943AEE7FEBF21B8), U64(0x6C3B8E3E336139D3), U64(0x364F6FFA464EE52E), U64(0xD60F6DCEDC314222), U64(0x56963B0DCA418FC0), U64(0x16F50EDF91E513AF), U64(0xEF1955914B609F93), U64(0x565601C0364E3228), U64(0xECB53939887E8175), U64(0xBAC7A9A18531294B), U64(0xB344C470397BBA52), U64(0x65D34954DAF3CEBD), U64(0xB4B81B3FA97511E2), U64(0xB422061193D6F6A7), U64(0x071582401C38434D), U64(0x7A13F18BBEDC4FF5), U64(0xBC4097B116C524D2), U64(0x59B97885E2F2EA28), U64(0x99170A5DC3115544), U64(0x6F423357E7C6A9F9), U64(0x325928EE6E6F8794), U64(0xD0E4366228B03343), U64(0x565C31F7DE89EA27), U64(0x30F5611484119414), U64(0xD873DB391292ED4F), U64(0x7BD94E1D8E17DEBC), U64(0xC7D9F16864A76E94), U64(0x947AE053EE56E63C), U64(0xC8C93882F9475F5F), U64(0x3A9BF55BA91F81CA), U64(0xD9A11FBB3D9808E4), U64(0x0FD22063EDC29FCA), U64(0xB3F256D8ACA0B0B9), U64(0xB03031A8B4516E84), U64(0x35DD37D5871448AF), U64(0xE9F6082B05542E4E), U64(0xEBFAFA33D7254B59), U64(0x9255ABB50D532280), U64(0xB9AB4CE57F2D34F3), U64(0x693501D628297551), U64(0xC62C58F97DD949BF), U64(0xCD454F8F19C5126A), U64(0xBBE83F4ECC2BDECB), U64(0xDC842B7E2819E230), U64(0xBA89142E007503B8), U64(0xA3BC941D0A5061CB), U64(0xE9F6760E32CD8021), U64(0x09C7E552BC76492F), U64(0x852F54934DA55CC9), U64(0x8107FCCF064FCF56), U64(0x098954D51FFF6580), U64(0x23B70EDB1955C4BF), U64(0xC330DE426430F69D), U64(0x4715ED43E8A45C0A), U64(0xA8D7E4DAB780A08D), U64(0x0572B974F03CE0BB), U64(0xB57D2E985E1419C7), U64(0xE8D9ECBE2CF3D73F), U64(0x2FE4B17170E59750), U64(0x11317BA87905E790), U64(0x7FBF21EC8A1F45EC), U64(0x1725CABFCB045B00), U64(0x964E915CD5E2B207), U64(0x3E2B8BCBF016D66D), U64(0xBE7444E39328A0AC), U64(0xF85B2B4FBCDE44B7), U64(0x49353FEA39BA63B1), U64(0x1DD01AAFCD53486A), U64(0x1FCA8A92FD719F85), U64(0xFC7C95D827357AFA), U64(0x18A6A990C8B35EBD), U64(0xCCCB7005C6B9C28D), U64(0x3BDBB92C43B17F26), U64(0xAA70B5B4F89695A2), U64(0xE94C39A54A98307F), U64(0xB7A0B174CFF6F36E), U64(0xD4DBA84729AF48AD), U64(0x2E18BC1AD9704A68), U64(0x2DE0966DAF2F8B1C), U64(0xB9C11D5B1E43A07E), U64(0x64972D68DEE33360), U64(0x94628D38D0C20584), U64(0xDBC0D2B6AB90A559), U64(0xD2733C4335C6A72F), U64(0x7E75D99D94A70F4D), U64(0x6CED1983376FA72B), U64(0x97FCAACBF030BC24), U64(0x7B77497B32503B12), U64(0x8547EDDFB81CCB94), U64(0x79999CDFF70902CB), U64(0xCFFE1939438E9B24), U64(0x829626E3892D95D7), U64(0x92FAE24291F2B3F1), U64(0x63E22C147B9C3403), U64(0xC678B6D860284A1C), U64(0x5873888850659AE7), U64(0x0981DCD296A8736D), U64(0x9F65789A6509A440), U64(0x9FF38FED72E9052F), U64(0xE479EE5B9930578C), U64(0xE7F28ECD2D49EECD), U64(0x56C074A581EA17FE), U64(0x5544F7D774B14AEF), U64(0x7B3F0195FC6F290F), U64(0x12153635B2C0CF57), U64(0x7F5126DBBA5E0CA7), U64(0x7A76956C3EAFB413), U64(0x3D5774A11D31AB39), U64(0x8A1B083821F40CB4), U64(0x7B4A38E32537DF62), U64(0x950113646D1D6E03), U64(0x4DA8979A0041E8A9), U64(0x3BC36E078F7515D7), U64(0x5D0A12F27AD310D1), U64(0x7F9D1A2E1EBE1327), U64(0xDA3A361B1C5157B1), U64(0xDCDD7D20903D0C25), U64(0x36833336D068F707), U64(0xCE68341F79893389), U64(0xAB9090168DD05F34), U64(0x43954B3252DC25E5), U64(0xB438C2B67F98E5E9), U64(0x10DCD78E3851A492), U64(0xDBC27AB5447822BF), U64(0x9B3CDB65F82CA382), U64(0xB67B7896167B4C84), U64(0xBFCED1B0048EAC50), U64(0xA9119B60369FFEBD), U64(0x1FFF7AC80904BF45), U64(0xAC12FB171817EEE7), U64(0xAF08DA9177DDA93D), U64(0x1B0CAB936E65C744), U64(0xB559EB1D04E5E932), U64(0xC37B45B3F8D6F2BA), U64(0xC3A9DC228CAAC9E9), U64(0xF3B8B6675A6507FF), U64(0x9FC477DE4ED681DA), U64(0x67378D8ECCEF96CB), U64(0x6DD856D94D259236), U64(0xA319CE15B0B4DB31), U64(0x073973751F12DD5E), U64(0x8A8E849EB32781A5), U64(0xE1925C71285279F5), U64(0x74C04BF1790C0EFE), U64(0x4DDA48153C94938A), U64(0x9D266D6A1CC0542C), U64(0x7440FB816508C4FE), U64(0x13328503DF48229F), U64(0xD6BF7BAEE43CAC40), U64(0x4838D65F6EF6748F), U64(0x1E152328F3318DEA), U64(0x8F8419A348F296BF), U64(0x72C8834A5957B511), U64(0xD7A023A73260B45C), U64(0x94EBC8ABCFB56DAE), U64(0x9FC10D0F989993E0), U64(0xDE68A2355B93CAE6), U64(0xA44CFE79AE538BBE), U64(0x9D1D84FCCE371425), U64(0x51D2B1AB2DDFB636), U64(0x2FD7E4B9E72CD38C), U64(0x65CA5B96B7552210), U64(0xDD69A0D8AB3B546D), U64(0x604D51B25FBF70E2), U64(0x73AA8A564FB7AC9E), U64(0x1A8C1E992B941148), U64(0xAAC40A2703D9BEA0), U64(0x764DBEAE7FA4F3A6), U64(0x1E99B96E70A9BE8B), U64(0x2C5E9DEB57EF4743), U64(0x3A938FEE32D29981), U64(0x26E6DB8FFDF5ADFE), U64(0x469356C504EC9F9D), U64(0xC8763C5B08D1908C), U64(0x3F6C6AF859D80055), U64(0x7F7CC39420A3A545), U64(0x9BFB227EBDF4C5CE), U64(0x89039D79D6FC5C5C), U64(0x8FE88B57305E2AB6), U64(0xA09E8C8C35AB96DE), U64(0xFA7E393983325753), U64(0xD6B6D0ECC617C699), U64(0xDFEA21EA9E7557E3), U64(0xB67C1FA481680AF8), U64(0xCA1E3785A9E724E5), U64(0x1CFC8BED0D681639), U64(0xD18D8549D140CAEA), U64(0x4ED0FE7E9DC91335), U64(0xE4DBF0634473F5D2), U64(0x1761F93A44D5AEFE), U64(0x53898E4C3910DA55), U64(0x734DE8181F6EC39A), U64(0x2680B122BAA28D97), U64(0x298AF231C85BAFAB), U64(0x7983EED3740847D5), U64(0x66C1A2A1A60CD889), U64(0x9E17E49642A3E4C1), U64(0xEDB454E7BADC0805), U64(0x50B704CAB602C329), U64(0x4CC317FB9CDDD023), U64(0x66B4835D9EAFEA22), U64(0x219B97E26FFC81BD), U64(0x261E4E4C0A333A9D), U64(0x1FE2CCA76517DB90), U64(0xD7504DFA8816EDBB), U64(0xB9571FA04DC089C8), U64(0x1DDC0325259B27DE), U64(0xCF3F4688801EB9AA), U64(0xF4F5D05C10CAB243), U64(0x38B6525C21A42B0E), U64(0x36F60E2BA4FA6800), U64(0xEB3593803173E0CE), U64(0x9C4CD6257C5A3603), U64(0xAF0C317D32ADAA8A), U64(0x258E5A80C7204C4B), U64(0x8B889D624D44885D), U64(0xF4D14597E660F855), U64(0xD4347F66EC8941C3), U64(0xE699ED85B0DFB40D), U64(0x2472F6207C2D0484), U64(0xC2A1E7B5B459AEB5), U64(0xAB4F6451CC1D45EC), U64(0x63767572AE3D6174), U64(0xA59E0BD101731A28), U64(0x116D0016CB948F09), U64(0x2CF9C8CA052F6E9F), U64(0x0B090A7560A968E3), U64(0xABEEDDB2DDE06FF1), U64(0x58EFC10B06A2068D), U64(0xC6E57A78FBD986E0), U64(0x2EAB8CA63CE802D7), U64(0x14A195640116F336), U64(0x7C0828DD624EC390), U64(0xD74BBE77E6116AC7), U64(0x804456AF10F5FB53), U64(0xEBE9EA2ADF4321C7), U64(0x03219A39EE587A30), U64(0x49787FEF17AF9924), U64(0xA1E9300CD8520548), U64(0x5B45E522E4B1B4EF), U64(0xB49C3B3995091A36), U64(0xD4490AD526F14431), U64(0x12A8F216AF9418C2), U64(0x001F837CC7350524), U64(0x1877B51E57A764D5), U64(0xA2853B80F17F58EE), U64(0x993E1DE72D36D310), U64(0xB3598080CE64A656), U64(0x252F59CF0D9F04BB), U64(0xD23C8E176D113600), U64(0x1BDA0492E7E4586E), U64(0x21E0BD5026C619BF), U64(0x3B097ADAF088F94E), U64(0x8D14DEDB30BE846E), U64(0xF95CFFA23AF5F6F4), U64(0x3871700761B3F743), U64(0xCA672B91E9E4FA16), U64(0x64C8E531BFF53B55), U64(0x241260ED4AD1E87D), U64(0x106C09B972D2E822), U64(0x7FBA195410E5CA30), U64(0x7884D9BC6CB569D8), U64(0x0647DFEDCD894A29), U64(0x63573FF03E224774), U64(0x4FC8E9560F91B123), U64(0x1DB956E450275779), U64(0xB8D91274B9E9D4FB), U64(0xA2EBEE47E2FBFCE1), U64(0xD9F1F30CCD97FB09), U64(0xEFED53D75FD64E6B), U64(0x2E6D02C36017F67F), U64(0xA9AA4D20DB084E9B), U64(0xB64BE8D8B25396C1), U64(0x70CB6AF7C2D5BCF0), U64(0x98F076A4F7A2322E), U64(0xBF84470805E69B5F), U64(0x94C3251F06F90CF3), U64(0x3E003E616A6591E9), U64(0xB925A6CD0421AFF3), U64(0x61BDD1307C66E300), U64(0xBF8D5108E27E0D48), U64(0x240AB57A8B888B20), U64(0xFC87614BAF287E07), U64(0xEF02CDD06FFDB432), U64(0xA1082C0466DF6C0A), U64(0x8215E577001332C8), U64(0xD39BB9C3A48DB6CF), U64(0x2738259634305C14), U64(0x61CF4F94C97DF93D), U64(0x1B6BACA2AE4E125B), U64(0x758F450C88572E0B), U64(0x959F587D507A8359), U64(0xB063E962E045F54D), U64(0x60E8ED72C0DFF5D1), U64(0x7B64978555326F9F), U64(0xFD080D236DA814BA), U64(0x8C90FD9B083F4558), U64(0x106F72FE81E2C590), U64(0x7976033A39F7D952), U64(0xA4EC0132764CA04B), U64(0x733EA705FAE4FA77), U64(0xB4D8F77BC3E56167), U64(0x9E21F4F903B33FD9), U64(0x9D765E419FB69F6D), U64(0xD30C088BA61EA5EF), U64(0x5D94337FBFAF7F5B), U64(0x1A4E4822EB4D7A59), U64(0x6FFE73E81B637FB3), U64(0xDDF957BC36D8B9CA), U64(0x64D0E29EEA8838B3), U64(0x08DD9BDFD96B9F63), U64(0x087E79E5A57D1D13), U64(0xE328E230E3E2B3FB), U64(0x1C2559E30F0946BE), U64(0x720BF5F26F4D2EAA), U64(0xB0774D261CC609DB), U64(0x443F64EC5A371195), U64(0x4112CF68649A260E), U64(0xD813F2FAB7F5C5CA), U64(0x660D3257380841EE), U64(0x59AC2C7873F910A3), U64(0xE846963877671A17), U64(0x93B633ABFA3469F8), U64(0xC0C0F5A60EF4CDCF), U64(0xCAF21ECD4377B28C), U64(0x57277707199B8175), U64(0x506C11B9D90E8B1D), U64(0xD83CC2687A19255F), U64(0x4A29C6465A314CD1), U64(0xED2DF21216235097), U64(0xB5635C95FF7296E2), U64(0x22AF003AB672E811), U64(0x52E762596BF68235), U64(0x9AEBA33AC6ECC6B0), U64(0x944F6DE09134DFB6), U64(0x6C47BEC883A7DE39), U64(0x6AD047C430A12104), U64(0xA5B1CFDBA0AB4067), U64(0x7C45D833AFF07862), U64(0x5092EF950A16DA0B), U64(0x9338E69C052B8E7B), U64(0x455A4B4CFE30E3F5), U64(0x6B02E63195AD0CF8), U64(0x6B17B224BAD6BF27), U64(0xD1E0CCD25BB9C169), U64(0xDE0C89A556B9AE70), U64(0x50065E535A213CF6), U64(0x9C1169FA2777B874), U64(0x78EDEFD694AF1EED), U64(0x6DC93D9526A50E68), U64(0xEE97F453F06791ED), U64(0x32AB0EDB696703D3), U64(0x3A6853C7E70757A7), U64(0x31865CED6120F37D), U64(0x67FEF95D92607890), U64(0x1F2B1D1F15F6DC9C), U64(0xB69E38A8965C6B65), U64(0xAA9119FF184CCCF4), U64(0xF43C732873F24C13), U64(0xFB4A3D794A9A80D2), U64(0x3550C2321FD6109C), U64(0x371F77E76BB8417E), U64(0x6BFA9AAE5EC05779), U64(0xCD04F3FF001A4778), U64(0xE3273522064480CA), U64(0x9F91508BFFCFC14A), U64(0x049A7F41061A9E60), U64(0xFCB6BE43A9F2FE9B), U64(0x08DE8A1C7797DA9B), U64(0x8F9887E6078735A1), U64(0xB5B4071DBFC73A66), U64(0x230E343DFBA08D33), U64(0x43ED7F5A0FAE657D), U64(0x3A88A0FBBCB05C63), U64(0x21874B8B4D2DBC4F), U64(0x1BDEA12E35F6A8C9), U64(0x53C065C6C8E63528), U64(0xE34A1D250E7A8D6B), U64(0xD6B04D3B7651DD7E), U64(0x5E90277E7CB39E2D), U64(0x2C046F22062DC67D), U64(0xB10BB459132D0A26), U64(0x3FA9DDFB67E2F199), U64(0x0E09B88E1914F7AF), U64(0x10E8B35AF3EEAB37), U64(0x9EEDECA8E272B933), U64(0xD4C718BC4AE8AE5F), U64(0x81536D601170FC20), U64(0x91B534F885818A06), U64(0xEC8177F83F900978), U64(0x190E714FADA5156E), U64(0xB592BF39B0364963), U64(0x89C350C893AE7DC1), U64(0xAC042E70F8B383F2), U64(0xB49B52E587A1EE60), U64(0xFB152FE3FF26DA89), U64(0x3E666E6F69AE2C15), U64(0x3B544EBE544C19F9), U64(0xE805A1E290CF2456), U64(0x24B33C9D7ED25117), U64(0xE74733427B72F0C1), U64(0x0A804D18B7097475), U64(0x57E3306D881EDB4F), U64(0x4AE7D6A36EB5DBCB), U64(0x2D8D5432157064C8), U64(0xD1E649DE1E7F268B), U64(0x8A328A1CEDFE552C), U64(0x07A3AEC79624C7DA), U64(0x84547DDC3E203C94), U64(0x990A98FD5071D263), U64(0x1A4FF12616EEFC89), U64(0xF6F7FD1431714200), U64(0x30C05B1BA332F41C), U64(0x8D2636B81555A786), U64(0x46C9FEB55D120902), U64(0xCCEC0A73B49C9921), U64(0x4E9D2827355FC492), U64(0x19EBB029435DCB0F), U64(0x4659D2B743848A2C), U64(0x963EF2C96B33BE31), U64(0x74F85198B05A2E7D), U64(0x5A0F544DD2B1FB18), U64(0x03727073C2E134B1), U64(0xC7F6AA2DE59AEA61), U64(0x352787BAA0D7C22F), U64(0x9853EAB63B5E0B35), U64(0xABBDCDD7ED5C0860), U64(0xCF05DAF5AC8D77B0), U64(0x49CAD48CEBF4A71E), U64(0x7A4C10EC2158C4A6), U64(0xD9E92AA246BF719E), U64(0x13AE978D09FE5557), U64(0x730499AF921549FF), U64(0x4E4B705B92903BA4), U64(0xFF577222C14F0A3A), U64(0x55B6344CF97AAFAE), U64(0xB862225B055B6960), U64(0xCAC09AFBDDD2CDB4), U64(0xDAF8E9829FE96B5F), U64(0xB5FDFC5D3132C498), U64(0x310CB380DB6F7503), U64(0xE87FBB46217A360E), U64(0x2102AE466EBB1148), U64(0xF8549E1A3AA5E00D), U64(0x07A69AFDCC42261A), U64(0xC4C118BFE78FEAAE), U64(0xF9F4892ED96BD438), U64(0x1AF3DBE25D8F45DA), U64(0xF5B4B0B0D2DEEEB4), U64(0x962ACEEFA82E1C84), U64(0x046E3ECAAF453CE9), U64(0xF05D129681949A4C), U64(0x964781CE734B3C84), U64(0x9C2ED44081CE5FBD), U64(0x522E23F3925E319E), U64(0x177E00F9FC32F791), U64(0x2BC60A63A6F3B3F2), U64(0x222BBFAE61725606), U64(0x486289DDCC3D6780), U64(0x7DC7785B8EFDFC80), U64(0x8AF38731C02BA980), U64(0x1FAB64EA29A2DDF7), U64(0xE4D9429322CD065A), U64(0x9DA058C67844F20C), U64(0x24C0E332B70019B0), U64(0x233003B5A6CFE6AD), U64(0xD586BD01C5C217F6), U64(0x5E5637885F29BC2B), U64(0x7EBA726D8C94094B), U64(0x0A56A5F0BFE39272), U64(0xD79476A84EE20D06), U64(0x9E4C1269BAA4BF37), U64(0x17EFEE45B0DEE640), U64(0x1D95B0A5FCF90BC6), U64(0x93CBE0B699C2585D), U64(0x65FA4F227A2B6D79), U64(0xD5F9E858292504D5), U64(0xC2B5A03F71471A6F), U64(0x59300222B4561E00), U64(0xCE2F8642CA0712DC), U64(0x7CA9723FBB2E8988), U64(0x2785338347F2BA08), U64(0xC61BB3A141E50E8C), U64(0x150F361DAB9DEC26), U64(0x9F6A419D382595F4), U64(0x64A53DC924FE7AC9), U64(0x142DE49FFF7A7C3D), U64(0x0C335248857FA9E7), U64(0x0A9C32D5EAE45305), U64(0xE6C42178C4BBB92E), U64(0x71F1CE2490D20B07), U64(0xF1BCC3D275AFE51A), U64(0xE728E8C83C334074), U64(0x96FBF83A12884624), U64(0x81A1549FD6573DA5), U64(0x5FA7867CAF35E149), U64(0x56986E2EF3ED091B), U64(0x917F1DD5F8886C61), U64(0xD20D8C88C8FFE65F), U64(0x31D71DCE64B2C310), U64(0xF165B587DF898190), U64(0xA57E6339DD2CF3A0), U64(0x1EF6E6DBB1961EC9), U64(0x70CC73D90BC26E24), U64(0xE21A6B35DF0C3AD7), U64(0x003A93D8B2806962), U64(0x1C99DED33CB890A1), U64(0xCF3145DE0ADD4289), U64(0xD0E4427A5514FB72), U64(0x77C621CC9FB3A483), U64(0x67A34DAC4356550B), U64(0xF8D626AAAF278509), }; // functions // random_init() void random_init() { if ((Random64[RandomNb-1] >> 32) != 0xF8D626AA) { // upper half of the last element of the array my_fatal("broken 64-bit types\n"); } } // end of random.cpp fruit-2.1.dfsg-1.orig/src/recog.h0000600000175000017500000000034210402400155016123 0ustar oliveroliver // recog.h #ifndef RECOG_H #define RECOG_H // includes #include "board.h" #include "util.h" // functions extern bool recog_draw (const board_t * board); #endif // !defined RECOG_H // end of recog.h fruit-2.1.dfsg-1.orig/src/attack.h0000600000175000017500000000320710402400155016276 0ustar oliveroliver // attack.h #ifndef ATTACK_H #define ATTACK_H // includes #include "board.h" #include "util.h" #include "vector.h" // macros #define IS_IN_CHECK(board,colour) (is_attacked((board),KING_POS((board),(colour)),COLOUR_OPP((colour)))) #define DELTA_INC_LINE(delta) (DeltaIncLine[DeltaOffset+(delta)]) #define DELTA_INC_ALL(delta) (DeltaIncAll[DeltaOffset+(delta)]) #define DELTA_MASK(delta) (DeltaMask[DeltaOffset+(delta)]) #define INC_MASK(inc) (IncMask[IncOffset+(inc)]) #define PIECE_ATTACK(board,piece,from,to) (PSEUDO_ATTACK((piece),(to)-(from))&&line_is_empty((board),(from),(to))) #define PSEUDO_ATTACK(piece,delta) (((piece)&DELTA_MASK(delta))!=0) #define SLIDER_ATTACK(piece,inc) (((piece)&INC_MASK(inc))!=0) #define ATTACK_IN_CHECK(attack) ((attack)->dn!=0) // types struct attack_t { int dn; int ds[2+1]; int di[2+1]; }; // variables extern int DeltaIncLine[DeltaNb]; extern int DeltaIncAll[DeltaNb]; extern int DeltaMask[DeltaNb]; extern int IncMask[IncNb]; // functions extern void attack_init (); extern bool is_attacked (const board_t * board, int to, int colour); extern bool line_is_empty (const board_t * board, int from, int to); extern bool is_pinned (const board_t * board, int square, int colour); extern bool attack_is_ok (const attack_t * attack); extern void attack_set (attack_t * attack, const board_t * board); extern bool piece_attack_king (const board_t * board, int piece, int from, int king); #endif // !defined ATTACK_H // end of attack.h fruit-2.1.dfsg-1.orig/src/trans.cpp0000600000175000017500000002222710402400155016514 0ustar oliveroliver // trans.cpp // includes #include "hash.h" #include "move.h" #include "option.h" #include "protocol.h" #include "trans.h" #include "util.h" #include "value.h" // macros #define MIN(a,b) ((a)<=(b)?(a):(b)) #define MAX(a,b) ((a)>=(b)?(a):(b)) // constants static const bool UseModulo = false; static const int DateSize = 16; static const int ClusterSize = 4; // TODO: unsigned? static const int DepthNone = -128; // types struct entry_t { uint32 lock; uint16 move; sint8 depth; uint8 date; sint8 move_depth; uint8 flags; sint8 min_depth; sint8 max_depth; sint16 min_value; sint16 max_value; }; struct trans { // HACK: typedef'ed in trans.h entry_t * table; uint32 size; uint32 mask; int date; int age[DateSize]; uint32 used; sint64 read_nb; sint64 read_hit; sint64 write_nb; sint64 write_hit; sint64 write_collision; }; // variables trans_t Trans[1]; // prototypes static void trans_set_date (trans_t * trans, int date); static int trans_age (const trans_t * trans, int date); static entry_t * trans_entry (trans_t * trans, uint64 key); static bool entry_is_ok (const entry_t * entry); // functions // trans_is_ok() bool trans_is_ok(const trans_t * trans) { int date; if (trans == NULL) return false; if (trans->table == NULL) return false; if (trans->size == 0) return false; if (trans->mask == 0 || trans->mask >= trans->size) return false; if (trans->date >= DateSize) return false; for (date = 0; date < DateSize; date++) { if (trans->age[date] != trans_age(trans,date)) return false; } return true; } // trans_init() void trans_init(trans_t * trans) { ASSERT(trans!=NULL); ASSERT(sizeof(entry_t)==16); trans->size = 0; trans->mask = 0; trans->table = NULL; trans_set_date(trans,0); trans_clear(trans); // ASSERT(trans_is_ok(trans)); } // trans_alloc() void trans_alloc(trans_t * trans) { uint32 size, target; ASSERT(trans!=NULL); // calculate size target = option_get_int("Hash"); if (target < 4) target = 16; target *= 1024 * 1024; for (size = 1; size != 0 && size <= target; size *= 2) ; size /= 2; ASSERT(size>0&&size<=target); // allocate table size /= sizeof(entry_t); ASSERT(size!=0&&(size&(size-1))==0); // power of 2 trans->size = size + (ClusterSize - 1); // HACK to avoid testing for end of table trans->mask = size - 1; trans->table = (entry_t *) my_malloc(trans->size*sizeof(entry_t)); trans_clear(trans); ASSERT(trans_is_ok(trans)); } // trans_free() void trans_free(trans_t * trans) { ASSERT(trans_is_ok(trans)); my_free(trans->table); trans->table = NULL; trans->size = 0; trans->mask = 0; } // trans_clear() void trans_clear(trans_t * trans) { entry_t clear_entry[1]; entry_t * entry; uint32 index; ASSERT(trans!=NULL); trans_set_date(trans,0); clear_entry->lock = 0; clear_entry->move = MoveNone; clear_entry->depth = DepthNone; clear_entry->date = trans->date; clear_entry->move_depth = DepthNone; clear_entry->flags = 0; clear_entry->min_depth = DepthNone; clear_entry->max_depth = DepthNone; clear_entry->min_value = -ValueInf; clear_entry->max_value = +ValueInf; ASSERT(entry_is_ok(clear_entry)); entry = trans->table; for (index = 0; index < trans->size; index++) { *entry++ = *clear_entry; } } // trans_inc_date() void trans_inc_date(trans_t * trans) { ASSERT(trans!=NULL); trans_set_date(trans,(trans->date+1)%DateSize); } // trans_set_date() static void trans_set_date(trans_t * trans, int date) { ASSERT(trans!=NULL); ASSERT(date>=0&&datedate = date; for (date = 0; date < DateSize; date++) { trans->age[date] = trans_age(trans,date); } trans->used = 0; trans->read_nb = 0; trans->read_hit = 0; trans->write_nb = 0; trans->write_hit = 0; trans->write_collision = 0; } // trans_age() static int trans_age(const trans_t * trans, int date) { int age; ASSERT(trans!=NULL); ASSERT(date>=0&&datedate - date; if (age < 0) age += DateSize; ASSERT(age>=0&&age=0&&move<65536); ASSERT(depth>=-127&&depth<=+127); ASSERT(min_value>=-ValueInf&&min_value<=+ValueInf); ASSERT(max_value>=-ValueInf&&max_value<=+ValueInf); ASSERT(min_value<=max_value); // init trans->write_nb++; // probe best_entry = NULL; best_score = -32767; entry = trans_entry(trans,key); for (i = 0; i < ClusterSize; i++, entry++) { if (entry->lock == KEY_LOCK(key)) { // hash hit => update existing entry trans->write_hit++; if (entry->date != trans->date) trans->used++; entry->date = trans->date; if (depth > entry->depth) entry->depth = depth; // for replacement scheme if (move != MoveNone && depth >= entry->move_depth) { entry->move_depth = depth; entry->move = move; } if (min_value > -ValueInf && depth >= entry->min_depth) { entry->min_depth = depth; entry->min_value = min_value; } if (max_value < +ValueInf && depth >= entry->max_depth) { entry->max_depth = depth; entry->max_value = max_value; } ASSERT(entry_is_ok(entry)); return; } // evaluate replacement score score = trans->age[entry->date] * 256 - entry->depth; ASSERT(score>-32767); if (score > best_score) { best_entry = entry; best_score = score; } } // "best" entry found entry = best_entry; ASSERT(entry!=NULL); ASSERT(entry->lock!=KEY_LOCK(key)); if (entry->date == trans->date) { trans->write_collision++; } else { trans->used++; } // store ASSERT(entry!=NULL); entry->lock = KEY_LOCK(key); entry->date = trans->date; entry->depth = depth; entry->move_depth = (move != MoveNone) ? depth : DepthNone; entry->move = move; entry->min_depth = (min_value > -ValueInf) ? depth : DepthNone; entry->max_depth = (max_value < +ValueInf) ? depth : DepthNone; entry->min_value = min_value; entry->max_value = max_value; ASSERT(entry_is_ok(entry)); } // trans_retrieve() bool trans_retrieve(trans_t * trans, uint64 key, int * move, int * min_depth, int * max_depth, int * min_value, int * max_value) { entry_t * entry; int i; ASSERT(trans_is_ok(trans)); ASSERT(move!=NULL); ASSERT(min_depth!=NULL); ASSERT(max_depth!=NULL); ASSERT(min_value!=NULL); ASSERT(max_value!=NULL); // init trans->read_nb++; // probe entry = trans_entry(trans,key); for (i = 0; i < ClusterSize; i++, entry++) { if (entry->lock == KEY_LOCK(key)) { // found trans->read_hit++; if (entry->date != trans->date) entry->date = trans->date; *move = entry->move; *min_depth = entry->min_depth; *max_depth = entry->max_depth; *min_value = entry->min_value; *max_value = entry->max_value; return true; } } // not found return false; } // trans_stats() void trans_stats(const trans_t * trans) { double full; // double hit, collision; ASSERT(trans_is_ok(trans)); full = double(trans->used) / double(trans->size); // hit = double(trans->read_hit) / double(trans->read_nb); // collision = double(trans->write_collision) / double(trans->write_nb); send("info hashfull %.0f",full*1000.0); } // trans_entry() static entry_t * trans_entry(trans_t * trans, uint64 key) { uint32 index; ASSERT(trans_is_ok(trans)); if (UseModulo) { index = KEY_INDEX(key) % (trans->mask + 1); } else { index = KEY_INDEX(key) & trans->mask; } ASSERT(index<=trans->mask); return &trans->table[index]; } // entry_is_ok() static bool entry_is_ok(const entry_t * entry) { if (entry == NULL) return false; if (entry->date >= DateSize) return false; if (entry->move == MoveNone && entry->move_depth != DepthNone) return false; if (entry->move != MoveNone && entry->move_depth == DepthNone) return false; if (entry->min_value == -ValueInf && entry->min_depth != DepthNone) return false; if (entry->min_value > -ValueInf && entry->min_depth == DepthNone) return false; if (entry->max_value == +ValueInf && entry->max_depth != DepthNone) return false; if (entry->max_value < +ValueInf && entry->max_depth == DepthNone) return false; return true; } // end of trans.cpp fruit-2.1.dfsg-1.orig/src/vector.cpp0000600000175000017500000000224710402400155016667 0ustar oliveroliver // vector.cpp // includes #include "piece.h" #include "square.h" #include "util.h" #include "vector.h" // variables int Distance[DeltaNb]; // functions void vector_init() { int delta; int x, y; int dist, tmp; // Distance[] for (delta = 0; delta < DeltaNb; delta++) Distance[delta] = -1; for (y = -7; y <= +7; y++) { for (x = -7; x <= +7; x++) { delta = y * 16 + x; ASSERT(delta_is_ok(delta)); dist = 0; tmp = x; if (tmp < 0) tmp = -tmp; if (tmp > dist) dist = tmp; tmp = y; if (tmp < 0) tmp = -tmp; if (tmp > dist) dist = tmp; Distance[DeltaOffset+delta] = dist; } } } // delta_is_ok() bool delta_is_ok(int delta) { if (delta < -119 || delta > +119) return false; if ((delta & 0xF) == 8) return false; // HACK: delta % 16 would be ill-defined for negative numbers return true; } // inc_is_ok() bool inc_is_ok(int inc) { int dir; for (dir = 0; dir < 8; dir++) { if (KingInc[dir] == inc) return true; } return false; } // end of vector.cpp fruit-2.1.dfsg-1.orig/src/move_check.h0000600000175000017500000000053210402400155017130 0ustar oliveroliver // move_check.h #ifndef MOVE_CHECK_H #define MOVE_CHECK_H // includes #include "board.h" #include "list.h" #include "util.h" // functions extern void gen_quiet_checks (list_t * list, board_t * board); extern bool move_is_check (int move, board_t * board); #endif // !defined MOVE_CHECK_H // end of move_check.h fruit-2.1.dfsg-1.orig/src/move_legal.cpp0000600000175000017500000001116110402400155017472 0ustar oliveroliver // move_legal.cpp // includes #include "attack.h" #include "colour.h" #include "fen.h" #include "list.h" #include "move.h" #include "move_do.h" #include "move_gen.h" #include "move_legal.h" #include "piece.h" #include "square.h" #include "util.h" // prototypes static bool move_is_pseudo_debug (int move, board_t * board); // functions // move_is_pseudo() bool move_is_pseudo(int move, board_t * board) { int me, opp; int from, to; int piece, capture; int inc, delta; ASSERT(move_is_ok(move)); ASSERT(board!=NULL); ASSERT(!board_is_check(board)); // special cases if (MOVE_IS_SPECIAL(move)) { return move_is_pseudo_debug(move,board); } ASSERT((move&~07777)==0); // init me = board->turn; opp = COLOUR_OPP(board->turn); // from from = MOVE_FROM(move); ASSERT(SQUARE_IS_OK(from)); piece = board->square[from]; if (!COLOUR_IS(piece,me)) return false; ASSERT(piece_is_ok(piece)); // to to = MOVE_TO(move); ASSERT(SQUARE_IS_OK(to)); capture = board->square[to]; if (COLOUR_IS(capture,me)) return false; // move if (PIECE_IS_PAWN(piece)) { if (SQUARE_IS_PROMOTE(to)) return false; inc = PAWN_MOVE_INC(me); delta = to - from; ASSERT(delta_is_ok(delta)); if (capture == Empty) { // pawn push if (delta == inc) return true; if (delta == (2*inc) && PAWN_RANK(from,me) == Rank2 && board->square[from+inc] == Empty) { return true; } } else { // pawn capture if (delta == (inc-1) || delta == (inc+1)) return true; } } else { if (PIECE_ATTACK(board,piece,from,to)) return true; } return false; } // quiet_is_pseudo() bool quiet_is_pseudo(int move, board_t * board) { int me, opp; int from, to; int piece; int inc, delta; ASSERT(move_is_ok(move)); ASSERT(board!=NULL); ASSERT(!board_is_check(board)); // special cases if (MOVE_IS_CASTLE(move)) { return move_is_pseudo_debug(move,board); } else if (MOVE_IS_SPECIAL(move)) { return false; } ASSERT((move&~07777)==0); // init me = board->turn; opp = COLOUR_OPP(board->turn); // from from = MOVE_FROM(move); ASSERT(SQUARE_IS_OK(from)); piece = board->square[from]; if (!COLOUR_IS(piece,me)) return false; ASSERT(piece_is_ok(piece)); // to to = MOVE_TO(move); ASSERT(SQUARE_IS_OK(to)); if (board->square[to] != Empty) return false; // capture // move if (PIECE_IS_PAWN(piece)) { if (SQUARE_IS_PROMOTE(to)) return false; inc = PAWN_MOVE_INC(me); delta = to - from; ASSERT(delta_is_ok(delta)); // pawn push if (delta == inc) return true; if (delta == (2*inc) && PAWN_RANK(from,me) == Rank2 && board->square[from+inc] == Empty) { return true; } } else { if (PIECE_ATTACK(board,piece,from,to)) return true; } return false; } // pseudo_is_legal() bool pseudo_is_legal(int move, board_t * board) { int me, opp; int from, to; int piece; bool legal; int king; undo_t undo[1]; ASSERT(move_is_ok(move)); ASSERT(board!=NULL); // init me = board->turn; opp = COLOUR_OPP(me); from = MOVE_FROM(move); to = MOVE_TO(move); piece = board->square[from]; ASSERT(COLOUR_IS(piece,me)); // slow test for en-passant captures if (MOVE_IS_EN_PASSANT(move)) { move_do(board,move,undo); legal = !IS_IN_CHECK(board,me); move_undo(board,move,undo); return legal; } // king moves (including castle) if (PIECE_IS_KING(piece)) { legal = !is_attacked(board,to,opp); if (DEBUG) { ASSERT(board->square[from]==piece); board->square[from] = Empty; ASSERT(legal==!is_attacked(board,to,opp)); board->square[from] = piece; } return legal; } // pins if (is_pinned(board,from,me)) { king = KING_POS(board,me); return DELTA_INC_LINE(king-to) == DELTA_INC_LINE(king-from); // does not discover the line } return true; } // move_is_pseudo_debug() static bool move_is_pseudo_debug(int move, board_t * board) { list_t list[1]; ASSERT(move_is_ok(move)); ASSERT(board!=NULL); ASSERT(!board_is_check(board)); gen_moves(list,board); return list_contain(list,move); } // end of move_legal.cpp fruit-2.1.dfsg-1.orig/src/fen.h0000600000175000017500000000055410402400155015601 0ustar oliveroliver // fen.h #ifndef FEN_H #define FEN_H // includes #include "board.h" #include "util.h" // "constants" extern const char * const StartFen; // functions extern void board_from_fen (board_t * board, const char fen[]); extern bool board_to_fen (const board_t * board, char fen[], int size); #endif // !defined FEN_H // end of fen.h fruit-2.1.dfsg-1.orig/src/pst.h0000600000175000017500000000062610402400155015637 0ustar oliveroliver // pst.h #ifndef PST_H #define PST_H // includes #include "util.h" // constants const int Opening = 0; const int Endgame = 1; const int StageNb = 2; // macros #define PST(piece_12,square_64,stage) (Pst[piece_12][square_64][stage]) // variables extern sint16 Pst[12][64][StageNb]; // functions extern void pst_init (); #endif // !defined PST_H // end of pst.h fruit-2.1.dfsg-1.orig/src/see.h0000600000175000017500000000044510402400155015604 0ustar oliveroliver // see.h #ifndef SEE_H #define SEE_H // includes #include "board.h" #include "util.h" // functions extern int see_move (int move, const board_t * board); extern int see_square (const board_t * board, int to, int colour); #endif // !defined SEE_H // end of see.h fruit-2.1.dfsg-1.orig/src/sort.cpp0000600000175000017500000004444710402400155016364 0ustar oliveroliver // sort.cpp // includes #include "attack.h" #include "board.h" #include "colour.h" #include "list.h" #include "move.h" #include "move_check.h" #include "move_evasion.h" #include "move_gen.h" #include "move_legal.h" #include "piece.h" #include "search.h" #include "see.h" #include "sort.h" #include "util.h" #include "value.h" // constants static const int KillerNb = 2; static const int HistorySize = 12 * 64; static const int HistoryMax = 16384; static const int TransScore = +32766; static const int GoodScore = +4000; static const int KillerScore = +4; static const int HistoryScore = -24000; static const int BadScore = -28000; static const int CODE_SIZE = 256; // macros #define HISTORY_INC(depth) ((depth)*(depth)) // types enum gen_t { GEN_ERROR, GEN_LEGAL_EVASION, GEN_TRANS, GEN_GOOD_CAPTURE, GEN_BAD_CAPTURE, GEN_KILLER, GEN_QUIET, GEN_EVASION_QS, GEN_CAPTURE_QS, GEN_CHECK_QS, GEN_END }; enum test_t { TEST_ERROR, TEST_NONE, TEST_LEGAL, TEST_TRANS_KILLER, TEST_GOOD_CAPTURE, TEST_BAD_CAPTURE, TEST_KILLER, TEST_QUIET, TEST_CAPTURE_QS, TEST_CHECK_QS }; // variables static int PosLegalEvasion; static int PosSEE; static int PosEvasionQS; static int PosCheckQS; static int PosCaptureQS; static int Code[CODE_SIZE]; static uint16 Killer[HeightMax][KillerNb]; static uint16 History[HistorySize]; static uint16 HistHit[HistorySize]; static uint16 HistTot[HistorySize]; // prototypes static void note_captures (list_t * list, const board_t * board); static void note_quiet_moves (list_t * list, const board_t * board); static void note_moves_simple (list_t * list, const board_t * board); static void note_mvv_lva (list_t * list, const board_t * board); static int move_value (int move, const board_t * board, int height, int trans_killer); static int capture_value (int move, const board_t * board); static int quiet_move_value (int move, const board_t * board); static int move_value_simple (int move, const board_t * board); static int history_prob (int move, const board_t * board); static bool capture_is_good (int move, const board_t * board); static int mvv_lva (int move, const board_t * board); static int history_index (int move, const board_t * board); // functions // sort_init() void sort_init() { int i, height; int pos; // killer for (height = 0; height < HeightMax; height++) { for (i = 0; i < KillerNb; i++) Killer[height][i] = MoveNone; } // history for (i = 0; i < HistorySize; i++) History[i] = 0; for (i = 0; i < HistorySize; i++) { HistHit[i] = 1; HistTot[i] = 1; } // Code[] for (pos = 0; pos < CODE_SIZE; pos++) Code[pos] = GEN_ERROR; pos = 0; // main search PosLegalEvasion = pos; Code[pos++] = GEN_LEGAL_EVASION; Code[pos++] = GEN_END; PosSEE = pos; Code[pos++] = GEN_TRANS; Code[pos++] = GEN_GOOD_CAPTURE; Code[pos++] = GEN_KILLER; Code[pos++] = GEN_QUIET; Code[pos++] = GEN_BAD_CAPTURE; Code[pos++] = GEN_END; // quiescence search PosEvasionQS = pos; Code[pos++] = GEN_EVASION_QS; Code[pos++] = GEN_END; PosCheckQS = pos; Code[pos++] = GEN_CAPTURE_QS; Code[pos++] = GEN_CHECK_QS; Code[pos++] = GEN_END; PosCaptureQS = pos; Code[pos++] = GEN_CAPTURE_QS; Code[pos++] = GEN_END; ASSERT(posboard = board; sort->attack = attack; sort->depth = depth; sort->height = height; sort->trans_killer = trans_killer; sort->killer_1 = Killer[sort->height][0]; sort->killer_2 = Killer[sort->height][1]; if (ATTACK_IN_CHECK(sort->attack)) { gen_legal_evasions(sort->list,sort->board,sort->attack); note_moves(sort->list,sort->board,sort->height,sort->trans_killer); list_sort(sort->list); sort->gen = PosLegalEvasion + 1; sort->test = TEST_NONE; } else { // not in check LIST_CLEAR(sort->list); sort->gen = PosSEE; } sort->pos = 0; } // sort_next() int sort_next(sort_t * sort) { int move; int gen; ASSERT(sort!=NULL); while (true) { while (sort->pos < LIST_SIZE(sort->list)) { // next move move = LIST_MOVE(sort->list,sort->pos); sort->value = 16384; // default score sort->pos++; ASSERT(move!=MoveNone); // test if (false) { } else if (sort->test == TEST_NONE) { // no-op } else if (sort->test == TEST_TRANS_KILLER) { if (!move_is_pseudo(move,sort->board)) continue; if (!pseudo_is_legal(move,sort->board)) continue; } else if (sort->test == TEST_GOOD_CAPTURE) { ASSERT(move_is_tactical(move,sort->board)); if (move == sort->trans_killer) continue; if (!capture_is_good(move,sort->board)) { LIST_ADD(sort->bad,move); continue; } if (!pseudo_is_legal(move,sort->board)) continue; } else if (sort->test == TEST_BAD_CAPTURE) { ASSERT(move_is_tactical(move,sort->board)); ASSERT(!capture_is_good(move,sort->board)); ASSERT(move!=sort->trans_killer); if (!pseudo_is_legal(move,sort->board)) continue; } else if (sort->test == TEST_KILLER) { if (move == sort->trans_killer) continue; if (!quiet_is_pseudo(move,sort->board)) continue; if (!pseudo_is_legal(move,sort->board)) continue; ASSERT(!move_is_tactical(move,sort->board)); } else if (sort->test == TEST_QUIET) { ASSERT(!move_is_tactical(move,sort->board)); if (move == sort->trans_killer) continue; if (move == sort->killer_1) continue; if (move == sort->killer_2) continue; if (!pseudo_is_legal(move,sort->board)) continue; sort->value = history_prob(move,sort->board); } else { ASSERT(false); return MoveNone; } ASSERT(pseudo_is_legal(move,sort->board)); return move; } // next stage gen = Code[sort->gen++]; if (false) { } else if (gen == GEN_TRANS) { LIST_CLEAR(sort->list); if (sort->trans_killer != MoveNone) LIST_ADD(sort->list,sort->trans_killer); sort->test = TEST_TRANS_KILLER; } else if (gen == GEN_GOOD_CAPTURE) { gen_captures(sort->list,sort->board); note_mvv_lva(sort->list,sort->board); list_sort(sort->list); LIST_CLEAR(sort->bad); sort->test = TEST_GOOD_CAPTURE; } else if (gen == GEN_BAD_CAPTURE) { list_copy(sort->list,sort->bad); sort->test = TEST_BAD_CAPTURE; } else if (gen == GEN_KILLER) { LIST_CLEAR(sort->list); if (sort->killer_1 != MoveNone) LIST_ADD(sort->list,sort->killer_1); if (sort->killer_2 != MoveNone) LIST_ADD(sort->list,sort->killer_2); sort->test = TEST_KILLER; } else if (gen == GEN_QUIET) { gen_quiet_moves(sort->list,sort->board); note_quiet_moves(sort->list,sort->board); list_sort(sort->list); sort->test = TEST_QUIET; } else { ASSERT(gen==GEN_END); return MoveNone; } sort->pos = 0; } } // sort_init_qs() void sort_init_qs(sort_t * sort, board_t * board, const attack_t * attack, bool check) { ASSERT(sort!=NULL); ASSERT(board!=NULL); ASSERT(attack!=NULL); ASSERT(check==true||check==false); sort->board = board; sort->attack = attack; if (ATTACK_IN_CHECK(sort->attack)) { sort->gen = PosEvasionQS; } else if (check) { sort->gen = PosCheckQS; } else { sort->gen = PosCaptureQS; } LIST_CLEAR(sort->list); sort->pos = 0; } // sort_next_qs() int sort_next_qs(sort_t * sort) { int move; int gen; ASSERT(sort!=NULL); while (true) { while (sort->pos < LIST_SIZE(sort->list)) { // next move move = LIST_MOVE(sort->list,sort->pos); sort->pos++; ASSERT(move!=MoveNone); // test if (false) { } else if (sort->test == TEST_LEGAL) { if (!pseudo_is_legal(move,sort->board)) continue; } else if (sort->test == TEST_CAPTURE_QS) { ASSERT(move_is_tactical(move,sort->board)); if (!capture_is_good(move,sort->board)) continue; if (!pseudo_is_legal(move,sort->board)) continue; } else if (sort->test == TEST_CHECK_QS) { ASSERT(!move_is_tactical(move,sort->board)); ASSERT(move_is_check(move,sort->board)); if (see_move(move,sort->board) < 0) continue; if (!pseudo_is_legal(move,sort->board)) continue; } else { ASSERT(false); return MoveNone; } ASSERT(pseudo_is_legal(move,sort->board)); return move; } // next stage gen = Code[sort->gen++]; if (false) { } else if (gen == GEN_EVASION_QS) { gen_pseudo_evasions(sort->list,sort->board,sort->attack); note_moves_simple(sort->list,sort->board); list_sort(sort->list); sort->test = TEST_LEGAL; } else if (gen == GEN_CAPTURE_QS) { gen_captures(sort->list,sort->board); note_mvv_lva(sort->list,sort->board); list_sort(sort->list); sort->test = TEST_CAPTURE_QS; } else if (gen == GEN_CHECK_QS) { gen_quiet_checks(sort->list,sort->board); sort->test = TEST_CHECK_QS; } else { ASSERT(gen==GEN_END); return MoveNone; } sort->pos = 0; } } // good_move() void good_move(int move, const board_t * board, int depth, int height) { int index; int i; ASSERT(move_is_ok(move)); ASSERT(board!=NULL); ASSERT(depth_is_ok(depth)); ASSERT(height_is_ok(height)); if (move_is_tactical(move,board)) return; // killer if (Killer[height][0] != move) { Killer[height][1] = Killer[height][0]; Killer[height][0] = move; } ASSERT(Killer[height][0]==move); ASSERT(Killer[height][1]!=move); // history index = history_index(move,board); History[index] += HISTORY_INC(depth); if (History[index] >= HistoryMax) { for (i = 0; i < HistorySize; i++) { History[i] = (History[i] + 1) / 2; } } } // history_good() void history_good(int move, const board_t * board) { int index; ASSERT(move_is_ok(move)); ASSERT(board!=NULL); if (move_is_tactical(move,board)) return; // history index = history_index(move,board); HistHit[index]++; HistTot[index]++; if (HistTot[index] >= HistoryMax) { HistHit[index] = (HistHit[index] + 1) / 2; HistTot[index] = (HistTot[index] + 1) / 2; } ASSERT(HistHit[index]<=HistTot[index]); ASSERT(HistTot[index]= HistoryMax) { HistHit[index] = (HistHit[index] + 1) / 2; HistTot[index] = (HistTot[index] + 1) / 2; } ASSERT(HistHit[index]<=HistTot[index]); ASSERT(HistTot[index]= 2) { for (i = 0; i < size; i++) { move = LIST_MOVE(list,i); list->value[i] = move_value(move,board,height,trans_killer); } } } // note_captures() static void note_captures(list_t * list, const board_t * board) { int size; int i, move; ASSERT(list_is_ok(list)); ASSERT(board!=NULL); size = LIST_SIZE(list); if (size >= 2) { for (i = 0; i < size; i++) { move = LIST_MOVE(list,i); list->value[i] = capture_value(move,board); } } } // note_quiet_moves() static void note_quiet_moves(list_t * list, const board_t * board) { int size; int i, move; ASSERT(list_is_ok(list)); ASSERT(board!=NULL); size = LIST_SIZE(list); if (size >= 2) { for (i = 0; i < size; i++) { move = LIST_MOVE(list,i); list->value[i] = quiet_move_value(move,board); } } } // note_moves_simple() static void note_moves_simple(list_t * list, const board_t * board) { int size; int i, move; ASSERT(list_is_ok(list)); ASSERT(board!=NULL); size = LIST_SIZE(list); if (size >= 2) { for (i = 0; i < size; i++) { move = LIST_MOVE(list,i); list->value[i] = move_value_simple(move,board); } } } // note_mvv_lva() static void note_mvv_lva(list_t * list, const board_t * board) { int size; int i, move; ASSERT(list_is_ok(list)); ASSERT(board!=NULL); size = LIST_SIZE(list); if (size >= 2) { for (i = 0; i < size; i++) { move = LIST_MOVE(list,i); list->value[i] = mvv_lva(move,board); } } } // move_value() static int move_value(int move, const board_t * board, int height, int trans_killer) { int value; ASSERT(move_is_ok(move)); ASSERT(board!=NULL); ASSERT(height_is_ok(height)); ASSERT(trans_killer==MoveNone||move_is_ok(trans_killer)); if (false) { } else if (move == trans_killer) { // transposition table killer value = TransScore; } else if (move_is_tactical(move,board)) { // capture or promote value = capture_value(move,board); } else if (move == Killer[height][0]) { // killer 1 value = KillerScore; } else if (move == Killer[height][1]) { // killer 2 value = KillerScore - 1; } else { // quiet move value = quiet_move_value(move,board); } return value; } // capture_value() static int capture_value(int move, const board_t * board) { int value; ASSERT(move_is_ok(move)); ASSERT(board!=NULL); ASSERT(move_is_tactical(move,board)); value = mvv_lva(move,board); if (capture_is_good(move,board)) { value += GoodScore; } else { value += BadScore; } ASSERT(value>=-30000&&value<=+30000); return value; } // quiet_move_value() static int quiet_move_value(int move, const board_t * board) { int value; int index; ASSERT(move_is_ok(move)); ASSERT(board!=NULL); ASSERT(!move_is_tactical(move,board)); index = history_index(move,board); value = HistoryScore + History[index]; ASSERT(value>=HistoryScore&&value<=KillerScore-4); return value; } // move_value_simple() static int move_value_simple(int move, const board_t * board) { int value; ASSERT(move_is_ok(move)); ASSERT(board!=NULL); value = HistoryScore; if (move_is_tactical(move,board)) value = mvv_lva(move,board); return value; } // history_prob() static int history_prob(int move, const board_t * board) { int value; int index; ASSERT(move_is_ok(move)); ASSERT(board!=NULL); ASSERT(!move_is_tactical(move,board)); index = history_index(move,board); ASSERT(HistHit[index]<=HistTot[index]); ASSERT(HistTot[index]=0&&value<=16384); return value; } // capture_is_good() static bool capture_is_good(int move, const board_t * board) { int piece, capture; ASSERT(move_is_ok(move)); ASSERT(board!=NULL); ASSERT(move_is_tactical(move,board)); // special cases if (MOVE_IS_EN_PASSANT(move)) return true; if (move_is_under_promote(move)) return false; // REMOVE ME? // captures and queen promotes capture = board->square[MOVE_TO(move)]; if (capture != Empty) { // capture ASSERT(move_is_capture(move,board)); if (MOVE_IS_PROMOTE(move)) return true; // promote-capture piece = board->square[MOVE_FROM(move)]; if (VALUE_PIECE(capture) >= VALUE_PIECE(piece)) return true; } return see_move(move,board) >= 0; } // mvv_lva() static int mvv_lva(int move, const board_t * board) { int piece, capture, promote; int value; ASSERT(move_is_ok(move)); ASSERT(board!=NULL); ASSERT(move_is_tactical(move,board)); if (MOVE_IS_EN_PASSANT(move)) { // en-passant capture value = 5; // PxP } else if ((capture = board->square[MOVE_TO(move)]) != Empty) { // normal capture piece = board->square[MOVE_FROM(move)]; value = PIECE_ORDER(capture) * 6 - PIECE_ORDER(piece) + 5; ASSERT(value>=0&&value<30); } else { // promote ASSERT(MOVE_IS_PROMOTE(move)); promote = move_promote(move); value = PIECE_ORDER(promote) - 5; ASSERT(value>=-4&&value<0); } ASSERT(value>=-4&&value<+30); return value; } // history_index() static int history_index(int move, const board_t * board) { int index; ASSERT(move_is_ok(move)); ASSERT(board!=NULL); ASSERT(!move_is_tactical(move,board)); index = PIECE_TO_12(board->square[MOVE_FROM(move)]) * 64 + SQUARE_TO_64(MOVE_TO(move)); ASSERT(index>=0&&indexsize=0) // types struct alist_t { int size; int square[15]; }; struct alists_t { alist_t alist[ColourNb][1]; }; // prototypes static int see_rec (alists_t * alists, const board_t * board, int colour, int to, int piece_value); static void alist_build (alist_t * alist, const board_t * board, int to, int colour); static void alists_hidden (alists_t * alists, const board_t * board, int from, int to); static void alist_clear (alist_t * alist); static void alist_add (alist_t * alist, int square, const board_t * board); static void alist_remove (alist_t * alist, int pos); static int alist_pop (alist_t * alist, const board_t * board); // functions // see_move() int see_move(int move, const board_t * board) { int att, def; int from, to; alists_t alists[1]; int value, piece_value; int piece, capture; alist_t * alist; int pos; ASSERT(move_is_ok(move)); ASSERT(board!=NULL); // init from = MOVE_FROM(move); to = MOVE_TO(move); // move the piece piece_value = 0; piece = board->square[from]; ASSERT(piece_is_ok(piece)); att = PIECE_COLOUR(piece); def = COLOUR_OPP(att); // promote if (MOVE_IS_PROMOTE(move)) { ASSERT(PIECE_IS_PAWN(piece)); piece = move_promote(move); ASSERT(piece_is_ok(piece)); ASSERT(COLOUR_IS(piece,att)); } piece_value += VALUE_PIECE(piece); // clear attacker lists ALIST_CLEAR(alists->alist[Black]); ALIST_CLEAR(alists->alist[White]); // find hidden attackers alists_hidden(alists,board,from,to); // capture the piece value = 0; capture = board->square[to]; if (capture != Empty) { ASSERT(piece_is_ok(capture)); ASSERT(COLOUR_IS(capture,def)); value += VALUE_PIECE(capture); } // promote if (MOVE_IS_PROMOTE(move)) { value += VALUE_PIECE(piece) - ValuePawn; } // en-passant if (MOVE_IS_EN_PASSANT(move)) { ASSERT(value==0); ASSERT(PIECE_IS_PAWN(board->square[SQUARE_EP_DUAL(to)])); value += ValuePawn; alists_hidden(alists,board,SQUARE_EP_DUAL(to),to); } // build defender list alist = alists->alist[def]; alist_build(alist,board,to,def); if (alist->size == 0) return value; // no defender => stop SEE // build attacker list alist = alists->alist[att]; alist_build(alist,board,to,att); // remove the moved piece (if it's an attacker) for (pos = 0; pos < alist->size && alist->square[pos] != from; pos++) ; if (pos < alist->size) alist_remove(alist,pos); // SEE search value -= see_rec(alists,board,def,to,piece_value); return value; } // see_square() int see_square(const board_t * board, int to, int colour) { int att, def; alists_t alists[1]; alist_t * alist; int piece_value; int piece; ASSERT(board!=NULL); ASSERT(SQUARE_IS_OK(to)); ASSERT(COLOUR_IS_OK(colour)); ASSERT(COLOUR_IS(board->square[to],COLOUR_OPP(colour))); // build attacker list att = colour; alist = alists->alist[att]; ALIST_CLEAR(alist); alist_build(alist,board,to,att); if (alist->size == 0) return 0; // no attacker => stop SEE // build defender list def = COLOUR_OPP(att); alist = alists->alist[def]; ALIST_CLEAR(alist); alist_build(alist,board,to,def); // captured piece piece = board->square[to]; ASSERT(piece_is_ok(piece)); ASSERT(COLOUR_IS(piece,def)); piece_value = VALUE_PIECE(piece); // SEE search return see_rec(alists,board,att,to,piece_value); } // see_rec() static int see_rec(alists_t * alists, const board_t * board, int colour, int to, int piece_value) { int from, piece; int value; ASSERT(alists!=NULL); ASSERT(board!=NULL); ASSERT(COLOUR_IS_OK(colour)); ASSERT(SQUARE_IS_OK(to)); ASSERT(piece_value>0); // find the least valuable attacker from = alist_pop(alists->alist[colour],board); if (from == SquareNone) return 0; // no more attackers // find hidden attackers alists_hidden(alists,board,from,to); // calculate the capture value value = +piece_value; // captured piece if (value == ValueKing) return value; // do not allow an answer to a king capture piece = board->square[from]; ASSERT(piece_is_ok(piece)); ASSERT(COLOUR_IS(piece,colour)); piece_value = VALUE_PIECE(piece); // promote if (piece_value == ValuePawn && SQUARE_IS_PROMOTE(to)) { // HACK: PIECE_IS_PAWN(piece) ASSERT(PIECE_IS_PAWN(piece)); piece_value = ValueQueen; value += ValueQueen - ValuePawn; } value -= see_rec(alists,board,COLOUR_OPP(colour),to,piece_value); if (value < 0) value = 0; return value; } // alist_build() static void alist_build(alist_t * alist, const board_t * board, int to, int colour) { const sq_t * ptr; int from; int piece; int delta; int inc; int sq; int pawn; ASSERT(alist!=NULL); ASSERT(board!=NULL); ASSERT(SQUARE_IS_OK(to)); ASSERT(COLOUR_IS_OK(colour)); // piece attacks for (ptr = &board->piece[colour][0]; (from=*ptr) != SquareNone; ptr++) { piece = board->square[from]; delta = to - from; if (PSEUDO_ATTACK(piece,delta)) { inc = DELTA_INC_ALL(delta); ASSERT(inc!=IncNone); sq = from; do { sq += inc; if (sq == to) { // attack alist_add(alist,from,board); break; } } while (board->square[sq] == Empty); } } // pawn attacks inc = PAWN_MOVE_INC(colour); pawn = PAWN_MAKE(colour); from = to - (inc-1); if (board->square[from] == pawn) alist_add(alist,from,board); from = to - (inc+1); if (board->square[from] == pawn) alist_add(alist,from,board); } // alists_hidden() static void alists_hidden(alists_t * alists, const board_t * board, int from, int to) { int inc; int sq, piece; ASSERT(alists!=NULL); ASSERT(board!=NULL); ASSERT(SQUARE_IS_OK(from)); ASSERT(SQUARE_IS_OK(to)); inc = DELTA_INC_LINE(to-from); if (inc != IncNone) { // line sq = from; do sq -= inc; while ((piece=board->square[sq]) == Empty); if (SLIDER_ATTACK(piece,inc)) { ASSERT(piece_is_ok(piece)); ASSERT(PIECE_IS_SLIDER(piece)); alist_add(alists->alist[PIECE_COLOUR(piece)],sq,board); } } } // alist_clear() static void alist_clear(alist_t * alist) { ASSERT(alist!=NULL); alist->size = 0; } // alist_add() static void alist_add(alist_t * alist, int square, const board_t * board) { int piece; int size, pos; ASSERT(alist!=NULL); ASSERT(SQUARE_IS_OK(square)); ASSERT(board!=NULL); // insert in MV order piece = board->square[square]; size = ++alist->size; // HACK ASSERT(size>0&&size<16); for (pos = size-1; pos > 0 && piece > board->square[alist->square[pos-1]]; pos--) { // HACK ASSERT(pos>0&&possquare[pos] = alist->square[pos-1]; } ASSERT(pos>=0&&possquare[pos] = square; } // alist_remove() static void alist_remove(alist_t * alist, int pos) { int size, i; ASSERT(alist!=NULL); ASSERT(pos>=0&&possize); size = alist->size--; // HACK ASSERT(size>=1); ASSERT(pos>=0&&pos=0&&isquare[i] = alist->square[i+1]; } } // alist_pop() static int alist_pop(alist_t * alist, const board_t * board) { int sq; int size; ASSERT(alist!=NULL); ASSERT(board!=NULL); sq = SquareNone; size = alist->size; if (size != 0) { size--; ASSERT(size>=0); sq = alist->square[size]; alist->size = size; } return sq; } // end of see.cpp fruit-2.1.dfsg-1.orig/src/protocol.h0000600000175000017500000000047110402400155016670 0ustar oliveroliver // protocol.h #ifndef PROTOCOL_H #define PROTOCOL_H // includes #include "util.h" // functions extern void loop (); extern void event (); extern void get (char string[], int size); extern void send (const char format[], ...); #endif // !defined PROTOCOL_H // end of protocol.h fruit-2.1.dfsg-1.orig/src/option.cpp0000600000175000017500000000777310402400155016706 0ustar oliveroliver // option.cpp // includes #include #include "option.h" #include "protocol.h" #include "util.h" // types struct option_t { const char * var; bool declare; const char * init; const char * type; const char * extra; const char * val; }; // variables static option_t Option[] = { { "Hash", true, "16", "spin", "min 4 max 1024", NULL }, { "Ponder", true, "false", "check", "", NULL }, { "OwnBook", true, "true", "check", "", NULL }, { "BookFile", true, "book_small.bin", "string", "", NULL }, { "NullMove Pruning", true, "Fail High", "combo", "var Always var Fail High var Never", NULL }, { "NullMove Reduction", true, "3", "spin", "min 1 max 3", NULL }, { "Verification Search", true, "Endgame", "combo", "var Always var Endgame var Never", NULL }, { "Verification Reduction", true, "5", "spin", "min 1 max 6", NULL }, { "History Pruning", true, "true", "check", "", NULL }, { "History Threshold", true, "60", "spin", "min 0 max 100", NULL }, { "Futility Pruning", true, "false", "check", "", NULL }, { "Futility Margin", true, "100", "spin", "min 0 max 500", NULL }, { "Delta Pruning", true, "false", "check", "", NULL }, { "Delta Margin", true, "50", "spin", "min 0 max 500", NULL }, { "Quiescence Check Plies", true, "1", "spin", "min 0 max 2", NULL }, { "Material", true, "100", "spin", "min 0 max 400", NULL }, { "Piece Activity", true, "100", "spin", "min 0 max 400", NULL }, { "King Safety", true, "100", "spin", "min 0 max 400", NULL }, { "Pawn Structure", true, "100", "spin", "min 0 max 400", NULL }, { "Passed Pawns", true, "100", "spin", "min 0 max 400", NULL }, { NULL, false, NULL, NULL, NULL, NULL, }, }; // prototypes static option_t * option_find (const char var[]); // functions // option_init() void option_init() { option_t * opt; for (opt = &Option[0]; opt->var != NULL; opt++) { option_set(opt->var,opt->init); } } // option_list() void option_list() { option_t * opt; for (opt = &Option[0]; opt->var != NULL; opt++) { if (opt->declare) { if (opt->extra != NULL && *opt->extra != '\0') { send("option name %s type %s default %s %s",opt->var,opt->type,opt->val,opt->extra); } else { send("option name %s type %s default %s",opt->var,opt->type,opt->val); } } } } // option_set() bool option_set(const char var[], const char val[]) { option_t * opt; ASSERT(var!=NULL); ASSERT(val!=NULL); opt = option_find(var); if (opt == NULL) return false; my_string_set(&opt->val,val); return true; } // option_get() const char * option_get(const char var[]) { option_t * opt; ASSERT(var!=NULL); opt = option_find(var); if (opt == NULL) my_fatal("option_get(): unknown option \"%s\"\n",var); return opt->val; } // option_get_bool() bool option_get_bool(const char var[]) { const char * val; val = option_get(var); if (false) { } else if (my_string_equal(val,"true") || my_string_equal(val,"yes") || my_string_equal(val,"1")) { return true; } else if (my_string_equal(val,"false") || my_string_equal(val,"no") || my_string_equal(val,"0")) { return false; } ASSERT(false); return false; } // option_get_int() int option_get_int(const char var[]) { const char * val; val = option_get(var); return atoi(val); } // option_get_string() const char * option_get_string(const char var[]) { const char * val; val = option_get(var); return val; } // option_find() static option_t * option_find(const char var[]) { option_t * opt; ASSERT(var!=NULL); for (opt = &Option[0]; opt->var != NULL; opt++) { if (my_string_equal(opt->var,var)) return opt; } return NULL; } // end of option.cpp fruit-2.1.dfsg-1.orig/src/vector.h0000600000175000017500000000114210402400155016325 0ustar oliveroliver // vector.h #ifndef VECTOR_H #define VECTOR_H // includes #include "util.h" // "constants" const int IncNone = 0; const int IncNb = 2 * 17 + 1; const int IncOffset = 17; const int DeltaNone = 0; const int DeltaNb = 2 * 119 + 1; const int DeltaOffset = 119; // macros #define DISTANCE(square_1,square_2) (Distance[DeltaOffset+((square_2)-(square_1))]) // variables extern int Distance[DeltaNb]; // functions extern void vector_init (); extern bool delta_is_ok (int delta); extern bool inc_is_ok (int inc); #endif // !defined VECTOR_H // end of vector.h fruit-2.1.dfsg-1.orig/src/fen.cpp0000600000175000017500000001361410402400155016135 0ustar oliveroliver // fen.cpp // includes #include #include #include #include "board.h" #include "colour.h" #include "fen.h" #include "piece.h" #include "square.h" #include "util.h" // "constants" const char * const StartFen = "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1"; // variables static const bool Strict = false; // functions // board_from_fen() void board_from_fen(board_t * board, const char fen[]) { int pos; int file, rank, sq; int c; int i, len; int piece; int pawn; ASSERT(board!=NULL); ASSERT(fen!=NULL); board_clear(board); pos = 0; c = fen[pos]; // piece placement for (rank = Rank8; rank >= Rank1; rank--) { for (file = FileA; file <= FileH;) { if (c >= '1' && c <= '8') { // empty square(s) len = c - '0'; for (i = 0; i < len; i++) { if (file > FileH) my_fatal("board_from_fen(): bad FEN (pos=%d)\n",pos); board->square[SQUARE_MAKE(file,rank)] = Empty; file++; } } else { // piece piece = piece_from_char(c); if (piece == PieceNone256) my_fatal("board_from_fen(): bad FEN (pos=%d)\n",pos); board->square[SQUARE_MAKE(file,rank)] = piece; file++; } c = fen[++pos]; } if (rank > Rank1) { if (c != '/') my_fatal("board_from_fen(): bad FEN (pos=%d)\n",pos); c = fen[++pos]; } } // active colour if (c != ' ') my_fatal("board_from_fen(): bad FEN (pos=%d)\n",pos); c = fen[++pos]; switch (c) { case 'w': board->turn = White; break; case 'b': board->turn = Black; break; default: my_fatal("board_from_fen(): bad FEN (pos=%d)\n",pos); break; } c = fen[++pos]; // castling if (c != ' ') my_fatal("board_from_fen(): bad FEN (pos=%d)\n",pos); c = fen[++pos]; board->flags = FlagsNone; if (c == '-') { // no castling rights c = fen[++pos]; } else { if (c == 'K') { if (board->square[E1] == WK && board->square[H1] == WR) board->flags |= FlagsWhiteKingCastle; c = fen[++pos]; } if (c == 'Q') { if (board->square[E1] == WK && board->square[A1] == WR) board->flags |= FlagsWhiteQueenCastle; c = fen[++pos]; } if (c == 'k') { if (board->square[E8] == BK && board->square[H8] == BR) board->flags |= FlagsBlackKingCastle; c = fen[++pos]; } if (c == 'q') { if (board->square[E8] == BK && board->square[A8] == BR) board->flags |= FlagsBlackQueenCastle; c = fen[++pos]; } } // en-passant if (c != ' ') my_fatal("board_from_fen(): bad FEN (pos=%d)\n",pos); c = fen[++pos]; if (c == '-') { // no en-passant sq = SquareNone; c = fen[++pos]; } else { if (c < 'a' || c > 'h') my_fatal("board_from_fen(): bad FEN (pos=%d)\n",pos); file = file_from_char(c); c = fen[++pos]; if (c != (COLOUR_IS_WHITE(board->turn) ? '6' : '3')) my_fatal("board_from_fen(): bad FEN (pos=%d)\n",pos); rank = rank_from_char(c); c = fen[++pos]; sq = SQUARE_MAKE(file,rank); pawn = SQUARE_EP_DUAL(sq); if (board->square[sq] != Empty || board->square[pawn] != PAWN_MAKE(COLOUR_OPP(board->turn)) || (board->square[pawn-1] != PAWN_MAKE(board->turn) && board->square[pawn+1] != PAWN_MAKE(board->turn))) { sq = SquareNone; } } board->ep_square = sq; // halfmove clock board->ply_nb = 0; if (c != ' ') { if (!Strict) goto update; my_fatal("board_from_fen(): bad FEN (pos=%d)\n",pos); } c = fen[++pos]; if (!isdigit(c)) { if (!Strict) goto update; my_fatal("board_from_fen(): bad FEN (pos=%d)\n",pos); } board->ply_nb = atoi(&fen[pos]); // board update update: board_init_list(board); } // board_to_fen() bool board_to_fen(const board_t * board, char fen[], int size) { int pos; int file, rank; int sq, piece; int c; int len; ASSERT(board!=NULL); ASSERT(fen!=NULL); ASSERT(size>=92); // init if (size < 92) return false; pos = 0; // piece placement for (rank = Rank8; rank >= Rank1; rank--) { for (file = FileA; file <= FileH;) { sq = SQUARE_MAKE(file,rank); piece = board->square[sq]; ASSERT(piece==Empty||piece_is_ok(piece)); if (piece == Empty) { len = 0; for (; file <= FileH && board->square[SQUARE_MAKE(file,rank)] == Empty; file++) { len++; } ASSERT(len>=1&&len<=8); c = '0' + len; } else { c = piece_to_char(piece); file++; } fen[pos++] = c; } fen[pos++] = '/'; } fen[pos-1] = ' '; // HACK: remove the last '/' // active colour fen[pos++] = (COLOUR_IS_WHITE(board->turn)) ? 'w' : 'b'; fen[pos++] = ' '; // castling if (board->flags == FlagsNone) { fen[pos++] = '-'; } else { if ((board->flags & FlagsWhiteKingCastle) != 0) fen[pos++] = 'K'; if ((board->flags & FlagsWhiteQueenCastle) != 0) fen[pos++] = 'Q'; if ((board->flags & FlagsBlackKingCastle) != 0) fen[pos++] = 'k'; if ((board->flags & FlagsBlackQueenCastle) != 0) fen[pos++] = 'q'; } fen[pos++] = ' '; // en-passant if (board->ep_square == SquareNone) { fen[pos++] = '-'; } else { square_to_string(board->ep_square,&fen[pos],3); pos += 2; } fen[pos++] = ' '; // halfmove clock sprintf(&fen[pos],"%d 1",board->ply_nb); return true; } // end of fen.cpp fruit-2.1.dfsg-1.orig/src/main.cpp0000600000175000017500000000170710402400155016311 0ustar oliveroliver // main.cpp // includes #include #include #include "attack.h" #include "book.h" #include "hash.h" #include "move_do.h" #include "option.h" #include "pawn.h" #include "piece.h" #include "protocol.h" #include "random.h" #include "square.h" #include "trans.h" #include "util.h" #include "value.h" #include "vector.h" // functions // main() int main(int argc, char * argv[]) { // init util_init(); my_random_init(); // for opening book printf("Fruit 2.1 UCI by Fabien Letouzey\n"); // early initialisation (the rest is done after UCI options are parsed in protocol.cpp) option_init(); square_init(); piece_init(); pawn_init_bit(); value_init(); vector_init(); attack_init(); move_do_init(); random_init(); hash_init(); trans_init(Trans); book_init(); // loop loop(); return EXIT_SUCCESS; } // end of main.cpp fruit-2.1.dfsg-1.orig/src/move_legal.h0000600000175000017500000000061510402400155017141 0ustar oliveroliver // move_legal.h #ifndef MOVE_LEGAL_H #define MOVE_LEGAL_H // includes #include "board.h" #include "list.h" #include "util.h" // functions extern bool move_is_pseudo (int move, board_t * board); extern bool quiet_is_pseudo (int move, board_t * board); extern bool pseudo_is_legal (int move, board_t * board); #endif // !defined MOVE_LEGAL_H // end of move_legal.h fruit-2.1.dfsg-1.orig/src/square.cpp0000600000175000017500000000444010402400155016662 0ustar oliveroliver // square.cpp // includes #include "colour.h" #include "square.h" #include "util.h" // "constants" const int SquareFrom64[64] = { A1, B1, C1, D1, E1, F1, G1, H1, A2, B2, C2, D2, E2, F2, G2, H2, A3, B3, C3, D3, E3, F3, G3, H3, A4, B4, C4, D4, E4, F4, G4, H4, A5, B5, C5, D5, E5, F5, G5, H5, A6, B6, C6, D6, E6, F6, G6, H6, A7, B7, C7, D7, E7, F7, G7, H7, A8, B8, C8, D8, E8, F8, G8, H8, }; const int RankMask[ColourNb] = { 0, 0xF }; const int PromoteRank[ColourNb] = { 0xB0, 0x40 }; // variables int SquareTo64[SquareNb]; bool SquareIsPromote[SquareNb]; // functions // square_init() void square_init() { int sq; // SquareTo64[] for (sq = 0; sq < SquareNb; sq++) SquareTo64[sq] = -1; for (sq = 0; sq < 64; sq++) { SquareTo64[SquareFrom64[sq]] = sq; } // SquareIsPromote[] for (sq = 0; sq < SquareNb; sq++) { SquareIsPromote[sq] = SQUARE_IS_OK(sq) && (SQUARE_RANK(sq) == Rank1 || SQUARE_RANK(sq) == Rank8); } } // file_from_char() int file_from_char(int c) { ASSERT(c>='a'&&c<='h'); return FileA + (c - 'a'); } // rank_from_char() int rank_from_char(int c) { ASSERT(c>='1'&&c<='8'); return Rank1 + (c - '1'); } // file_to_char() int file_to_char(int file) { ASSERT(file>=FileA&&file<=FileH); return 'a' + (file - FileA); } // rank_to_char() int rank_to_char(int rank) { ASSERT(rank>=Rank1&&rank<=Rank8); return '1' + (rank - Rank1); } // square_to_string() bool square_to_string(int square, char string[], int size) { ASSERT(SQUARE_IS_OK(square)); ASSERT(string!=NULL); ASSERT(size>=3); if (size < 3) return false; string[0] = file_to_char(SQUARE_FILE(square)); string[1] = rank_to_char(SQUARE_RANK(square)); string[2] = '\0'; return true; } // square_from_string() int square_from_string(const char string[]) { int file, rank; ASSERT(string!=NULL); if (string[0] < 'a' || string[0] > 'h') return SquareNone; if (string[1] < '1' || string[1] > '8') return SquareNone; if (string[2] != '\0') return SquareNone; file = file_from_char(string[0]); rank = rank_from_char(string[1]); return SQUARE_MAKE(file,rank); } // end of square.cpp fruit-2.1.dfsg-1.orig/src/recog.cpp0000600000175000017500000001310310402400155016455 0ustar oliveroliver // recog.cpp // includes #include "board.h" #include "colour.h" #include "material.h" #include "piece.h" #include "recog.h" #include "util.h" #include "vector.h" // prototypes static bool kpk_draw (int wp, int wk, int bk, int turn); static bool kbpk_draw (int wp, int wb, int bk); // functions // recog_draw() bool recog_draw(const board_t * board) { material_info_t mat_info[1]; ASSERT(board!=NULL); // material if (board->piece_nb > 4) return false; material_get_info(mat_info,board); if ((mat_info->flags & DrawNodeFlag) == 0) return false; // recognisers if (false) { } else if (mat_info->recog == MAT_KK) { // KK return true; } else if (mat_info->recog == MAT_KBK) { // KBK (white) return true; } else if (mat_info->recog == MAT_KKB) { // KBK (black) return true; } else if (mat_info->recog == MAT_KNK) { // KNK (white) return true; } else if (mat_info->recog == MAT_KKN) { // KNK (black) return true; } else if (mat_info->recog == MAT_KPK) { // KPK (white) int me, opp; int wp, wk, bk; me = White; opp = COLOUR_OPP(me); wp = board->pawn[me][0]; wk = KING_POS(board,me); bk = KING_POS(board,opp); if (SQUARE_FILE(wp) >= FileE) { wp = SQUARE_FILE_MIRROR(wp); wk = SQUARE_FILE_MIRROR(wk); bk = SQUARE_FILE_MIRROR(bk); } if (kpk_draw(wp,wk,bk,board->turn)) { return true; } } else if (mat_info->recog == MAT_KKP) { // KPK (black) int me, opp; int wp, wk, bk; me = Black; opp = COLOUR_OPP(me); wp = SQUARE_RANK_MIRROR(board->pawn[me][0]); wk = SQUARE_RANK_MIRROR(KING_POS(board,me)); bk = SQUARE_RANK_MIRROR(KING_POS(board,opp)); if (SQUARE_FILE(wp) >= FileE) { wp = SQUARE_FILE_MIRROR(wp); wk = SQUARE_FILE_MIRROR(wk); bk = SQUARE_FILE_MIRROR(bk); } if (kpk_draw(wp,wk,bk,COLOUR_OPP(board->turn))) { return true; } } else if (mat_info->recog == MAT_KBKB) { // KBKB int wb, bb; wb = board->piece[White][1]; bb = board->piece[Black][1]; if (SQUARE_COLOUR(wb) == SQUARE_COLOUR(bb)) { // bishops on same colour return true; } } else if (mat_info->recog == MAT_KBPK) { // KBPK (white) int me, opp; int wp, wb, bk; me = White; opp = COLOUR_OPP(me); wp = board->pawn[me][0]; wb = board->piece[me][1]; bk = KING_POS(board,opp); if (SQUARE_FILE(wp) >= FileE) { wp = SQUARE_FILE_MIRROR(wp); wb = SQUARE_FILE_MIRROR(wb); bk = SQUARE_FILE_MIRROR(bk); } if (kbpk_draw(wp,wb,bk)) return true; } else if (mat_info->recog == MAT_KKBP) { // KBPK (black) int me, opp; int wp, wb, bk; me = Black; opp = COLOUR_OPP(me); wp = SQUARE_RANK_MIRROR(board->pawn[me][0]); wb = SQUARE_RANK_MIRROR(board->piece[me][1]); bk = SQUARE_RANK_MIRROR(KING_POS(board,opp)); if (SQUARE_FILE(wp) >= FileE) { wp = SQUARE_FILE_MIRROR(wp); wb = SQUARE_FILE_MIRROR(wb); bk = SQUARE_FILE_MIRROR(bk); } if (kbpk_draw(wp,wb,bk)) return true; } else { ASSERT(false); } return false; } // kpk_draw() static bool kpk_draw(int wp, int wk, int bk, int turn) { int wp_file, wp_rank; int wk_file; int bk_file, bk_rank; ASSERT(SQUARE_IS_OK(wp)); ASSERT(SQUARE_IS_OK(wk)); ASSERT(SQUARE_IS_OK(bk)); ASSERT(COLOUR_IS_OK(turn)); ASSERT(SQUARE_FILE(wp)<=FileD); wp_file = SQUARE_FILE(wp); wp_rank = SQUARE_RANK(wp); wk_file = SQUARE_FILE(wk); bk_file = SQUARE_FILE(bk); bk_rank = SQUARE_RANK(bk); if (false) { } else if (bk == wp+16) { if (wp_rank <= Rank6) { return true; } else { ASSERT(wp_rank==Rank7); if (COLOUR_IS_WHITE(turn)) { if (wk == wp-15 || wk == wp-17) return true; } else { if (wk != wp-15 && wk != wp-17) return true; } } } else if (bk == wp+32) { if (wp_rank <= Rank5) { return true; } else { ASSERT(wp_rank==Rank6); if (COLOUR_IS_WHITE(turn)) { if (wk != wp-1 && wk != wp+1) return true; } else { return true; } } } else if (wk == wp-1 || wk == wp+1) { if (bk == wk+32 && COLOUR_IS_WHITE(turn)) { // opposition return true; } } else if (wk == wp+15 || wk == wp+16 || wk == wp+17) { if (wp_rank <= Rank4) { if (bk == wk+32 && COLOUR_IS_WHITE(turn)) { // opposition return true; } } } // rook pawn if (wp_file == FileA) { if (DISTANCE(bk,A8) <= 1) return true; if (wk_file == FileA) { if (wp_rank == Rank2) wp_rank++; // HACK if (bk_file == FileC && bk_rank > wp_rank) return true; } } return false; } // kbpk_draw() static bool kbpk_draw (int wp, int wb, int bk) { ASSERT(SQUARE_IS_OK(wp)); ASSERT(SQUARE_IS_OK(wb)); ASSERT(SQUARE_IS_OK(bk)); if (SQUARE_FILE(wp) == FileA && DISTANCE(bk,A8) <= 1 && SQUARE_COLOUR(wb) != SQUARE_COLOUR(A8)) { return true; } return false; } // end of recog.cpp fruit-2.1.dfsg-1.orig/src/pawn.cpp0000600000175000017500000002751310402400155016335 0ustar oliveroliver // pawn.cpp // includes #include #include "board.h" #include "colour.h" #include "hash.h" #include "option.h" #include "pawn.h" #include "piece.h" #include "protocol.h" #include "square.h" #include "util.h" // constants static const bool UseTable = true; static const uint32 TableSize = 16384; // 256kB // types typedef pawn_info_t entry_t; struct pawn_t { entry_t * table; uint32 size; uint32 mask; uint32 used; sint64 read_nb; sint64 read_hit; sint64 write_nb; sint64 write_collision; }; // constants and variables static /* const */ int PawnStructureWeight = 256; // 100% static const int DoubledOpening = 10; static const int DoubledEndgame = 20; static const int IsolatedOpening = 10; static const int IsolatedOpeningOpen = 20; static const int IsolatedEndgame = 20; static const int BackwardOpening = 8; static const int BackwardOpeningOpen = 16; static const int BackwardEndgame = 10; static const int CandidateOpeningMin = 5; static const int CandidateOpeningMax = 55; static const int CandidateEndgameMin = 10; static const int CandidateEndgameMax = 110; // this was moved to eval.cpp /* static const int PassedOpeningMin = 10; static const int PassedOpeningMax = 70; static const int PassedEndgameMin = 20; static const int PassedEndgameMax = 140; */ static /* const */ int Bonus[RankNb]; // variables int BitEQ[16]; int BitLT[16]; int BitLE[16]; int BitGT[16]; int BitGE[16]; int BitFirst[0x100]; int BitLast[0x100]; int BitCount[0x100]; int BitRev[0x100]; static pawn_t Pawn[1]; static int BitRank1[RankNb]; static int BitRank2[RankNb]; static int BitRank3[RankNb]; // prototypes static void pawn_comp_info (pawn_info_t * info, const board_t * board); // functions // pawn_init_bit() void pawn_init_bit() { int rank; int first, last, count; int b, rev; // rank-indexed Bit*[] for (rank = 0; rank < RankNb; rank++) { BitEQ[rank] = 0; BitLT[rank] = 0; BitLE[rank] = 0; BitGT[rank] = 0; BitGE[rank] = 0; BitRank1[rank] = 0; BitRank2[rank] = 0; BitRank3[rank] = 0; } for (rank = Rank1; rank <= Rank8; rank++) { BitEQ[rank] = 1 << (rank - Rank1); BitLT[rank] = BitEQ[rank] - 1; BitLE[rank] = BitLT[rank] | BitEQ[rank]; BitGT[rank] = BitLE[rank] ^ 0xFF; BitGE[rank] = BitGT[rank] | BitEQ[rank]; } for (rank = Rank1; rank <= Rank8; rank++) { BitRank1[rank] = BitEQ[rank+1]; BitRank2[rank] = BitEQ[rank+1] | BitEQ[rank+2]; BitRank3[rank] = BitEQ[rank+1] | BitEQ[rank+2] | BitEQ[rank+3]; } // bit-indexed Bit*[] for (b = 0; b < 0x100; b++) { first = Rank8; // HACK for pawn shelter last = Rank1; // HACK count = 0; rev = 0; for (rank = Rank1; rank <= Rank8; rank++) { if ((b & BitEQ[rank]) != 0) { if (rank < first) first = rank; if (rank > last) last = rank; count++; rev |= BitEQ[RANK_OPP(rank)]; } } BitFirst[b] = first; BitLast[b] = last; BitCount[b] = count; BitRev[b] = rev; } } // pawn_init() void pawn_init() { int rank; // UCI options PawnStructureWeight = (option_get_int("Pawn Structure") * 256 + 50) / 100; // bonus for (rank = 0; rank < RankNb; rank++) Bonus[rank] = 0; Bonus[Rank4] = 26; Bonus[Rank5] = 77; Bonus[Rank6] = 154; Bonus[Rank7] = 256; // pawn hash-table Pawn->size = 0; Pawn->mask = 0; Pawn->table = NULL; } // pawn_alloc() void pawn_alloc() { ASSERT(sizeof(entry_t)==16); if (UseTable) { Pawn->size = TableSize; Pawn->mask = TableSize - 1; Pawn->table = (entry_t *) my_malloc(Pawn->size*sizeof(entry_t)); pawn_clear(); } } // pawn_clear() void pawn_clear() { if (Pawn->table != NULL) { memset(Pawn->table,0,Pawn->size*sizeof(entry_t)); } Pawn->used = 0; Pawn->read_nb = 0; Pawn->read_hit = 0; Pawn->write_nb = 0; Pawn->write_collision = 0; } // pawn_get_info() void pawn_get_info(pawn_info_t * info, const board_t * board) { uint64 key; entry_t * entry; ASSERT(info!=NULL); ASSERT(board!=NULL); // probe if (UseTable) { Pawn->read_nb++; key = board->pawn_key; entry = &Pawn->table[KEY_INDEX(key)&Pawn->mask]; if (entry->lock == KEY_LOCK(key)) { // found Pawn->read_hit++; *info = *entry; return; } } // calculation pawn_comp_info(info,board); // store if (UseTable) { Pawn->write_nb++; if (entry->lock == 0) { // HACK: assume free entry Pawn->used++; } else { Pawn->write_collision++; } *entry = *info; entry->lock = KEY_LOCK(key); } } // pawn_comp_info() static void pawn_comp_info(pawn_info_t * info, const board_t * board) { int colour; int file, rank; int me, opp; const sq_t * ptr; int sq; bool backward, candidate, doubled, isolated, open, passed; int t1, t2; int n; int bits; int opening[ColourNb], endgame[ColourNb]; int flags[ColourNb]; int file_bits[ColourNb]; int passed_bits[ColourNb]; int single_file[ColourNb]; ASSERT(info!=NULL); ASSERT(board!=NULL); // pawn_file[] #if DEBUG for (colour = 0; colour < ColourNb; colour++) { int pawn_file[FileNb]; me = colour; for (file = 0; file < FileNb; file++) { pawn_file[file] = 0; } for (ptr = &board->pawn[me][0]; (sq=*ptr) != SquareNone; ptr++) { file = SQUARE_FILE(sq); rank = PAWN_RANK(sq,me); ASSERT(file>=FileA&&file<=FileH); ASSERT(rank>=Rank2&&rank<=Rank7); pawn_file[file] |= BIT(rank); } for (file = 0; file < FileNb; file++) { if (board->pawn_file[colour][file] != pawn_file[file]) my_fatal("board->pawn_file[][]\n"); } } #endif // init for (colour = 0; colour < ColourNb; colour++) { opening[colour] = 0; endgame[colour] = 0; flags[colour] = 0; file_bits[colour] = 0; passed_bits[colour] = 0; single_file[colour] = SquareNone; } // features and scoring for (colour = 0; colour < ColourNb; colour++) { me = colour; opp = COLOUR_OPP(me); for (ptr = &board->pawn[me][0]; (sq=*ptr) != SquareNone; ptr++) { // init file = SQUARE_FILE(sq); rank = PAWN_RANK(sq,me); ASSERT(file>=FileA&&file<=FileH); ASSERT(rank>=Rank2&&rank<=Rank7); // flags file_bits[me] |= BIT(file); if (rank == Rank2) flags[me] |= BackRankFlag; // features backward = false; candidate = false; doubled = false; isolated = false; open = false; passed = false; t1 = board->pawn_file[me][file-1] | board->pawn_file[me][file+1]; t2 = board->pawn_file[me][file] | BitRev[board->pawn_file[opp][file]]; // doubled if ((board->pawn_file[me][file] & BitLT[rank]) != 0) { doubled = true; } // isolated and backward if (t1 == 0) { isolated = true; } else if ((t1 & BitLE[rank]) == 0) { backward = true; // really backward? if ((t1 & BitRank1[rank]) != 0) { ASSERT(rank+2<=Rank8); if (((t2 & BitRank1[rank]) | ((BitRev[board->pawn_file[opp][file-1]] | BitRev[board->pawn_file[opp][file+1]]) & BitRank2[rank])) == 0) { backward = false; } } else if (rank == Rank2 && ((t1 & BitEQ[rank+2]) != 0)) { ASSERT(rank+3<=Rank8); if (((t2 & BitRank2[rank]) | ((BitRev[board->pawn_file[opp][file-1]] | BitRev[board->pawn_file[opp][file+1]]) & BitRank3[rank])) == 0) { backward = false; } } } // open, candidate and passed if ((t2 & BitGT[rank]) == 0) { open = true; if (((BitRev[board->pawn_file[opp][file-1]] | BitRev[board->pawn_file[opp][file+1]]) & BitGT[rank]) == 0) { passed = true; passed_bits[me] |= BIT(file); } else { // candidate? n = 0; n += BIT_COUNT(board->pawn_file[me][file-1]&BitLE[rank]); n += BIT_COUNT(board->pawn_file[me][file+1]&BitLE[rank]); n -= BIT_COUNT(BitRev[board->pawn_file[opp][file-1]]&BitGT[rank]); n -= BIT_COUNT(BitRev[board->pawn_file[opp][file+1]]&BitGT[rank]); if (n >= 0) { // safe? n = 0; n += BIT_COUNT(board->pawn_file[me][file-1]&BitEQ[rank-1]); n += BIT_COUNT(board->pawn_file[me][file+1]&BitEQ[rank-1]); n -= BIT_COUNT(BitRev[board->pawn_file[opp][file-1]]&BitEQ[rank+1]); n -= BIT_COUNT(BitRev[board->pawn_file[opp][file+1]]&BitEQ[rank+1]); if (n >= 0) candidate = true; } } } // score if (doubled) { opening[me] -= DoubledOpening; endgame[me] -= DoubledEndgame; } if (isolated) { if (open) { opening[me] -= IsolatedOpeningOpen; endgame[me] -= IsolatedEndgame; } else { opening[me] -= IsolatedOpening; endgame[me] -= IsolatedEndgame; } } if (backward) { if (open) { opening[me] -= BackwardOpeningOpen; endgame[me] -= BackwardEndgame; } else { opening[me] -= BackwardOpening; endgame[me] -= BackwardEndgame; } } if (candidate) { opening[me] += quad(CandidateOpeningMin,CandidateOpeningMax,rank); endgame[me] += quad(CandidateEndgameMin,CandidateEndgameMax,rank); } // this was moved to the dynamic evaluation /* if (passed) { opening[me] += quad(PassedOpeningMin,PassedOpeningMax,rank); endgame[me] += quad(PassedEndgameMin,PassedEndgameMax,rank); } */ } } // store info info->opening = ((opening[White] - opening[Black]) * PawnStructureWeight) / 256; info->endgame = ((endgame[White] - endgame[Black]) * PawnStructureWeight) / 256; for (colour = 0; colour < ColourNb; colour++) { me = colour; opp = COLOUR_OPP(me); // draw flags bits = file_bits[me]; if (bits != 0 && (bits & (bits-1)) == 0) { // one set bit file = BIT_FIRST(bits); rank = BIT_FIRST(board->pawn_file[me][file]); ASSERT(rank>=Rank2); if (((BitRev[board->pawn_file[opp][file-1]] | BitRev[board->pawn_file[opp][file+1]]) & BitGT[rank]) == 0) { rank = BIT_LAST(board->pawn_file[me][file]); single_file[me] = SQUARE_MAKE(file,rank); } } info->flags[colour] = flags[colour]; info->passed_bits[colour] = passed_bits[colour]; info->single_file[colour] = single_file[colour]; } } // quad() int quad(int y_min, int y_max, int x) { int y; ASSERT(y_min>=0&&y_min<=y_max&&y_max<=+32767); ASSERT(x>=Rank2&&x<=Rank7); y = y_min + ((y_max - y_min) * Bonus[x] + 128) / 256; ASSERT(y>=y_min&&y<=y_max); return y; } // end of pawn.cpp fruit-2.1.dfsg-1.orig/src/book.h0000600000175000017500000000050510402400155015757 0ustar oliveroliver // book.h #ifndef BOOK_H #define BOOK_H // includes #include "board.h" #include "util.h" // functions extern void book_init (); extern void book_open (const char file_name[]); extern void book_close (); extern int book_move (board_t * board); #endif // !defined BOOK_H // end of book.h fruit-2.1.dfsg-1.orig/src/colour.h0000600000175000017500000000134110402400155016327 0ustar oliveroliver // colour.h #ifndef COLOUR_H #define COLOUR_H // includes #include "util.h" // constants const int ColourNone = -1; const int White = 0; const int Black = 1; const int ColourNb = 2; const int WhiteFlag = 1 << White; const int BlackFlag = 1 << Black; // macros #define COLOUR_IS_OK(colour) (((colour)&~1)==0) #define COLOUR_IS_WHITE(colour) ((colour)==White) #define COLOUR_IS_BLACK(colour) ((colour)!=White) #define COLOUR_IS(piece,colour) (FLAG_IS((piece),COLOUR_FLAG(colour))) #define FLAG_IS(piece,flag) (((piece)&(flag))!=0) #define COLOUR_OPP(colour) ((colour)^(White^Black)) #define COLOUR_FLAG(colour) ((colour)+1) #endif // !defined COLOUR_H // end of colour.h fruit-2.1.dfsg-1.orig/src/posix.cpp0000600000175000017500000001023310402400155016521 0ustar oliveroliver // posix.cpp // includes #include #include // REMOVE ME? #include #include #include #if defined(_WIN32) || defined(_WIN64) # include #else // assume POSIX # include // # include # include # include # include #endif #include "posix.h" #include "util.h" // constants static const bool UseDebug = false; // prototypes #if !defined(_WIN32) && !defined(_WIN64) static double duration (const struct timeval * tv); #endif // functions // input_available() bool input_available() { #if defined(_WIN32) || defined(_WIN64) static bool init = false, is_pipe; static HANDLE stdin_h; DWORD val, error; // val = 0; // needed to make the compiler happy? // have a look at the "local" buffer first, *this time before init (no idea if it helps)* if (UseDebug && !init) printf("info string init=%d stdin->_cnt=%d\n",int(init),stdin->_cnt); if (stdin->_cnt > 0) return true; // HACK: assumes FILE internals // input init (only done once) if (!init) { init = true; stdin_h = GetStdHandle(STD_INPUT_HANDLE); if (UseDebug && (stdin_h == NULL || stdin_h == INVALID_HANDLE_VALUE)) { error = GetLastError(); printf("info string GetStdHandle() failed, error=%d\n",error); } is_pipe = !GetConsoleMode(stdin_h,&val); // HACK: assumes pipe on failure if (UseDebug) printf("info string init=%d is_pipe=%d\n",int(init),int(is_pipe)); if (UseDebug && is_pipe) { // GetConsoleMode() failed, everybody assumes pipe then error = GetLastError(); printf("info string GetConsoleMode() failed, error=%d\n",error); } if (!is_pipe) { SetConsoleMode(stdin_h,val&~(ENABLE_MOUSE_INPUT|ENABLE_WINDOW_INPUT)); FlushConsoleInputBuffer(stdin_h); // no idea if we can lose data doing this } } // different polling depending on input type // does this code work at all for pipes? if (is_pipe) { if (!PeekNamedPipe(stdin_h,NULL,0,NULL,&val,NULL)) { if (UseDebug) { // PeekNamedPipe() failed, everybody assumes EOF then error = GetLastError(); printf("info string PeekNamedPipe() failed, error=%d\n",error); } return true; // HACK: assumes EOF on failure } if (UseDebug && val < 0) printf("info string PeekNamedPipe(): val=%d\n",val); return val > 0; // != 0??? } else { GetNumberOfConsoleInputEvents(stdin_h,&val); return val > 1; // no idea why 1 } return false; #else // assume POSIX int val; fd_set set[1]; struct timeval time_val[1]; FD_ZERO(set); FD_SET(STDIN_FILENO,set); time_val->tv_sec = 0; time_val->tv_usec = 0; val = select(STDIN_FILENO+1,set,NULL,NULL,time_val); if (val == -1 && errno != EINTR) { my_fatal("input_available(): select(): %s\n",strerror(errno)); } return val > 0; #endif } // now_real() double now_real() { #if defined(_WIN32) || defined(_WIN64) return double(GetTickCount()) / 1000.0; #else // assume POSIX struct timeval tv[1]; struct timezone tz[1]; tz->tz_minuteswest = 0; tz->tz_dsttime = 0; // DST_NONE not declared in linux if (gettimeofday(tv,tz) == -1) { // tz needed at all? my_fatal("now_real(): gettimeofday(): %s\n",strerror(errno)); } return duration(tv); #endif } // now_cpu() double now_cpu() { #if defined(_WIN32) || defined(_WIN64) return double(clock()) / double(CLOCKS_PER_SEC); // OK if CLOCKS_PER_SEC is small enough #else // assume POSIX struct rusage ru[1]; if (getrusage(RUSAGE_SELF,ru) == -1) { my_fatal("now_cpu(): getrusage(): %s\n",strerror(errno)); } return duration(&ru->ru_utime); #endif } // duration() #if !defined(_WIN32) && !defined(_WIN64) static double duration(const struct timeval * tv) { ASSERT(tv!=NULL); return double(tv->tv_sec) + double(tv->tv_usec) * 1E-6; } #endif // end of posix.cpp fruit-2.1.dfsg-1.orig/src/hash.cpp0000600000175000017500000000636310402400155016313 0ustar oliveroliver // hash.cpp // includes #include "board.h" #include "hash.h" #include "piece.h" #include "random.h" #include "square.h" #include "util.h" // variables uint64 Castle64[16]; // prototypes static uint64 hash_counter_key (int piece_12, int count); // functions // hash_init() void hash_init() { int i; for (i = 0; i < 16; i++) Castle64[i] = hash_castle_key(i); } // hash_key() uint64 hash_key(const board_t * board) { uint64 key; int colour; const sq_t * ptr; int sq, piece; ASSERT(board!=NULL); // init key = 0; // pieces for (colour = 0; colour < ColourNb; colour++) { for (ptr = &board->piece[colour][0]; (sq=*ptr) != SquareNone; ptr++) { piece = board->square[sq]; key ^= hash_piece_key(piece,sq); } for (ptr = &board->pawn[colour][0]; (sq=*ptr) != SquareNone; ptr++) { piece = board->square[sq]; key ^= hash_piece_key(piece,sq); } } // castle flags key ^= hash_castle_key(board->flags); // en-passant square sq = board->ep_square; if (sq != SquareNone) key ^= hash_ep_key(sq); // turn key ^= hash_turn_key(board->turn); return key; } // hash_pawn_key() uint64 hash_pawn_key(const board_t * board) { uint64 key; int colour; const sq_t * ptr; int sq, piece; ASSERT(board!=NULL); // init key = 0; // pawns for (colour = 0; colour < ColourNb; colour++) { for (ptr = &board->pawn[colour][0]; (sq=*ptr) != SquareNone; ptr++) { piece = board->square[sq]; key ^= hash_piece_key(piece,sq); } } return key; } // hash_material_key() uint64 hash_material_key(const board_t * board) { uint64 key; int piece_12, count; ASSERT(board!=NULL); // init key = 0; // counters for (piece_12 = 0; piece_12 < 12; piece_12++) { count = board->number[piece_12]; key ^= hash_counter_key(piece_12,count); } return key; } // hash_piece_key() uint64 hash_piece_key(int piece, int square) { ASSERT(piece_is_ok(piece)); ASSERT(SQUARE_IS_OK(square)); return RANDOM_64(RandomPiece+(PIECE_TO_12(piece)^1)*64+SQUARE_TO_64(square)); // HACK: ^1 for PolyGlot book } // hash_castle_key() uint64 hash_castle_key(int flags) { uint64 key; int i; ASSERT((flags&~0xF)==0); key = 0; for (i = 0; i < 4; i++) { if ((flags & (1<=0&&piece_12<12); ASSERT(count>=0&&count<=10); // init key = 0; // counter index = piece_12 * 16; for (i = 0; i < count; i++) key ^= RANDOM_64(index+i); return key; } // end of hash.cpp fruit-2.1.dfsg-1.orig/src/eval.h0000600000175000017500000000037110402400155015755 0ustar oliveroliver // eval.h #ifndef EVAL_H #define EVAL_H // includes #include "board.h" #include "util.h" // functions extern void eval_init (); extern int eval (const board_t * board); #endif // !defined EVAL_H // end of eval.h fruit-2.1.dfsg-1.orig/src/random.h0000600000175000017500000000053410402400155016307 0ustar oliveroliver // random.h #ifndef RANDOM_H #define RANDOM_H // includes #include "util.h" // constants const int RandomNb = 781; // macros #define RANDOM_64(n) (Random64[n]) // "constants" extern const uint64 Random64[RandomNb]; // functions extern void random_init (); #endif // !defined RANDOM_H // end of random.h fruit-2.1.dfsg-1.orig/src/hash.h0000600000175000017500000000161510402400155015753 0ustar oliveroliver // hash.h #ifndef HASH_H #define HASH_H // includes #include "board.h" #include "util.h" // macros #define KEY_INDEX(key) (uint32(key)) #define KEY_LOCK(key) (uint32((key)>>32)) // constants const int RandomPiece = 0; // 12 * 64 const int RandomCastle = 768; // 4 const int RandomEnPassant = 772; // 8 const int RandomTurn = 780; // 1 // variables extern uint64 Castle64[16]; // functions extern void hash_init (); extern uint64 hash_key (const board_t * board); extern uint64 hash_pawn_key (const board_t * board); extern uint64 hash_material_key (const board_t * board); extern uint64 hash_piece_key (int piece, int square); extern uint64 hash_castle_key (int flags); extern uint64 hash_ep_key (int square); extern uint64 hash_turn_key (int colour); #endif // !defined HASH_H // end of hash.h fruit-2.1.dfsg-1.orig/src/move_gen.h0000600000175000017500000000116210402400155016624 0ustar oliveroliver // move_gen.h #ifndef MOVE_GEN_H #define MOVE_GEN_H // includes #include "attack.h" #include "board.h" #include "list.h" #include "util.h" // functions extern void gen_legal_moves (list_t * list, board_t * board); extern void gen_moves (list_t * list, const board_t * board); extern void gen_captures (list_t * list, const board_t * board); extern void gen_quiet_moves (list_t * list, const board_t * board); extern void add_pawn_move (list_t * list, int from, int to); extern void add_promote (list_t * list, int move); #endif // !defined MOVE_GEN_H // end of move_gen.h fruit-2.1.dfsg-1.orig/src/square.h0000600000175000017500000000573410402400155016336 0ustar oliveroliver // square.h #ifndef SQUARE_H #define SQUARE_H // includes #include "colour.h" #include "util.h" // constants const int FileNb = 16; const int RankNb = 16; const int SquareNb = FileNb * RankNb; const int FileInc = +1; const int RankInc = +16; const int FileNone = 0; const int FileA = 0x4; const int FileB = 0x5; const int FileC = 0x6; const int FileD = 0x7; const int FileE = 0x8; const int FileF = 0x9; const int FileG = 0xA; const int FileH = 0xB; const int RankNone = 0; const int Rank1 = 0x4; const int Rank2 = 0x5; const int Rank3 = 0x6; const int Rank4 = 0x7; const int Rank5 = 0x8; const int Rank6 = 0x9; const int Rank7 = 0xA; const int Rank8 = 0xB; const int SquareNone = 0; const int A1=0x44, B1=0x45, C1=0x46, D1=0x47, E1=0x48, F1=0x49, G1=0x4A, H1=0x4B; const int A2=0x54, B2=0x55, C2=0x56, D2=0x57, E2=0x58, F2=0x59, G2=0x5A, H2=0x5B; const int A3=0x64, B3=0x65, C3=0x66, D3=0x67, E3=0x68, F3=0x69, G3=0x6A, H3=0x6B; const int A4=0x74, B4=0x75, C4=0x76, D4=0x77, E4=0x78, F4=0x79, G4=0x7A, H4=0x7B; const int A5=0x84, B5=0x85, C5=0x86, D5=0x87, E5=0x88, F5=0x89, G5=0x8A, H5=0x8B; const int A6=0x94, B6=0x95, C6=0x96, D6=0x97, E6=0x98, F6=0x99, G6=0x9A, H6=0x9B; const int A7=0xA4, B7=0xA5, C7=0xA6, D7=0xA7, E7=0xA8, F7=0xA9, G7=0xAA, H7=0xAB; const int A8=0xB4, B8=0xB5, C8=0xB6, D8=0xB7, E8=0xB8, F8=0xB9, G8=0xBA, H8=0xBB; const int Dark = 0; const int Light = 1; // macros #define SQUARE_IS_OK(square) ((((square)-0x44)&~0x77)==0) #define SQUARE_MAKE(file,rank) (((rank)<<4)|(file)) #define SQUARE_FILE(square) ((square)&0xF) #define SQUARE_RANK(square) ((square)>>4) #define SQUARE_FROM_64(square) (SquareFrom64[square]) #define SQUARE_TO_64(square) (SquareTo64[square]) #define SQUARE_IS_PROMOTE(square) (SquareIsPromote[square]) #define SQUARE_EP_DUAL(square) ((square)^16) #define SQUARE_COLOUR(square) (((square)^((square)>>4))&1) #define SQUARE_FILE_MIRROR(square) ((square)^0x0F) #define SQUARE_RANK_MIRROR(square) ((square)^0xF0) #define FILE_OPP(file) ((file)^0xF) #define RANK_OPP(rank) ((rank)^0xF) #define PAWN_RANK(square,colour) (SQUARE_RANK(square)^RankMask[colour]) #define PAWN_PROMOTE(square,colour) (PromoteRank[colour]|((square)&0xF)) // types typedef int sq_t; // "constants" extern const int SquareFrom64[64]; extern const int RankMask[ColourNb]; extern const int PromoteRank[ColourNb]; // variables extern int SquareTo64[SquareNb]; extern bool SquareIsPromote[SquareNb]; // functions extern void square_init (); extern int file_from_char (int c); extern int rank_from_char (int c); extern int file_to_char (int file); extern int rank_to_char (int rank); extern bool square_to_string (int square, char string[], int size); extern int square_from_string (const char string[]); #endif // !defined SQUARE_H // end of square.h fruit-2.1.dfsg-1.orig/src/protocol.cpp0000600000175000017500000003035310402400155017225 0ustar oliveroliver // protocol.cpp // includes #include #include #include #include #include "board.h" #include "book.h" #include "eval.h" #include "fen.h" #include "material.h" #include "move.h" #include "move_do.h" #include "move_legal.h" #include "option.h" #include "pawn.h" #include "posix.h" #include "protocol.h" #include "pst.h" #include "search.h" #include "trans.h" #include "util.h" // constants #define VERSION "2.1" static const double NormalRatio = 1.0; static const double PonderRatio = 1.25; // variables static bool Init; static bool Searching; // search in progress? static bool Infinite; // infinite or ponder mode? static bool Delay; // postpone "bestmove" in infinite/ponder mode? // prototypes static void init (); static void loop_step (); static void parse_go (char string[]); static void parse_position (char string[]); static void parse_setoption (char string[]); static void send_best_move (); static bool string_equal (const char s1[], const char s2[]); static bool string_start_with (const char s1[], const char s2[]); // functions // loop() void loop() { // init (to help debugging) Init = false; Searching = false; Infinite = false; Delay = false; search_clear(); board_from_fen(SearchInput->board,StartFen); // loop while (true) loop_step(); } // init() static void init() { if (!Init) { // late initialisation Init = true; if (option_get_bool("OwnBook")) { book_open(option_get_string("BookFile")); } trans_alloc(Trans); pawn_init(); pawn_alloc(); material_init(); material_alloc(); pst_init(); eval_init(); } } // event() void event() { while (!SearchInfo->stop && input_available()) loop_step(); } // loop_step() static void loop_step() { char string[65536]; // read a line get(string,65536); // parse if (false) { } else if (string_start_with(string,"debug ")) { // dummy } else if (string_start_with(string,"go ")) { if (!Searching && !Delay) { init(); parse_go(string); } else { ASSERT(false); } } else if (string_equal(string,"isready")) { if (!Searching && !Delay) { init(); } send("readyok"); // no need to wait when searching (dixit SMK) } else if (string_equal(string,"ponderhit")) { if (Searching) { ASSERT(Infinite); SearchInput->infinite = false; Infinite = false; } else if (Delay) { send_best_move(); Delay = false; } else { ASSERT(false); } } else if (string_start_with(string,"position ")) { if (!Searching && !Delay) { init(); parse_position(string); } else { ASSERT(false); } } else if (string_equal(string,"quit")) { ASSERT(!Searching); ASSERT(!Delay); exit(EXIT_SUCCESS); } else if (string_start_with(string,"setoption ")) { if (!Searching && !Delay) { parse_setoption(string); } else { ASSERT(false); } } else if (string_equal(string,"stop")) { if (Searching) { SearchInfo->stop = true; Infinite = false; } else if (Delay) { send_best_move(); Delay = false; } } else if (string_equal(string,"uci")) { ASSERT(!Searching); ASSERT(!Delay); send("id name Fruit " VERSION); send("id author Fabien Letouzey"); option_list(); send("uciok"); } else if (string_equal(string,"ucinewgame")) { if (!Searching && !Delay && Init) { trans_clear(Trans); } else { ASSERT(false); } } } // parse_go() static void parse_go(char string[]) { const char * ptr; bool infinite, ponder; int depth, mate, movestogo; sint64 nodes; double binc, btime, movetime, winc, wtime; double time, inc; double time_max, alloc; // init infinite = false; ponder = false; depth = -1; mate = -1; movestogo = -1; nodes = -1; binc = -1.0; btime = -1.0; movetime = -1.0; winc = -1.0; wtime = -1.0; // parse ptr = strtok(string," "); // skip "go" for (ptr = strtok(NULL," "); ptr != NULL; ptr = strtok(NULL," ")) { if (false) { } else if (string_equal(ptr,"binc")) { ptr = strtok(NULL," "); if (ptr == NULL) my_fatal("parse_go(): missing argument\n"); binc = double(atoi(ptr)) / 1000.0; ASSERT(binc>=0.0); } else if (string_equal(ptr,"btime")) { ptr = strtok(NULL," "); if (ptr == NULL) my_fatal("parse_go(): missing argument\n"); btime = double(atoi(ptr)) / 1000.0; ASSERT(btime>=0.0); } else if (string_equal(ptr,"depth")) { ptr = strtok(NULL," "); if (ptr == NULL) my_fatal("parse_go(): missing argument\n"); depth = atoi(ptr); ASSERT(depth>=0); } else if (string_equal(ptr,"infinite")) { infinite = true; } else if (string_equal(ptr,"mate")) { ptr = strtok(NULL," "); if (ptr == NULL) my_fatal("parse_go(): missing argument\n"); mate = atoi(ptr); ASSERT(mate>=0); } else if (string_equal(ptr,"movestogo")) { ptr = strtok(NULL," "); if (ptr == NULL) my_fatal("parse_go(): missing argument\n"); movestogo = atoi(ptr); ASSERT(movestogo>=0); } else if (string_equal(ptr,"movetime")) { ptr = strtok(NULL," "); if (ptr == NULL) my_fatal("parse_go(): missing argument\n"); movetime = double(atoi(ptr)) / 1000.0; ASSERT(movetime>=0.0); } else if (string_equal(ptr,"nodes")) { ptr = strtok(NULL," "); if (ptr == NULL) my_fatal("parse_go(): missing argument\n"); nodes = my_atoll(ptr); ASSERT(nodes>=0); } else if (string_equal(ptr,"ponder")) { ponder = true; } else if (string_equal(ptr,"searchmoves")) { // dummy } else if (string_equal(ptr,"winc")) { ptr = strtok(NULL," "); if (ptr == NULL) my_fatal("parse_go(): missing argument\n"); winc = double(atoi(ptr)) / 1000.0; ASSERT(winc>=0.0); } else if (string_equal(ptr,"wtime")) { ptr = strtok(NULL," "); if (ptr == NULL) my_fatal("parse_go(): missing argument\n"); wtime = double(atoi(ptr)) / 1000.0; ASSERT(wtime>=0.0); } } // init search_clear(); // depth limit if (depth >= 0) { SearchInput->depth_is_limited = true; SearchInput->depth_limit = depth; } else if (mate >= 0) { SearchInput->depth_is_limited = true; SearchInput->depth_limit = mate * 2 - 1; // HACK: move -> ply } // time limit if (COLOUR_IS_WHITE(SearchInput->board->turn)) { time = wtime; inc = winc; } else { time = btime; inc = binc; } if (movestogo <= 0 || movestogo > 30) movestogo = 30; // HACK if (inc < 0.0) inc = 0.0; if (movetime >= 0.0) { // fixed time SearchInput->time_is_limited = true; SearchInput->time_limit_1 = movetime * 5.0; // HACK to avoid early exit SearchInput->time_limit_2 = movetime; } else if (time >= 0.0) { // dynamic allocation time_max = time * 0.95 - 1.0; if (time_max < 0.0) time_max = 0.0; SearchInput->time_is_limited = true; alloc = (time_max + inc * double(movestogo-1)) / double(movestogo); alloc *= (option_get_bool("Ponder") ? PonderRatio : NormalRatio); if (alloc > time_max) alloc = time_max; SearchInput->time_limit_1 = alloc; alloc = (time_max + inc * double(movestogo-1)) * 0.5; if (alloc < SearchInput->time_limit_1) alloc = SearchInput->time_limit_1; if (alloc > time_max) alloc = time_max; SearchInput->time_limit_2 = alloc; } if (infinite || ponder) SearchInput->infinite = true; // search ASSERT(!Searching); ASSERT(!Delay); Searching = true; Infinite = infinite || ponder; Delay = false; search(); search_update_current(); ASSERT(Searching); ASSERT(!Delay); Searching = false; Delay = Infinite; if (!Delay) send_best_move(); } // parse_position() static void parse_position(char string[]) { const char * fen; char * moves; const char * ptr; char move_string[256]; int move; undo_t undo[1]; // init fen = strstr(string,"fen "); moves = strstr(string,"moves "); // start position if (fen != NULL) { // "fen" present if (moves != NULL) { // "moves" present ASSERT(moves>fen); moves[-1] = '\0'; // dirty, but so is UCI } board_from_fen(SearchInput->board,fen+4); // CHANGE ME } else { // HACK: assumes startpos board_from_fen(SearchInput->board,StartFen); } // moves if (moves != NULL) { // "moves" present ptr = moves + 6; while (*ptr != '\0') { move_string[0] = *ptr++; move_string[1] = *ptr++; move_string[2] = *ptr++; move_string[3] = *ptr++; if (*ptr == '\0' || *ptr == ' ') { move_string[4] = '\0'; } else { // promote move_string[4] = *ptr++; move_string[5] = '\0'; } move = move_from_string(move_string,SearchInput->board); move_do(SearchInput->board,move,undo); while (*ptr == ' ') ptr++; } } } // parse_setoption() static void parse_setoption(char string[]) { const char * name; char * value; // init name = strstr(string,"name "); value = strstr(string,"value "); if (name == NULL || value == NULL || name >= value) return; // ignore buttons value[-1] = '\0'; // HACK name += 5; value += 6; // update option_set(name,value); // update transposition-table size if needed if (Init && my_string_equal(name,"Hash")) { // Init => already allocated ASSERT(!Searching); if (option_get_int("Hash") >= 4) { trans_free(Trans); trans_alloc(Trans); } } } // send_best_move() static void send_best_move() { double time, speed, cpu; sint64 node_nb; char move_string[256]; char ponder_string[256]; int move; mv_t * pv; // info // HACK: should be in search.cpp time = SearchCurrent->time; speed = SearchCurrent->speed; cpu = SearchCurrent->cpu; node_nb = SearchCurrent->node_nb; send("info time %.0f nodes " S64_FORMAT " nps %.0f cpuload %.0f",time*1000.0,node_nb,speed,cpu*1000.0); trans_stats(Trans); // pawn_stats(); // material_stats(); // best move move = SearchBest->move; pv = SearchBest->pv; move_to_string(move,move_string,256); if (pv[0] == move && move_is_ok(pv[1])) { move_to_string(pv[1],ponder_string,256); send("bestmove %s ponder %s",move_string,ponder_string); } else { send("bestmove %s",move_string); } } // get() void get(char string[], int size) { ASSERT(string!=NULL); ASSERT(size>=65536); if (!my_file_read_line(stdin,string,size)) { // EOF exit(EXIT_SUCCESS); } } // send() void send(const char format[], ...) { va_list arg_list; char string[4096]; ASSERT(format!=NULL); va_start(arg_list,format); vsprintf(string,format,arg_list); va_end(arg_list); fprintf(stdout,"%s\n",string); } // string_equal() static bool string_equal(const char s1[], const char s2[]) { ASSERT(s1!=NULL); ASSERT(s2!=NULL); return strcmp(s1,s2) == 0; } // string_start_with() static bool string_start_with(const char s1[], const char s2[]) { ASSERT(s1!=NULL); ASSERT(s2!=NULL); return strstr(s1,s2) == s1; } // end of protocol.cpp fruit-2.1.dfsg-1.orig/src/search.h0000600000175000017500000000356410402400155016302 0ustar oliveroliver // search.h #ifndef SEARCH_H #define SEARCH_H // includes #include #include "board.h" #include "list.h" #include "move.h" #include "util.h" // constants const int DepthMax = 64; const int HeightMax = 256; const int SearchNormal = 0; const int SearchShort = 1; const int SearchUnknown = 0; const int SearchUpper = 1; const int SearchLower = 2; const int SearchExact = 3; // types struct search_input_t { board_t board[1]; list_t list[1]; bool infinite; bool depth_is_limited; int depth_limit; bool time_is_limited; double time_limit_1; double time_limit_2; }; struct search_info_t { jmp_buf buf; bool can_stop; bool stop; int check_nb; int check_inc; double last_time; }; struct search_root_t { list_t list[1]; int depth; int move; int move_pos; int move_nb; int last_value; bool bad_1; bool bad_2; bool change; bool easy; bool flag; }; struct search_best_t { int move; int value; int flags; int depth; mv_t pv[HeightMax]; }; struct search_current_t { board_t board[1]; my_timer_t timer[1]; int max_depth; sint64 node_nb; double time; double speed; double cpu; }; // variables extern search_input_t SearchInput[1]; extern search_info_t SearchInfo[1]; extern search_best_t SearchBest[1]; extern search_root_t SearchRoot[1]; extern search_current_t SearchCurrent[1]; // functions extern bool depth_is_ok (int depth); extern bool height_is_ok (int height); extern void search_clear (); extern void search (); extern void search_update_best (); extern void search_update_root (); extern void search_update_current (); extern void search_check (); #endif // !defined SEARCH_H // end of search.h fruit-2.1.dfsg-1.orig/src/search_full.h0000600000175000017500000000055310402400155017317 0ustar oliveroliver // search_full.h #ifndef SEARCH_FULL_H #define SEARCH_FULL_H // includes #include "board.h" #include "util.h" // functions extern void search_full_init (list_t * list, board_t * board); extern int search_full_root (list_t * list, board_t * board, int depth, int search_type); #endif // !defined SEARCH_FULL_H // end of search_full.h fruit-2.1.dfsg-1.orig/src/eval.cpp0000600000175000017500000013037610402400155016321 0ustar oliveroliver // eval.cpp // includes #include // for abs() #include "attack.h" #include "board.h" #include "colour.h" #include "eval.h" #include "material.h" #include "move.h" #include "option.h" #include "pawn.h" #include "piece.h" #include "see.h" #include "util.h" #include "value.h" #include "vector.h" // macros #define THROUGH(piece) ((piece)==Empty) // constants and variables static /* const */ int PieceActivityWeight = 256; // 100% static /* const */ int KingSafetyWeight = 256; // 100% static /* const */ int PassedPawnWeight = 256; // 100% static const int KnightUnit = 4; static const int BishopUnit = 6; static const int RookUnit = 7; static const int QueenUnit = 13; static const int MobMove = 1; static const int MobAttack = 1; static const int MobDefense = 0; static const int KnightMobOpening = 4; static const int KnightMobEndgame = 4; static const int BishopMobOpening = 5; static const int BishopMobEndgame = 5; static const int RookMobOpening = 2; static const int RookMobEndgame = 4; static const int QueenMobOpening = 1; static const int QueenMobEndgame = 2; static const int KingMobOpening = 0; static const int KingMobEndgame = 0; static const bool UseOpenFile = true; static const int RookSemiOpenFileOpening = 10; static const int RookSemiOpenFileEndgame = 10; static const int RookOpenFileOpening = 20; static const int RookOpenFileEndgame = 20; static const int RookSemiKingFileOpening = 10; static const int RookKingFileOpening = 20; static const bool UseKingAttack = true; static const int KingAttackOpening = 20; static const bool UseShelter = true; static const int ShelterOpening = 256; // 100% static const bool UseStorm = true; static const int StormOpening = 10; static const int Rook7thOpening = 20; static const int Rook7thEndgame = 40; static const int Queen7thOpening = 10; static const int Queen7thEndgame = 20; static const int TrappedBishop = 100; static const int BlockedBishop = 50; static const int BlockedRook = 50; static const int PassedOpeningMin = 10; static const int PassedOpeningMax = 70; static const int PassedEndgameMin = 20; static const int PassedEndgameMax = 140; static const int UnstoppablePasser = 800; static const int FreePasser = 60; static const int AttackerDistance = 5; static const int DefenderDistance = 20; // "constants" static const int KingAttackWeight[16] = { 0, 0, 128, 192, 224, 240, 248, 252, 254, 255, 256, 256 ,256, 256, 256, 256, }; // variables static int MobUnit[ColourNb][PieceNb]; static int KingAttackUnit[PieceNb]; // prototypes static void eval_draw (const board_t * board, const material_info_t * mat_info, const pawn_info_t * pawn_info, int mul[2]); static void eval_piece (const board_t * board, const material_info_t * mat_info, const pawn_info_t * pawn_info, int * opening, int * endgame); static void eval_king (const board_t * board, const material_info_t * mat_info, int * opening, int * endgame); static void eval_passer (const board_t * board, const pawn_info_t * pawn_info, int * opening, int * endgame); static void eval_pattern (const board_t * board, int * opening, int * endgame); static bool unstoppable_passer (const board_t * board, int pawn, int colour); static bool king_passer (const board_t * board, int pawn, int colour); static bool free_passer (const board_t * board, int pawn, int colour); static int pawn_att_dist (int pawn, int king, int colour); static int pawn_def_dist (int pawn, int king, int colour); static void draw_init_list (int list[], const board_t * board, int pawn_colour); static bool draw_kpkq (const int list[], int turn); static bool draw_kpkr (const int list[], int turn); static bool draw_kpkb (const int list[], int turn); static bool draw_kpkn (const int list[], int turn); static bool draw_knpk (const int list[], int turn); static bool draw_krpkr (const int list[], int turn); static bool draw_kbpkb (const int list[], int turn); static int shelter_square (const board_t * board, int square, int colour); static int shelter_file (const board_t * board, int file, int rank, int colour); static int storm_file (const board_t * board, int file, int colour); static bool bishop_can_attack (const board_t * board, int to, int colour); // functions // eval_init() void eval_init() { int colour; int piece; // UCI options PieceActivityWeight = (option_get_int("Piece Activity") * 256 + 50) / 100; KingSafetyWeight = (option_get_int("King Safety") * 256 + 50) / 100; PassedPawnWeight = (option_get_int("Passed Pawns") * 256 + 50) / 100; // mobility table for (colour = 0; colour < ColourNb; colour++) { for (piece = 0; piece < PieceNb; piece++) { MobUnit[colour][piece] = 0; } } MobUnit[White][Empty] = MobMove; MobUnit[White][BP] = MobAttack; MobUnit[White][BN] = MobAttack; MobUnit[White][BB] = MobAttack; MobUnit[White][BR] = MobAttack; MobUnit[White][BQ] = MobAttack; MobUnit[White][BK] = MobAttack; MobUnit[White][WP] = MobDefense; MobUnit[White][WN] = MobDefense; MobUnit[White][WB] = MobDefense; MobUnit[White][WR] = MobDefense; MobUnit[White][WQ] = MobDefense; MobUnit[White][WK] = MobDefense; MobUnit[Black][Empty] = MobMove; MobUnit[Black][WP] = MobAttack; MobUnit[Black][WN] = MobAttack; MobUnit[Black][WB] = MobAttack; MobUnit[Black][WR] = MobAttack; MobUnit[Black][WQ] = MobAttack; MobUnit[Black][WK] = MobAttack; MobUnit[Black][BP] = MobDefense; MobUnit[Black][BN] = MobDefense; MobUnit[Black][BB] = MobDefense; MobUnit[Black][BR] = MobDefense; MobUnit[Black][BQ] = MobDefense; MobUnit[Black][BK] = MobDefense; // KingAttackUnit[] for (piece = 0; piece < PieceNb; piece++) { KingAttackUnit[piece] = 0; } KingAttackUnit[WN] = 1; KingAttackUnit[WB] = 1; KingAttackUnit[WR] = 2; KingAttackUnit[WQ] = 4; KingAttackUnit[BN] = 1; KingAttackUnit[BB] = 1; KingAttackUnit[BR] = 2; KingAttackUnit[BQ] = 4; } // eval() int eval(const board_t * board) { int opening, endgame; material_info_t mat_info[1]; pawn_info_t pawn_info[1]; int mul[ColourNb]; int phase; int eval; int wb, bb; ASSERT(board!=NULL); ASSERT(board_is_legal(board)); ASSERT(!board_is_check(board)); // exceptions are extremely rare // init opening = 0; endgame = 0; // material material_get_info(mat_info,board); opening += mat_info->opening; endgame += mat_info->endgame; mul[White] = mat_info->mul[White]; mul[Black] = mat_info->mul[Black]; // PST opening += board->opening; endgame += board->endgame; // pawns pawn_get_info(pawn_info,board); opening += pawn_info->opening; endgame += pawn_info->endgame; // draw eval_draw(board,mat_info,pawn_info,mul); if (mat_info->mul[White] < mul[White]) mul[White] = mat_info->mul[White]; if (mat_info->mul[Black] < mul[Black]) mul[Black] = mat_info->mul[Black]; if (mul[White] == 0 && mul[Black] == 0) return ValueDraw; // eval eval_piece(board,mat_info,pawn_info,&opening,&endgame); eval_king(board,mat_info,&opening,&endgame); eval_passer(board,pawn_info,&opening,&endgame); eval_pattern(board,&opening,&endgame); // phase mix phase = mat_info->phase; eval = ((opening * (256 - phase)) + (endgame * phase)) / 256; // drawish bishop endgames if ((mat_info->flags & DrawBishopFlag) != 0) { wb = board->piece[White][1]; ASSERT(PIECE_IS_BISHOP(board->square[wb])); bb = board->piece[Black][1]; ASSERT(PIECE_IS_BISHOP(board->square[bb])); if (SQUARE_COLOUR(wb) != SQUARE_COLOUR(bb)) { if (mul[White] == 16) mul[White] = 8; // 1/2 if (mul[Black] == 16) mul[Black] = 8; // 1/2 } } // draw bound if (eval > ValueDraw) { eval = (eval * mul[White]) / 16; } else if (eval < ValueDraw) { eval = (eval * mul[Black]) / 16; } // value range if (eval < -ValueEvalInf) eval = -ValueEvalInf; if (eval > +ValueEvalInf) eval = +ValueEvalInf; ASSERT(eval>=-ValueEvalInf&&eval<=+ValueEvalInf); // turn if (COLOUR_IS_BLACK(board->turn)) eval = -eval; ASSERT(!value_is_mate(eval)); return eval; } // eval_draw() static void eval_draw(const board_t * board, const material_info_t * mat_info, const pawn_info_t * pawn_info, int mul[2]) { int colour; int me, opp; int pawn, king; int pawn_file; int prom; int list[7+1]; ASSERT(board!=NULL); ASSERT(mat_info!=NULL); ASSERT(pawn_info!=NULL); ASSERT(mul!=NULL); // draw patterns for (colour = 0; colour < ColourNb; colour++) { me = colour; opp = COLOUR_OPP(me); // KB*P+K* draw if ((mat_info->cflags[me] & MatRookPawnFlag) != 0) { pawn = pawn_info->single_file[me]; if (pawn != SquareNone) { // all pawns on one file pawn_file = SQUARE_FILE(pawn); if (pawn_file == FileA || pawn_file == FileH) { king = KING_POS(board,opp); prom = PAWN_PROMOTE(pawn,me); if (DISTANCE(king,prom) <= 1 && !bishop_can_attack(board,prom,me)) { mul[me] = 0; } } } } // K(B)P+K+ draw if ((mat_info->cflags[me] & MatBishopFlag) != 0) { pawn = pawn_info->single_file[me]; if (pawn != SquareNone) { // all pawns on one file king = KING_POS(board,opp); if (SQUARE_FILE(king) == SQUARE_FILE(pawn) && PAWN_RANK(king,me) > PAWN_RANK(pawn,me) && !bishop_can_attack(board,king,me)) { mul[me] = 1; // 1/16 } } } // KNPK* draw if ((mat_info->cflags[me] & MatKnightFlag) != 0) { pawn = board->pawn[me][0]; king = KING_POS(board,opp); if (SQUARE_FILE(king) == SQUARE_FILE(pawn) && PAWN_RANK(king,me) > PAWN_RANK(pawn,me) && PAWN_RANK(pawn,me) <= Rank6) { mul[me] = 1; // 1/16 } } } // recognisers, only heuristic draws here! if (false) { } else if (mat_info->recog == MAT_KPKQ) { // KPKQ (white) draw_init_list(list,board,White); if (draw_kpkq(list,board->turn)) { mul[White] = 1; // 1/16; mul[Black] = 1; // 1/16; } } else if (mat_info->recog == MAT_KQKP) { // KPKQ (black) draw_init_list(list,board,Black); if (draw_kpkq(list,COLOUR_OPP(board->turn))) { mul[White] = 1; // 1/16; mul[Black] = 1; // 1/16; } } else if (mat_info->recog == MAT_KPKR) { // KPKR (white) draw_init_list(list,board,White); if (draw_kpkr(list,board->turn)) { mul[White] = 1; // 1/16; mul[Black] = 1; // 1/16; } } else if (mat_info->recog == MAT_KRKP) { // KPKR (black) draw_init_list(list,board,Black); if (draw_kpkr(list,COLOUR_OPP(board->turn))) { mul[White] = 1; // 1/16; mul[Black] = 1; // 1/16; } } else if (mat_info->recog == MAT_KPKB) { // KPKB (white) draw_init_list(list,board,White); if (draw_kpkb(list,board->turn)) { mul[White] = 1; // 1/16; mul[Black] = 1; // 1/16; } } else if (mat_info->recog == MAT_KBKP) { // KPKB (black) draw_init_list(list,board,Black); if (draw_kpkb(list,COLOUR_OPP(board->turn))) { mul[White] = 1; // 1/16; mul[Black] = 1; // 1/16; } } else if (mat_info->recog == MAT_KPKN) { // KPKN (white) draw_init_list(list,board,White); if (draw_kpkn(list,board->turn)) { mul[White] = 1; // 1/16; mul[Black] = 1; // 1/16; } } else if (mat_info->recog == MAT_KNKP) { // KPKN (black) draw_init_list(list,board,Black); if (draw_kpkn(list,COLOUR_OPP(board->turn))) { mul[White] = 1; // 1/16; mul[Black] = 1; // 1/16; } } else if (mat_info->recog == MAT_KNPK) { // KNPK (white) draw_init_list(list,board,White); if (draw_knpk(list,board->turn)) { mul[White] = 1; // 1/16; mul[Black] = 1; // 1/16; } } else if (mat_info->recog == MAT_KKNP) { // KNPK (black) draw_init_list(list,board,Black); if (draw_knpk(list,COLOUR_OPP(board->turn))) { mul[White] = 1; // 1/16; mul[Black] = 1; // 1/16; } } else if (mat_info->recog == MAT_KRPKR) { // KRPKR (white) draw_init_list(list,board,White); if (draw_krpkr(list,board->turn)) { mul[White] = 1; // 1/16; mul[Black] = 1; // 1/16; } } else if (mat_info->recog == MAT_KRKRP) { // KRPKR (black) draw_init_list(list,board,Black); if (draw_krpkr(list,COLOUR_OPP(board->turn))) { mul[White] = 1; // 1/16; mul[Black] = 1; // 1/16; } } else if (mat_info->recog == MAT_KBPKB) { // KBPKB (white) draw_init_list(list,board,White); if (draw_kbpkb(list,board->turn)) { mul[White] = 1; // 1/16; mul[Black] = 1; // 1/16; } } else if (mat_info->recog == MAT_KBKBP) { // KBPKB (black) draw_init_list(list,board,Black); if (draw_kbpkb(list,COLOUR_OPP(board->turn))) { mul[White] = 1; // 1/16; mul[Black] = 1; // 1/16; } } } // eval_piece() static void eval_piece(const board_t * board, const material_info_t * mat_info, const pawn_info_t * pawn_info, int * opening, int * endgame) { int colour; int op[ColourNb], eg[ColourNb]; int me, opp; int opp_flag; const sq_t * ptr; int from, to; int piece; int mob; int capture; const int * unit; int rook_file, king_file; int king; int delta; ASSERT(board!=NULL); ASSERT(mat_info!=NULL); ASSERT(pawn_info!=NULL); ASSERT(opening!=NULL); ASSERT(endgame!=NULL); // init for (colour = 0; colour < ColourNb; colour++) { op[colour] = 0; eg[colour] = 0; } // eval for (colour = 0; colour < ColourNb; colour++) { me = colour; opp = COLOUR_OPP(me); opp_flag = COLOUR_FLAG(opp); unit = MobUnit[me]; // piece loop for (ptr = &board->piece[me][1]; (from=*ptr) != SquareNone; ptr++) { // HACK: no king piece = board->square[from]; switch (PIECE_TYPE(piece)) { case Knight64: // mobility mob = -KnightUnit; mob += unit[board->square[from-33]]; mob += unit[board->square[from-31]]; mob += unit[board->square[from-18]]; mob += unit[board->square[from-14]]; mob += unit[board->square[from+14]]; mob += unit[board->square[from+18]]; mob += unit[board->square[from+31]]; mob += unit[board->square[from+33]]; op[me] += mob * KnightMobOpening; eg[me] += mob * KnightMobEndgame; break; case Bishop64: // mobility mob = -BishopUnit; for (to = from-17; capture=board->square[to], THROUGH(capture); to -= 17) mob += MobMove; mob += unit[capture]; for (to = from-15; capture=board->square[to], THROUGH(capture); to -= 15) mob += MobMove; mob += unit[capture]; for (to = from+15; capture=board->square[to], THROUGH(capture); to += 15) mob += MobMove; mob += unit[capture]; for (to = from+17; capture=board->square[to], THROUGH(capture); to += 17) mob += MobMove; mob += unit[capture]; op[me] += mob * BishopMobOpening; eg[me] += mob * BishopMobEndgame; break; case Rook64: // mobility mob = -RookUnit; for (to = from-16; capture=board->square[to], THROUGH(capture); to -= 16) mob += MobMove; mob += unit[capture]; for (to = from- 1; capture=board->square[to], THROUGH(capture); to -= 1) mob += MobMove; mob += unit[capture]; for (to = from+ 1; capture=board->square[to], THROUGH(capture); to += 1) mob += MobMove; mob += unit[capture]; for (to = from+16; capture=board->square[to], THROUGH(capture); to += 16) mob += MobMove; mob += unit[capture]; op[me] += mob * RookMobOpening; eg[me] += mob * RookMobEndgame; // open file if (UseOpenFile) { op[me] -= RookOpenFileOpening / 2; eg[me] -= RookOpenFileEndgame / 2; rook_file = SQUARE_FILE(from); if (board->pawn_file[me][rook_file] == 0) { // no friendly pawn op[me] += RookSemiOpenFileOpening; eg[me] += RookSemiOpenFileEndgame; if (board->pawn_file[opp][rook_file] == 0) { // no enemy pawn op[me] += RookOpenFileOpening - RookSemiOpenFileOpening; eg[me] += RookOpenFileEndgame - RookSemiOpenFileEndgame; } if ((mat_info->cflags[opp] & MatKingFlag) != 0) { king = KING_POS(board,opp); king_file = SQUARE_FILE(king); delta = abs(rook_file-king_file); // file distance if (delta <= 1) { op[me] += RookSemiKingFileOpening; if (delta == 0) op[me] += RookKingFileOpening - RookSemiKingFileOpening; } } } } // 7th rank if (PAWN_RANK(from,me) == Rank7) { if ((pawn_info->flags[opp] & BackRankFlag) != 0 // opponent pawn on 7th rank || PAWN_RANK(KING_POS(board,opp),me) == Rank8) { op[me] += Rook7thOpening; eg[me] += Rook7thEndgame; } } break; case Queen64: // mobility mob = -QueenUnit; for (to = from-17; capture=board->square[to], THROUGH(capture); to -= 17) mob += MobMove; mob += unit[capture]; for (to = from-16; capture=board->square[to], THROUGH(capture); to -= 16) mob += MobMove; mob += unit[capture]; for (to = from-15; capture=board->square[to], THROUGH(capture); to -= 15) mob += MobMove; mob += unit[capture]; for (to = from- 1; capture=board->square[to], THROUGH(capture); to -= 1) mob += MobMove; mob += unit[capture]; for (to = from+ 1; capture=board->square[to], THROUGH(capture); to += 1) mob += MobMove; mob += unit[capture]; for (to = from+15; capture=board->square[to], THROUGH(capture); to += 15) mob += MobMove; mob += unit[capture]; for (to = from+16; capture=board->square[to], THROUGH(capture); to += 16) mob += MobMove; mob += unit[capture]; for (to = from+17; capture=board->square[to], THROUGH(capture); to += 17) mob += MobMove; mob += unit[capture]; op[me] += mob * QueenMobOpening; eg[me] += mob * QueenMobEndgame; // 7th rank if (PAWN_RANK(from,me) == Rank7) { if ((pawn_info->flags[opp] & BackRankFlag) != 0 // opponent pawn on 7th rank || PAWN_RANK(KING_POS(board,opp),me) == Rank8) { op[me] += Queen7thOpening; eg[me] += Queen7thEndgame; } } break; } } } // update *opening += ((op[White] - op[Black]) * PieceActivityWeight) / 256; *endgame += ((eg[White] - eg[Black]) * PieceActivityWeight) / 256; } // eval_king() static void eval_king(const board_t * board, const material_info_t * mat_info, int * opening, int * endgame) { int colour; int op[ColourNb], eg[ColourNb]; int me, opp; int from; int penalty_1, penalty_2; int tmp; int penalty; int king; const sq_t * ptr; int piece; int attack_tot; int piece_nb; ASSERT(board!=NULL); ASSERT(mat_info!=NULL); ASSERT(opening!=NULL); ASSERT(endgame!=NULL); // init for (colour = 0; colour < ColourNb; colour++) { op[colour] = 0; eg[colour] = 0; } // king attacks if (UseKingAttack) { for (colour = 0; colour < ColourNb; colour++) { if ((mat_info->cflags[colour] & MatKingFlag) != 0) { me = colour; opp = COLOUR_OPP(me); king = KING_POS(board,me); // piece attacks attack_tot = 0; piece_nb = 0; for (ptr = &board->piece[opp][1]; (from=*ptr) != SquareNone; ptr++) { // HACK: no king piece = board->square[from]; if (piece_attack_king(board,piece,from,king)) { piece_nb++; attack_tot += KingAttackUnit[piece]; } } // scoring ASSERT(piece_nb>=0&&piece_nb<16); op[colour] -= (attack_tot * KingAttackOpening * KingAttackWeight[piece_nb]) / 256; } } } // white pawn shelter if (UseShelter && (mat_info->cflags[White] & MatKingFlag) != 0) { me = White; // king penalty_1 = shelter_square(board,KING_POS(board,me),me); // castling penalty_2 = penalty_1; if ((board->flags & FlagsWhiteKingCastle) != 0) { tmp = shelter_square(board,G1,me); if (tmp < penalty_2) penalty_2 = tmp; } if ((board->flags & FlagsWhiteQueenCastle) != 0) { tmp = shelter_square(board,B1,me); if (tmp < penalty_2) penalty_2 = tmp; } ASSERT(penalty_2>=0&&penalty_2<=penalty_1); // penalty penalty = (penalty_1 + penalty_2) / 2; ASSERT(penalty>=0); op[me] -= (penalty * ShelterOpening) / 256; } // black pawn shelter if (UseShelter && (mat_info->cflags[Black] & MatKingFlag) != 0) { me = Black; // king penalty_1 = shelter_square(board,KING_POS(board,me),me); // castling penalty_2 = penalty_1; if ((board->flags & FlagsBlackKingCastle) != 0) { tmp = shelter_square(board,G8,me); if (tmp < penalty_2) penalty_2 = tmp; } if ((board->flags & FlagsBlackQueenCastle) != 0) { tmp = shelter_square(board,B8,me); if (tmp < penalty_2) penalty_2 = tmp; } ASSERT(penalty_2>=0&&penalty_2<=penalty_1); // penalty penalty = (penalty_1 + penalty_2) / 2; ASSERT(penalty>=0); op[me] -= (penalty * ShelterOpening) / 256; } // update *opening += ((op[White] - op[Black]) * KingSafetyWeight) / 256; *endgame += ((eg[White] - eg[Black]) * KingSafetyWeight) / 256; } // eval_passer() static void eval_passer(const board_t * board, const pawn_info_t * pawn_info, int * opening, int * endgame) { int colour; int op[ColourNb], eg[ColourNb]; int att, def; int bits; int file, rank; int sq; int min, max; int delta; ASSERT(board!=NULL); ASSERT(pawn_info!=NULL); ASSERT(opening!=NULL); ASSERT(endgame!=NULL); // init for (colour = 0; colour < ColourNb; colour++) { op[colour] = 0; eg[colour] = 0; } // passed pawns for (colour = 0; colour < ColourNb; colour++) { att = colour; def = COLOUR_OPP(att); for (bits = pawn_info->passed_bits[att]; bits != 0; bits &= bits-1) { file = BIT_FIRST(bits); ASSERT(file>=FileA&&file<=FileH); rank = BIT_LAST(board->pawn_file[att][file]); ASSERT(rank>=Rank2&&rank<=Rank7); sq = SQUARE_MAKE(file,rank); if (COLOUR_IS_BLACK(att)) sq = SQUARE_RANK_MIRROR(sq); ASSERT(PIECE_IS_PAWN(board->square[sq])); ASSERT(COLOUR_IS(board->square[sq],att)); // opening scoring op[att] += quad(PassedOpeningMin,PassedOpeningMax,rank); // endgame scoring init min = PassedEndgameMin; max = PassedEndgameMax; delta = max - min; ASSERT(delta>0); // "dangerous" bonus if (board->piece_size[def] <= 1 // defender has no piece && (unstoppable_passer(board,sq,att) || king_passer(board,sq,att))) { delta += UnstoppablePasser; } else if (free_passer(board,sq,att)) { delta += FreePasser; } // king-distance bonus delta -= pawn_att_dist(sq,KING_POS(board,att),att) * AttackerDistance; delta += pawn_def_dist(sq,KING_POS(board,def),att) * DefenderDistance; // endgame scoring eg[att] += min; if (delta > 0) eg[att] += quad(0,delta,rank); } } // update *opening += ((op[White] - op[Black]) * PassedPawnWeight) / 256; *endgame += ((eg[White] - eg[Black]) * PassedPawnWeight) / 256; } // eval_pattern() static void eval_pattern(const board_t * board, int * opening, int * endgame) { ASSERT(board!=NULL); ASSERT(opening!=NULL); ASSERT(endgame!=NULL); // trapped bishop (7th rank) if ((board->square[A7] == WB && board->square[B6] == BP) || (board->square[B8] == WB && board->square[C7] == BP)) { *opening -= TrappedBishop; *endgame -= TrappedBishop; } if ((board->square[H7] == WB && board->square[G6] == BP) || (board->square[G8] == WB && board->square[F7] == BP)) { *opening -= TrappedBishop; *endgame -= TrappedBishop; } if ((board->square[A2] == BB && board->square[B3] == WP) || (board->square[B1] == BB && board->square[C2] == WP)) { *opening += TrappedBishop; *endgame += TrappedBishop; } if ((board->square[H2] == BB && board->square[G3] == WP) || (board->square[G1] == BB && board->square[F2] == WP)) { *opening += TrappedBishop; *endgame += TrappedBishop; } // trapped bishop (6th rank) if (board->square[A6] == WB && board->square[B5] == BP) { *opening -= TrappedBishop / 2; *endgame -= TrappedBishop / 2; } if (board->square[H6] == WB && board->square[G5] == BP) { *opening -= TrappedBishop / 2; *endgame -= TrappedBishop / 2; } if (board->square[A3] == BB && board->square[B4] == WP) { *opening += TrappedBishop / 2; *endgame += TrappedBishop / 2; } if (board->square[H3] == BB && board->square[G4] == WP) { *opening += TrappedBishop / 2; *endgame += TrappedBishop / 2; } // blocked bishop if (board->square[D2] == WP && board->square[D3] != Empty && board->square[C1] == WB) { *opening -= BlockedBishop; } if (board->square[E2] == WP && board->square[E3] != Empty && board->square[F1] == WB) { *opening -= BlockedBishop; } if (board->square[D7] == BP && board->square[D6] != Empty && board->square[C8] == BB) { *opening += BlockedBishop; } if (board->square[E7] == BP && board->square[E6] != Empty && board->square[F8] == BB) { *opening += BlockedBishop; } // blocked rook if ((board->square[C1] == WK || board->square[B1] == WK) && (board->square[A1] == WR || board->square[A2] == WR || board->square[B1] == WR)) { *opening -= BlockedRook; } if ((board->square[F1] == WK || board->square[G1] == WK) && (board->square[H1] == WR || board->square[H2] == WR || board->square[G1] == WR)) { *opening -= BlockedRook; } if ((board->square[C8] == BK || board->square[B8] == BK) && (board->square[A8] == BR || board->square[A7] == BR || board->square[B8] == BR)) { *opening += BlockedRook; } if ((board->square[F8] == BK || board->square[G8] == BK) && (board->square[H8] == BR || board->square[H7] == BR || board->square[G8] == BR)) { *opening += BlockedRook; } } // unstoppable_passer() static bool unstoppable_passer(const board_t * board, int pawn, int colour) { int me, opp; int file, rank; int king; int prom; const sq_t * ptr; int sq; int dist; ASSERT(board!=NULL); ASSERT(SQUARE_IS_OK(pawn)); ASSERT(COLOUR_IS_OK(colour)); me = colour; opp = COLOUR_OPP(me); file = SQUARE_FILE(pawn); rank = PAWN_RANK(pawn,me); king = KING_POS(board,opp); // clear promotion path? for (ptr = &board->piece[me][0]; (sq=*ptr) != SquareNone; ptr++) { if (SQUARE_FILE(sq) == file && PAWN_RANK(sq,me) > rank) { return false; // "friendly" blocker } } // init if (rank == Rank2) { pawn += PAWN_MOVE_INC(me); rank++; ASSERT(rank==PAWN_RANK(pawn,me)); } ASSERT(rank>=Rank3&&rank<=Rank7); prom = PAWN_PROMOTE(pawn,me); dist = DISTANCE(pawn,prom); ASSERT(dist==Rank8-rank); if (board->turn == opp) dist++; if (DISTANCE(king,prom) > dist) return true; // not in the square return false; } // king_passer() static bool king_passer(const board_t * board, int pawn, int colour) { int me; int king; int file; int prom; ASSERT(board!=NULL); ASSERT(SQUARE_IS_OK(pawn)); ASSERT(COLOUR_IS_OK(colour)); me = colour; king = KING_POS(board,me); file = SQUARE_FILE(pawn); prom = PAWN_PROMOTE(pawn,me); if (DISTANCE(king,prom) <= 1 && DISTANCE(king,pawn) <= 1 && (SQUARE_FILE(king) != file || (file != FileA && file != FileH))) { return true; } return false; } // free_passer() static bool free_passer(const board_t * board, int pawn, int colour) { int me, opp; int inc; int sq; int move; ASSERT(board!=NULL); ASSERT(SQUARE_IS_OK(pawn)); ASSERT(COLOUR_IS_OK(colour)); me = colour; opp = COLOUR_OPP(me); inc = PAWN_MOVE_INC(me); sq = pawn + inc; ASSERT(SQUARE_IS_OK(sq)); if (board->square[sq] != Empty) return false; move = MOVE_MAKE(pawn,sq); if (see_move(move,board) < 0) return false; return true; } // pawn_att_dist() static int pawn_att_dist(int pawn, int king, int colour) { int me; int inc; int target; ASSERT(SQUARE_IS_OK(pawn)); ASSERT(SQUARE_IS_OK(king)); ASSERT(COLOUR_IS_OK(colour)); me = colour; inc = PAWN_MOVE_INC(me); target = pawn + inc; return DISTANCE(king,target); } // pawn_def_dist() static int pawn_def_dist(int pawn, int king, int colour) { int me; int inc; int target; ASSERT(SQUARE_IS_OK(pawn)); ASSERT(SQUARE_IS_OK(king)); ASSERT(COLOUR_IS_OK(colour)); me = colour; inc = PAWN_MOVE_INC(me); target = pawn + inc; return DISTANCE(king,target); } // draw_init_list() static void draw_init_list(int list[], const board_t * board, int pawn_colour) { int pos; int att, def; const sq_t * ptr; int sq; int pawn; int i; ASSERT(list!=NULL); ASSERT(board!=NULL); ASSERT(COLOUR_IS_OK(pawn_colour)); // init pos = 0; att = pawn_colour; def = COLOUR_OPP(att); ASSERT(board->pawn_size[att]==1); ASSERT(board->pawn_size[def]==0); // att for (ptr = &board->piece[att][0]; (sq=*ptr) != SquareNone; ptr++) { list[pos++] = sq; } for (ptr = &board->pawn[att][0]; (sq=*ptr) != SquareNone; ptr++) { list[pos++] = sq; } // def for (ptr = &board->piece[def][0]; (sq=*ptr) != SquareNone; ptr++) { list[pos++] = sq; } for (ptr = &board->pawn[def][0]; (sq=*ptr) != SquareNone; ptr++) { list[pos++] = sq; } // end marker ASSERT(pos==board->piece_nb); list[pos] = SquareNone; // file flip? pawn = board->pawn[att][0]; if (SQUARE_FILE(pawn) >= FileE) { for (i = 0; i < pos; i++) { list[i] = SQUARE_FILE_MIRROR(list[i]); } } // rank flip? if (COLOUR_IS_BLACK(pawn_colour)) { for (i = 0; i < pos; i++) { list[i] = SQUARE_RANK_MIRROR(list[i]); } } } // draw_kpkq() static bool draw_kpkq(const int list[], int turn) { int wk, wp, bk, bq; int prom; int dist; // int wp_file, wp_rank; ASSERT(list!=NULL); ASSERT(COLOUR_IS_OK(turn)); // load wk = *list++; ASSERT(SQUARE_IS_OK(wk)); wp = *list++; ASSERT(SQUARE_IS_OK(wp)); ASSERT(SQUARE_FILE(wp)<=FileD); bk = *list++; ASSERT(SQUARE_IS_OK(bk)); bq = *list++; ASSERT(SQUARE_IS_OK(bq)); ASSERT(*list==SquareNone); // test if (false) { } else if (wp == A7) { prom = A8; dist = 4; if (wk == B7 || wk == B8) { // best case if (COLOUR_IS_WHITE(turn)) dist--; } else if (wk == A8 || ((wk == C7 || wk == C8) && bq != A8)) { // white loses a tempo if (COLOUR_IS_BLACK(turn) && SQUARE_FILE(bq) != FileB) return false; } else { return false; } ASSERT(bq!=prom); if (DISTANCE(bk,prom) > dist) return true; } else if (wp == C7) { prom = C8; dist = 4; if (false) { } else if (wk == C8) { // dist = 0 dist++; // self-blocking penalty if (COLOUR_IS_WHITE(turn)) dist--; // right-to-move bonus } else if (wk == B7 || wk == B8) { // dist = 1, right side dist--; // right-side bonus if (DELTA_INC_LINE(wp-bq) == wk-wp) dist++; // pinned-pawn penalty if (COLOUR_IS_WHITE(turn)) dist--; // right-to-move bonus } else if (wk == D7 || wk == D8) { // dist = 1, wrong side if (DELTA_INC_LINE(wp-bq) == wk-wp) dist++; // pinned-pawn penalty if (COLOUR_IS_WHITE(turn)) dist--; // right-to-move bonus } else if ((wk == A7 || wk == A8) && bq != C8) { // dist = 2, right side if (COLOUR_IS_BLACK(turn) && SQUARE_FILE(bq) != FileB) return false; dist--; // right-side bonus } else if ((wk == E7 || wk == E8) && bq != C8) { // dist = 2, wrong side if (COLOUR_IS_BLACK(turn) && SQUARE_FILE(bq) != FileD) return false; } else { return false; } ASSERT(bq!=prom); if (DISTANCE(bk,prom) > dist) return true; } return false; } // draw_kpkr() static bool draw_kpkr(const int list[], int turn) { int wk, wp, bk, br; int wk_file, wk_rank; int wp_file, wp_rank; int br_file, br_rank; int inc; int prom; int dist; ASSERT(list!=NULL); ASSERT(COLOUR_IS_OK(turn)); // load wk = *list++; ASSERT(SQUARE_IS_OK(wk)); wp = *list++; ASSERT(SQUARE_IS_OK(wp)); ASSERT(SQUARE_FILE(wp)<=FileD); bk = *list++; ASSERT(SQUARE_IS_OK(bk)); br = *list++; ASSERT(SQUARE_IS_OK(br)); ASSERT(*list==SquareNone); // init wk_file = SQUARE_FILE(wk); wk_rank = SQUARE_RANK(wk); wp_file = SQUARE_FILE(wp); wp_rank = SQUARE_RANK(wp); br_file = SQUARE_FILE(br); br_rank = SQUARE_RANK(br); inc = PAWN_MOVE_INC(White); prom = PAWN_PROMOTE(wp,White); // conditions if (false) { } else if (DISTANCE(wk,wp) == 1) { ASSERT(abs(wk_file-wp_file)<=1); ASSERT(abs(wk_rank-wp_rank)<=1); // no-op } else if (DISTANCE(wk,wp) == 2 && abs(wk_rank-wp_rank) <= 1) { ASSERT(abs(wk_file-wp_file)==2); ASSERT(abs(wk_rank-wp_rank)<=1); if (COLOUR_IS_BLACK(turn) && br_file != (wk_file + wp_file) / 2) return false; } else { return false; } // white features dist = DISTANCE(wk,prom) + DISTANCE(wp,prom); if (wk == prom) dist++; if (wk == wp+inc) { // king on pawn's "front square" if (wp_file == FileA) return false; dist++; // self-blocking penalty } // black features if (br_file != wp_file && br_rank != Rank8) { dist--; // misplaced-rook bonus } // test if (COLOUR_IS_WHITE(turn)) dist--; // right-to-move bonus if (DISTANCE(bk,prom) > dist) return true; return false; } // draw_kpkb() static bool draw_kpkb(const int list[], int turn) { int wk, wp, bk, bb; int inc; int end, to; int delta, inc_2; int sq; ASSERT(list!=NULL); ASSERT(COLOUR_IS_OK(turn)); // load wk = *list++; ASSERT(SQUARE_IS_OK(wk)); wp = *list++; ASSERT(SQUARE_IS_OK(wp)); ASSERT(SQUARE_FILE(wp)<=FileD); bk = *list++; ASSERT(SQUARE_IS_OK(bk)); bb = *list++; ASSERT(SQUARE_IS_OK(bb)); ASSERT(*list==SquareNone); // blocked pawn? inc = PAWN_MOVE_INC(White); end = PAWN_PROMOTE(wp,White) + inc; for (to = wp+inc; to != end; to += inc) { ASSERT(SQUARE_IS_OK(to)); if (to == bb) return true; // direct blockade delta = to - bb; ASSERT(delta_is_ok(delta)); if (PSEUDO_ATTACK(BB,delta)) { inc_2 = DELTA_INC_ALL(delta); ASSERT(inc_2!=IncNone); sq = bb; do { sq += inc_2; ASSERT(SQUARE_IS_OK(sq)); ASSERT(sq!=wk); ASSERT(sq!=wp); ASSERT(sq!=bb); if (sq == to) return true; // indirect blockade } while (sq != bk); } } return false; } // draw_kpkn() static bool draw_kpkn(const int list[], int turn) { int wk, wp, bk, bn; int inc; int end; int file; int sq; ASSERT(list!=NULL); ASSERT(COLOUR_IS_OK(turn)); // load wk = *list++; ASSERT(SQUARE_IS_OK(wk)); wp = *list++; ASSERT(SQUARE_IS_OK(wp)); ASSERT(SQUARE_FILE(wp)<=FileD); bk = *list++; ASSERT(SQUARE_IS_OK(bk)); bn = *list++; ASSERT(SQUARE_IS_OK(bn)); ASSERT(*list==SquareNone); // blocked pawn? inc = PAWN_MOVE_INC(White); end = PAWN_PROMOTE(wp,White) + inc; file = SQUARE_FILE(wp); if (file == FileA || file == FileH) end -= inc; for (sq = wp+inc; sq != end; sq += inc) { ASSERT(SQUARE_IS_OK(sq)); if (sq == bn || PSEUDO_ATTACK(BN,sq-bn)) return true; // blockade } return false; } // draw_knpk() static bool draw_knpk(const int list[], int turn) { int wk, wn, wp, bk; ASSERT(list!=NULL); ASSERT(COLOUR_IS_OK(turn)); // load wk = *list++; ASSERT(SQUARE_IS_OK(wk)); wn = *list++; ASSERT(SQUARE_IS_OK(wn)); wp = *list++; ASSERT(SQUARE_IS_OK(wp)); ASSERT(SQUARE_FILE(wp)<=FileD); bk = *list++; ASSERT(SQUARE_IS_OK(bk)); ASSERT(*list==SquareNone); // test if (wp == A7 && DISTANCE(bk,A8) <= 1) return true; return false; } // draw_krpkr() static bool draw_krpkr(const int list[], int turn) { int wk, wr, wp, bk, br; int wp_file, wp_rank; int bk_file, bk_rank; int br_file, br_rank; int prom; ASSERT(list!=NULL); ASSERT(COLOUR_IS_OK(turn)); // load wk = *list++; ASSERT(SQUARE_IS_OK(wk)); wr = *list++; ASSERT(SQUARE_IS_OK(wr)); wp = *list++; ASSERT(SQUARE_IS_OK(wp)); ASSERT(SQUARE_FILE(wp)<=FileD); bk = *list++; ASSERT(SQUARE_IS_OK(bk)); br = *list++; ASSERT(SQUARE_IS_OK(br)); ASSERT(*list==SquareNone); // test wp_file = SQUARE_FILE(wp); wp_rank = SQUARE_RANK(wp); bk_file = SQUARE_FILE(bk); bk_rank = SQUARE_RANK(bk); br_file = SQUARE_FILE(br); br_rank = SQUARE_RANK(br); prom = PAWN_PROMOTE(wp,White); if (false) { } else if (bk == prom) { // TODO: rook near Rank1 if wp_rank == Rank6? if (br_file > wp_file) return true; } else if (bk_file == wp_file && bk_rank > wp_rank) { return true; } else if (wr == prom && wp_rank == Rank7 && (bk == G7 || bk == H7) && br_file == wp_file) { if (br_rank <= Rank3) { if (DISTANCE(wk,wp) > 1) return true; } else { // br_rank >= Rank4 if (DISTANCE(wk,wp) > 2) return true; } } return false; } // draw_kbpkb() static bool draw_kbpkb(const int list[], int turn) { int wk, wb, wp, bk, bb; int inc; int end, to; int delta, inc_2; int sq; ASSERT(list!=NULL); ASSERT(COLOUR_IS_OK(turn)); // load wk = *list++; ASSERT(SQUARE_IS_OK(wk)); wb = *list++; ASSERT(SQUARE_IS_OK(wb)); wp = *list++; ASSERT(SQUARE_IS_OK(wp)); ASSERT(SQUARE_FILE(wp)<=FileD); bk = *list++; ASSERT(SQUARE_IS_OK(bk)); bb = *list++; ASSERT(SQUARE_IS_OK(bb)); ASSERT(*list==SquareNone); // opposit colour? if (SQUARE_COLOUR(wb) == SQUARE_COLOUR(bb)) return false; // TODO // blocked pawn? inc = PAWN_MOVE_INC(White); end = PAWN_PROMOTE(wp,White) + inc; for (to = wp+inc; to != end; to += inc) { ASSERT(SQUARE_IS_OK(to)); if (to == bb) return true; // direct blockade delta = to - bb; ASSERT(delta_is_ok(delta)); if (PSEUDO_ATTACK(BB,delta)) { inc_2 = DELTA_INC_ALL(delta); ASSERT(inc_2!=IncNone); sq = bb; do { sq += inc_2; ASSERT(SQUARE_IS_OK(sq)); ASSERT(sq!=wk); ASSERT(sq!=wb); ASSERT(sq!=wp); ASSERT(sq!=bb); if (sq == to) return true; // indirect blockade } while (sq != bk); } } return false; } // shelter_square() static int shelter_square(const board_t * board, int square, int colour) { int penalty; int file, rank; ASSERT(board!=NULL); ASSERT(SQUARE_IS_OK(square)); ASSERT(COLOUR_IS_OK(colour)); penalty = 0; file = SQUARE_FILE(square); rank = PAWN_RANK(square,colour); penalty += shelter_file(board,file,rank,colour) * 2; if (file != FileA) penalty += shelter_file(board,file-1,rank,colour); if (file != FileH) penalty += shelter_file(board,file+1,rank,colour); if (penalty == 0) penalty = 11; // weak back rank if (UseStorm) { penalty += storm_file(board,file,colour); if (file != FileA) penalty += storm_file(board,file-1,colour); if (file != FileH) penalty += storm_file(board,file+1,colour); } return penalty; } // shelter_file() static int shelter_file(const board_t * board, int file, int rank, int colour) { int dist; int penalty; ASSERT(board!=NULL); ASSERT(file>=FileA&&file<=FileH); ASSERT(rank>=Rank1&&rank<=Rank8); ASSERT(COLOUR_IS_OK(colour)); dist = BIT_FIRST(board->pawn_file[colour][file]&BitGE[rank]); ASSERT(dist>=Rank2&&dist<=Rank8); dist = Rank8 - dist; ASSERT(dist>=0&&dist<=6); penalty = 36 - dist * dist; ASSERT(penalty>=0&&penalty<=36); return penalty; } // storm_file() static int storm_file(const board_t * board, int file, int colour) { int dist; int penalty; ASSERT(board!=NULL); ASSERT(file>=FileA&&file<=FileH); ASSERT(COLOUR_IS_OK(colour)); dist = BIT_LAST(board->pawn_file[COLOUR_OPP(colour)][file]); ASSERT(dist>=Rank1&&dist<=Rank7); penalty = 0; switch (dist) { case Rank4: penalty = StormOpening * 1; break; case Rank5: penalty = StormOpening * 3; break; case Rank6: penalty = StormOpening * 6; break; } return penalty; } // bishop_can_attack() static bool bishop_can_attack(const board_t * board, int to, int colour) { const sq_t * ptr; int from; int piece; ASSERT(board!=NULL); ASSERT(SQUARE_IS_OK(to)); ASSERT(COLOUR_IS_OK(colour)); for (ptr = &board->piece[colour][1]; (from=*ptr) != SquareNone; ptr++) { // HACK: no king piece = board->square[from]; if (PIECE_IS_BISHOP(piece) && SQUARE_COLOUR(from) == SQUARE_COLOUR(to)) { return true; } } return false; } // end of eval.cpp fruit-2.1.dfsg-1.orig/src/move_check.cpp0000600000175000017500000002174310402400155017472 0ustar oliveroliver // move_check.cpp // includes #include "attack.h" #include "colour.h" #include "fen.h" #include "list.h" #include "move.h" #include "move_check.h" #include "move_do.h" #include "move_gen.h" #include "piece.h" #include "square.h" #include "util.h" // prototypes static void add_quiet_checks (list_t * list, const board_t * board); static void add_castle_checks (list_t * list, board_t * board); static void add_check (list_t * list, int move, board_t * board); static void find_pins (int list[], const board_t * board); // functions // gen_quiet_checks() void gen_quiet_checks(list_t * list, board_t * board) { ASSERT(list!=NULL); ASSERT(board!=NULL); ASSERT(!board_is_check(board)); LIST_CLEAR(list); add_quiet_checks(list,board); add_castle_checks(list,board); // debug ASSERT(list_is_ok(list)); } // add_quiet_checks() static void add_quiet_checks(list_t * list, const board_t * board) { int me, opp; int king; const sq_t * ptr, * ptr_2; int from, to, sq; int piece; const inc_t * inc_ptr; int inc; int pawn; int rank; int pin[8+1]; ASSERT(list!=NULL); ASSERT(board!=NULL); // init me = board->turn; opp = COLOUR_OPP(me); king = KING_POS(board,opp); find_pins(pin,board); // indirect checks for (ptr = pin; (from=*ptr) != SquareNone; ptr++) { piece = board->square[from]; ASSERT(is_pinned(board,from,opp)); if (PIECE_IS_PAWN(piece)) { inc = PAWN_MOVE_INC(me); rank = PAWN_RANK(from,me); if (rank != Rank7) { // promotes are generated with captures to = from + inc; if (board->square[to] == Empty) { if (DELTA_INC_LINE(to-king) != DELTA_INC_LINE(from-king)) { ASSERT(!SQUARE_IS_PROMOTE(to)); LIST_ADD(list,MOVE_MAKE(from,to)); if (rank == Rank2) { to = from + (2*inc); if (board->square[to] == Empty) { ASSERT(DELTA_INC_LINE(to-king)!=DELTA_INC_LINE(from-king)); ASSERT(!SQUARE_IS_PROMOTE(to)); LIST_ADD(list,MOVE_MAKE(from,to)); } } } } } } else if (PIECE_IS_SLIDER(piece)) { for (inc_ptr = PIECE_INC(piece); (inc=*inc_ptr) != IncNone; inc_ptr++) { for (to = from+inc; board->square[to] == Empty; to += inc) { ASSERT(DELTA_INC_LINE(to-king)!=DELTA_INC_LINE(from-king)); LIST_ADD(list,MOVE_MAKE(from,to)); } } } else { for (inc_ptr = PIECE_INC(piece); (inc=*inc_ptr) != IncNone; inc_ptr++) { to = from + inc; if (board->square[to] == Empty) { if (DELTA_INC_LINE(to-king) != DELTA_INC_LINE(from-king)) { LIST_ADD(list,MOVE_MAKE(from,to)); } } } } } // piece direct checks for (ptr = &board->piece[me][1]; (from=*ptr) != SquareNone; ptr++) { // HACK: no king for (ptr_2 = pin; (sq=*ptr_2) != SquareNone; ptr_2++) { if (sq == from) goto next_piece; } ASSERT(!is_pinned(board,from,opp)); piece = board->square[from]; inc_ptr = PIECE_INC(piece); if (PIECE_IS_SLIDER(piece)) { for (; (inc=*inc_ptr) != IncNone; inc_ptr++) { for (to = from+inc; board->square[to] == Empty; to += inc) { if (PIECE_ATTACK(board,piece,to,king)) { LIST_ADD(list,MOVE_MAKE(from,to)); } } } } else { for (; (inc=*inc_ptr) != IncNone; inc_ptr++) { to = from + inc; if (board->square[to] == Empty) { if (PSEUDO_ATTACK(piece,king-to)) { LIST_ADD(list,MOVE_MAKE(from,to)); } } } } next_piece: ; } // pawn direct checks inc = PAWN_MOVE_INC(me); pawn = PAWN_MAKE(me); to = king - (inc-1); ASSERT(PSEUDO_ATTACK(pawn,king-to)); from = to - inc; if (board->square[from] == pawn) { if (board->square[to] == Empty) { ASSERT(!SQUARE_IS_PROMOTE(to)); LIST_ADD(list,MOVE_MAKE(from,to)); } } else { from = to - (2*inc); if (board->square[from] == pawn) { if (PAWN_RANK(from,me) == Rank2 && board->square[to] == Empty && board->square[from+inc] == Empty) { ASSERT(!SQUARE_IS_PROMOTE(to)); LIST_ADD(list,MOVE_MAKE(from,to)); } } } to = king - (inc+1); ASSERT(PSEUDO_ATTACK(pawn,king-to)); from = to - inc; if (board->square[from] == pawn) { if (board->square[to] == Empty) { ASSERT(!SQUARE_IS_PROMOTE(to)); LIST_ADD(list,MOVE_MAKE(from,to)); } } else { from = to - (2*inc); if (board->square[from] == pawn) { if (PAWN_RANK(from,me) == Rank2 && board->square[to] == Empty && board->square[from+inc] == Empty) { ASSERT(!SQUARE_IS_PROMOTE(to)); LIST_ADD(list,MOVE_MAKE(from,to)); } } } } // add_castle_checks() static void add_castle_checks(list_t * list, board_t * board) { ASSERT(list!=NULL); ASSERT(board!=NULL); ASSERT(!board_is_check(board)); if (COLOUR_IS_WHITE(board->turn)) { if ((board->flags & FlagsWhiteKingCastle) != 0 && board->square[F1] == Empty && board->square[G1] == Empty && !is_attacked(board,F1,Black)) { add_check(list,MOVE_MAKE_FLAGS(E1,G1,MoveCastle),board); } if ((board->flags & FlagsWhiteQueenCastle) != 0 && board->square[D1] == Empty && board->square[C1] == Empty && board->square[B1] == Empty && !is_attacked(board,D1,Black)) { add_check(list,MOVE_MAKE_FLAGS(E1,C1,MoveCastle),board); } } else { // black if ((board->flags & FlagsBlackKingCastle) != 0 && board->square[F8] == Empty && board->square[G8] == Empty && !is_attacked(board,F8,White)) { add_check(list,MOVE_MAKE_FLAGS(E8,G8,MoveCastle),board); } if ((board->flags & FlagsBlackQueenCastle) != 0 && board->square[D8] == Empty && board->square[C8] == Empty && board->square[B8] == Empty && !is_attacked(board,D8,White)) { add_check(list,MOVE_MAKE_FLAGS(E8,C8,MoveCastle),board); } } } // add_check() static void add_check(list_t * list, int move, board_t * board) { undo_t undo[1]; ASSERT(list!=NULL); ASSERT(move_is_ok(move)); ASSERT(board!=NULL); move_do(board,move,undo); if (IS_IN_CHECK(board,board->turn)) LIST_ADD(list,move); move_undo(board,move,undo); } // move_is_check() bool move_is_check(int move, board_t * board) { undo_t undo[1]; bool check; int me, opp, king; int from, to, piece; ASSERT(move_is_ok(move)); ASSERT(board!=NULL); // slow test for complex moves if (MOVE_IS_SPECIAL(move)) { move_do(board,move,undo); check = IS_IN_CHECK(board,board->turn); move_undo(board,move,undo); return check; } // init me = board->turn; opp = COLOUR_OPP(me); king = KING_POS(board,opp); from = MOVE_FROM(move); to = MOVE_TO(move); piece = board->square[from]; ASSERT(COLOUR_IS(piece,me)); // direct check if (PIECE_ATTACK(board,piece,to,king)) return true; // indirect check if (is_pinned(board,from,opp) && DELTA_INC_LINE(king-to) != DELTA_INC_LINE(king-from)) { return true; } return false; } // find_pins() static void find_pins(int list[], const board_t * board) { int me, opp; int king; const sq_t * ptr; int from; int piece; int delta; int inc; int sq; int capture; int pin; ASSERT(list!=NULL); ASSERT(board!=NULL); // init me = board->turn; opp = COLOUR_OPP(me); king = KING_POS(board,opp); for (ptr = &board->piece[me][1]; (from=*ptr) != SquareNone; ptr++) { // HACK: no king piece = board->square[from]; delta = king - from; ASSERT(delta_is_ok(delta)); if (PSEUDO_ATTACK(piece,delta)) { ASSERT(PIECE_IS_SLIDER(piece)); inc = DELTA_INC_LINE(delta); ASSERT(inc!=IncNone); ASSERT(SLIDER_ATTACK(piece,inc)); sq = from; do sq += inc; while ((capture=board->square[sq]) == Empty); ASSERT(sq!=king); if (COLOUR_IS(capture,me)) { pin = sq; do sq += inc; while (board->square[sq] == Empty); if (sq == king) *list++ = pin; } } } *list = SquareNone; } // end of move_check.cpp fruit-2.1.dfsg-1.orig/src/move.cpp0000600000175000017500000000774210402400155016340 0ustar oliveroliver // move.cpp // includes #include #include #include "attack.h" #include "colour.h" #include "list.h" #include "move.h" #include "move_do.h" #include "move_gen.h" #include "piece.h" #include "square.h" #include "util.h" // constants static const int PromotePiece[4] = { Knight64, Bishop64, Rook64, Queen64 }; // functions // move_is_ok() bool move_is_ok(int move) { if (move < 0 || move >= 65536) return false; if (move == MoveNone) return false; if (move == MoveNull) return false; return true; } // move_promote() int move_promote(int move) { int code, piece; ASSERT(move_is_ok(move)); ASSERT(MOVE_IS_PROMOTE(move)); code = (move >> 12) & 3; piece = PromotePiece[code]; if (SQUARE_RANK(MOVE_TO(move)) == Rank8) { piece |= WhiteFlag; } else { ASSERT(SQUARE_RANK(MOVE_TO(move))==Rank1); piece |= BlackFlag; } ASSERT(piece_is_ok(piece)); return piece; } // move_order() int move_order(int move) { ASSERT(move_is_ok(move)); return ((move & 07777) << 2) | ((move >> 12) & 3); } // move_is_capture() bool move_is_capture(int move, const board_t * board) { ASSERT(move_is_ok(move)); ASSERT(board!=NULL); return MOVE_IS_EN_PASSANT(move) || board->square[MOVE_TO(move)] != Empty; } // move_is_under_promote() bool move_is_under_promote(int move) { ASSERT(move_is_ok(move)); return MOVE_IS_PROMOTE(move) && (move & MoveAllFlags) != MovePromoteQueen; } // move_is_tactical() bool move_is_tactical(int move, const board_t * board) { ASSERT(move_is_ok(move)); ASSERT(board!=NULL); return (move & (1 << 15)) != 0 || board->square[MOVE_TO(move)] != Empty; // HACK } // move_capture() int move_capture(int move, const board_t * board) { ASSERT(move_is_ok(move)); ASSERT(board!=NULL); if (MOVE_IS_EN_PASSANT(move)) { return PAWN_OPP(board->square[MOVE_FROM(move)]); } return board->square[MOVE_TO(move)]; } // move_to_string() bool move_to_string(int move, char string[], int size) { ASSERT(move==MoveNull||move_is_ok(move)); ASSERT(string!=NULL); ASSERT(size>=6); if (size < 6) return false; // null move if (move == MoveNull) { strcpy(string,NullMoveString); return true; } // normal moves square_to_string(MOVE_FROM(move),&string[0],3); square_to_string(MOVE_TO(move),&string[2],3); ASSERT(strlen(string)==4); // promotes if (MOVE_IS_PROMOTE(move)) { string[4] = tolower(piece_to_char(move_promote(move))); string[5] = '\0'; } return true; } // move_from_string() int move_from_string(const char string[], const board_t * board) { char tmp_string[3]; int from, to; int move; int piece, delta; ASSERT(string!=NULL); ASSERT(board!=NULL); // from tmp_string[0] = string[0]; tmp_string[1] = string[1]; tmp_string[2] = '\0'; from = square_from_string(tmp_string); if (from == SquareNone) return MoveNone; // to tmp_string[0] = string[2]; tmp_string[1] = string[3]; tmp_string[2] = '\0'; to = square_from_string(tmp_string); if (to == SquareNone) return MoveNone; move = MOVE_MAKE(from,to); // promote switch (string[4]) { case '\0': // not a promotion break; case 'n': move |= MovePromoteKnight; break; case 'b': move |= MovePromoteBishop; break; case 'r': move |= MovePromoteRook; break; case 'q': move |= MovePromoteQueen; break; default: return MoveNone; } // flags piece = board->square[from]; if (PIECE_IS_PAWN(piece)) { if (to == board->ep_square) move |= MoveEnPassant; } else if (PIECE_IS_KING(piece)) { delta = to - from; if (delta == +2 || delta == -2) move |= MoveCastle; } return move; } // end of move.cpp fruit-2.1.dfsg-1.orig/src/trans.h0000600000175000017500000000151410402400155016155 0ustar oliveroliver // trans.h #ifndef TRANS_H #define TRANS_H // includes #include "util.h" // types typedef struct trans trans_t; // variables extern trans_t Trans[1]; // functions extern bool trans_is_ok (const trans_t * trans); extern void trans_init (trans_t * trans); extern void trans_alloc (trans_t * trans); extern void trans_free (trans_t * trans); extern void trans_clear (trans_t * trans); extern void trans_inc_date (trans_t * trans); extern void trans_store (trans_t * trans, uint64 key, int move, int depth, int min_value, int max_value); extern bool trans_retrieve (trans_t * trans, uint64 key, int * move, int * min_depth, int * max_depth, int * min_value, int * max_value); extern void trans_stats (const trans_t * trans); #endif // !defined TRANS_H // end of trans.h fruit-2.1.dfsg-1.orig/src/list.h0000600000175000017500000000214110402400155015776 0ustar oliveroliver // list.h #ifndef LIST_H #define LIST_H // includes #include "board.h" #include "util.h" // constants const int ListSize = 256; // macros #define LIST_CLEAR(list) ((list)->size=0) #define LIST_ADD(list,mv) ((list)->move[(list)->size++]=(mv)) #define LIST_IS_EMPTY(list) ((list)->size==0) #define LIST_SIZE(list) ((list)->size) #define LIST_MOVE(list,pos) ((list)->move[pos]) #define LIST_VALUE(list,pos) ((list)->value[pos]) // types struct list_t { int size; uint16 move[ListSize]; sint16 value[ListSize]; }; typedef bool (*move_test_t) (int move, board_t * board); // functions extern bool list_is_ok (const list_t * list); extern void list_remove (list_t * list, int pos); extern void list_copy (list_t * dst, const list_t * src); extern void list_sort (list_t * list); extern bool list_contain (const list_t * list, int move); extern void list_note (list_t * list); extern void list_filter (list_t * list, board_t * board, move_test_t test, bool keep); #endif // !defined LIST_H // end of list.h fruit-2.1.dfsg-1.orig/src/move_do.cpp0000600000175000017500000003607010402400155017016 0ustar oliveroliver // move_do.cpp // includes #include "attack.h" #include "board.h" #include "colour.h" #include "hash.h" #include "move.h" #include "move_do.h" #include "pawn.h" // TODO: bit.h #include "piece.h" #include "pst.h" #include "random.h" #include "util.h" #include "value.h" // variables static int CastleMask[SquareNb]; // prototypes static void square_clear (board_t * board, int square, int piece, bool update); static void square_set (board_t * board, int square, int piece, int pos, bool update); static void square_move (board_t * board, int from, int to, int piece, bool update); // functions // move_do_init() void move_do_init() { int sq; for (sq = 0; sq < SquareNb; sq++) CastleMask[sq] = 0xF; CastleMask[E1] &= ~FlagsWhiteKingCastle; CastleMask[H1] &= ~FlagsWhiteKingCastle; CastleMask[E1] &= ~FlagsWhiteQueenCastle; CastleMask[A1] &= ~FlagsWhiteQueenCastle; CastleMask[E8] &= ~FlagsBlackKingCastle; CastleMask[H8] &= ~FlagsBlackKingCastle; CastleMask[E8] &= ~FlagsBlackQueenCastle; CastleMask[A8] &= ~FlagsBlackQueenCastle; } // move_do() void move_do(board_t * board, int move, undo_t * undo) { int me, opp; int from, to; int piece, pos, capture; int old_flags, new_flags; int delta; int sq; int pawn, rook; ASSERT(board!=NULL); ASSERT(move_is_ok(move)); ASSERT(undo!=NULL); ASSERT(board_is_legal(board)); // initialise undo undo->capture = false; undo->turn = board->turn; undo->flags = board->flags; undo->ep_square = board->ep_square; undo->ply_nb = board->ply_nb; undo->cap_sq = board->cap_sq; undo->opening = board->opening; undo->endgame = board->endgame; undo->key = board->key; undo->pawn_key = board->pawn_key; undo->material_key = board->material_key; // init me = board->turn; opp = COLOUR_OPP(me); from = MOVE_FROM(move); to = MOVE_TO(move); piece = board->square[from]; ASSERT(COLOUR_IS(piece,me)); // update key stack ASSERT(board->spstack[board->sp++] = board->key; // update turn board->turn = opp; board->key ^= RANDOM_64(RandomTurn); // update castling rights old_flags = board->flags; new_flags = old_flags & CastleMask[from] & CastleMask[to]; board->flags = new_flags; board->key ^= Castle64[new_flags^old_flags]; // HACK // update en-passant square if ((sq=board->ep_square) != SquareNone) { board->key ^= RANDOM_64(RandomEnPassant+SQUARE_FILE(sq)-FileA); board->ep_square = SquareNone; } if (PIECE_IS_PAWN(piece)) { delta = to - from; if (delta == +32 || delta == -32) { pawn = PAWN_MAKE(opp); if (board->square[to-1] == pawn || board->square[to+1] == pawn) { board->ep_square = (from + to) / 2; board->key ^= RANDOM_64(RandomEnPassant+SQUARE_FILE(to)-FileA); } } } // update move number (captures are handled later) board->ply_nb++; if (PIECE_IS_PAWN(piece)) board->ply_nb = 0; // conversion // update last square board->cap_sq = SquareNone; // remove the captured piece sq = to; if (MOVE_IS_EN_PASSANT(move)) sq = SQUARE_EP_DUAL(sq); if ((capture=board->square[sq]) != Empty) { ASSERT(COLOUR_IS(capture,opp)); ASSERT(!PIECE_IS_KING(capture)); undo->capture = true; undo->capture_square = sq; undo->capture_piece = capture; undo->capture_pos = board->pos[sq]; square_clear(board,sq,capture,true); board->ply_nb = 0; // conversion board->cap_sq = to; } // move the piece if (MOVE_IS_PROMOTE(move)) { // promote undo->pawn_pos = board->pos[from]; square_clear(board,from,piece,true); piece = move_promote(move); // insert the promote piece in MV order for (pos = board->piece_size[me]; pos > 0 && piece > board->square[board->piece[me][pos-1]]; pos--) // HACK ; square_set(board,to,piece,pos,true); board->cap_sq = to; } else { // normal move square_move(board,from,to,piece,true); } // move the rook in case of castling if (MOVE_IS_CASTLE(move)) { rook = Rook64 | COLOUR_FLAG(me); // HACK if (to == G1) { square_move(board,H1,F1,rook,true); } else if (to == C1) { square_move(board,A1,D1,rook,true); } else if (to == G8) { square_move(board,H8,F8,rook,true); } else if (to == C8) { square_move(board,A8,D8,rook,true); } else { ASSERT(false); } } // debug ASSERT(board_is_ok(board)); } // move_undo() void move_undo(board_t * board, int move, const undo_t * undo) { int me; int from, to; int piece, pos; int rook; ASSERT(board!=NULL); ASSERT(move_is_ok(move)); ASSERT(undo!=NULL); // init me = undo->turn; from = MOVE_FROM(move); to = MOVE_TO(move); piece = board->square[to]; ASSERT(COLOUR_IS(piece,me)); // castle if (MOVE_IS_CASTLE(move)) { rook = Rook64 | COLOUR_FLAG(me); // HACK if (to == G1) { square_move(board,F1,H1,rook,false); } else if (to == C1) { square_move(board,D1,A1,rook,false); } else if (to == G8) { square_move(board,F8,H8,rook,false); } else if (to == C8) { square_move(board,D8,A8,rook,false); } else { ASSERT(false); } } // move the piece backward if (MOVE_IS_PROMOTE(move)) { // promote ASSERT(piece==move_promote(move)); square_clear(board,to,piece,false); piece = PAWN_MAKE(me); pos = undo->pawn_pos; square_set(board,from,piece,pos,false); } else { // normal move square_move(board,to,from,piece,false); } // put the captured piece back if (undo->capture) { square_set(board,undo->capture_square,undo->capture_piece,undo->capture_pos,false); } // update board info board->turn = undo->turn; board->flags = undo->flags; board->ep_square = undo->ep_square; board->ply_nb = undo->ply_nb; board->cap_sq = undo->cap_sq; board->opening = undo->opening; board->endgame = undo->endgame; board->key = undo->key; board->pawn_key = undo->pawn_key; board->material_key = undo->material_key; // update key stack ASSERT(board->sp>0); board->sp--; // debug ASSERT(board_is_ok(board)); ASSERT(board_is_legal(board)); } // move_do_null() void move_do_null(board_t * board, undo_t * undo) { int sq; ASSERT(board!=NULL); ASSERT(undo!=NULL); ASSERT(board_is_legal(board)); ASSERT(!board_is_check(board)); // initialise undo undo->turn = board->turn; undo->ep_square = board->ep_square; undo->ply_nb = board->ply_nb; undo->cap_sq = board->cap_sq; undo->key = board->key; // update key stack ASSERT(board->spstack[board->sp++] = board->key; // update turn board->turn = COLOUR_OPP(board->turn); board->key ^= RANDOM_64(RandomTurn); // update en-passant square sq = board->ep_square; if (sq != SquareNone) { board->key ^= RANDOM_64(RandomEnPassant+SQUARE_FILE(sq)-FileA); board->ep_square = SquareNone; } // update move number board->ply_nb = 0; // HACK: null move is considered as a conversion // update last square board->cap_sq = SquareNone; // debug ASSERT(board_is_ok(board)); } // move_undo_null() void move_undo_null(board_t * board, const undo_t * undo) { ASSERT(board!=NULL); ASSERT(undo!=NULL); ASSERT(board_is_legal(board)); ASSERT(!board_is_check(board)); // update board info board->turn = undo->turn; board->ep_square = undo->ep_square; board->ply_nb = undo->ply_nb; board->cap_sq = undo->cap_sq; board->key = undo->key; // update key stack ASSERT(board->sp>0); board->sp--; // debug ASSERT(board_is_ok(board)); } // square_clear() static void square_clear(board_t * board, int square, int piece, bool update) { int pos, piece_12, colour; int sq; int i, size; int sq_64; uint64 hash_xor; ASSERT(board!=NULL); ASSERT(SQUARE_IS_OK(square)); ASSERT(piece_is_ok(piece)); ASSERT(update==true||update==false); // init pos = board->pos[square]; ASSERT(pos>=0); piece_12 = PIECE_TO_12(piece); colour = PIECE_COLOUR(piece); // square ASSERT(board->square[square]==piece); board->square[square] = Empty; // piece list if (!PIECE_IS_PAWN(piece)) { // init size = board->piece_size[colour]; ASSERT(size>=1); // stable swap ASSERT(pos>=0&&pospos[square]==pos); board->pos[square] = -1; for (i = pos; i < size-1; i++) { sq = board->piece[colour][i+1]; board->piece[colour][i] = sq; ASSERT(board->pos[sq]==i+1); board->pos[sq] = i; } // size size--; board->piece[colour][size] = SquareNone; board->piece_size[colour] = size; } else { // init size = board->pawn_size[colour]; ASSERT(size>=1); // stable swap ASSERT(pos>=0&&pospos[square]==pos); board->pos[square] = -1; for (i = pos; i < size-1; i++) { sq = board->pawn[colour][i+1]; board->pawn[colour][i] = sq; ASSERT(board->pos[sq]==i+1); board->pos[sq] = i; } // size size--; board->pawn[colour][size] = SquareNone; board->pawn_size[colour] = size; // pawn "bitboard" board->pawn_file[colour][SQUARE_FILE(square)] ^= BIT(PAWN_RANK(square,colour)); } // material ASSERT(board->piece_nb>0); board->piece_nb--; ASSERT(board->number[piece_12]>0); board->number[piece_12]--; // update if (update) { // init sq_64 = SQUARE_TO_64(square); // PST board->opening -= PST(piece_12,sq_64,Opening); board->endgame -= PST(piece_12,sq_64,Endgame); // hash key hash_xor = RANDOM_64(RandomPiece+(piece_12^1)*64+sq_64); // HACK: ^1 for PolyGlot book board->key ^= hash_xor; if (PIECE_IS_PAWN(piece)) board->pawn_key ^= hash_xor; // material key board->material_key ^= RANDOM_64(piece_12*16+board->number[piece_12]); } } // square_set() static void square_set(board_t * board, int square, int piece, int pos, bool update) { int piece_12, colour; int sq; int i, size; int sq_64; uint64 hash_xor; ASSERT(board!=NULL); ASSERT(SQUARE_IS_OK(square)); ASSERT(piece_is_ok(piece)); ASSERT(pos>=0); ASSERT(update==true||update==false); // init piece_12 = PIECE_TO_12(piece); colour = PIECE_COLOUR(piece); // square ASSERT(board->square[square]==Empty); board->square[square] = piece; // piece list if (!PIECE_IS_PAWN(piece)) { // init size = board->piece_size[colour]; ASSERT(size>=0); // size size++; board->piece[colour][size] = SquareNone; board->piece_size[colour] = size; // stable swap ASSERT(pos>=0&&pos pos; i--) { sq = board->piece[colour][i-1]; board->piece[colour][i] = sq; ASSERT(board->pos[sq]==i-1); board->pos[sq] = i; } board->piece[colour][pos] = square; ASSERT(board->pos[square]==-1); board->pos[square] = pos; } else { // init size = board->pawn_size[colour]; ASSERT(size>=0); // size size++; board->pawn[colour][size] = SquareNone; board->pawn_size[colour] = size; // stable swap ASSERT(pos>=0&&pos pos; i--) { sq = board->pawn[colour][i-1]; board->pawn[colour][i] = sq; ASSERT(board->pos[sq]==i-1); board->pos[sq] = i; } board->pawn[colour][pos] = square; ASSERT(board->pos[square]==-1); board->pos[square] = pos; // pawn "bitboard" board->pawn_file[colour][SQUARE_FILE(square)] ^= BIT(PAWN_RANK(square,colour)); } // material ASSERT(board->piece_nb<32); board->piece_nb++;; ASSERT(board->number[piece_12]<9); board->number[piece_12]++; // update if (update) { // init sq_64 = SQUARE_TO_64(square); // PST board->opening += PST(piece_12,sq_64,Opening); board->endgame += PST(piece_12,sq_64,Endgame); // hash key hash_xor = RANDOM_64(RandomPiece+(piece_12^1)*64+sq_64); // HACK: ^1 for PolyGlot book board->key ^= hash_xor; if (PIECE_IS_PAWN(piece)) board->pawn_key ^= hash_xor; // material key board->material_key ^= RANDOM_64(piece_12*16+(board->number[piece_12]-1)); } } // square_move() static void square_move(board_t * board, int from, int to, int piece, bool update) { int colour; int pos; int from_64, to_64; int piece_12; int piece_index; uint64 hash_xor; ASSERT(board!=NULL); ASSERT(SQUARE_IS_OK(from)); ASSERT(SQUARE_IS_OK(to)); ASSERT(piece_is_ok(piece)); ASSERT(update==true||update==false); // init colour = PIECE_COLOUR(piece); pos = board->pos[from]; ASSERT(pos>=0); // from ASSERT(board->square[from]==piece); board->square[from] = Empty; ASSERT(board->pos[from]==pos); board->pos[from] = -1; // not needed // to ASSERT(board->square[to]==Empty); board->square[to] = piece; ASSERT(board->pos[to]==-1); board->pos[to] = pos; // piece list if (!PIECE_IS_PAWN(piece)) { ASSERT(board->piece[colour][pos]==from); board->piece[colour][pos] = to; } else { ASSERT(board->pawn[colour][pos]==from); board->pawn[colour][pos] = to; // pawn "bitboard" board->pawn_file[colour][SQUARE_FILE(from)] ^= BIT(PAWN_RANK(from,colour)); board->pawn_file[colour][SQUARE_FILE(to)] ^= BIT(PAWN_RANK(to,colour)); } // update if (update) { // init from_64 = SQUARE_TO_64(from); to_64 = SQUARE_TO_64(to); piece_12 = PIECE_TO_12(piece); // PST board->opening += PST(piece_12,to_64,Opening) - PST(piece_12,from_64,Opening); board->endgame += PST(piece_12,to_64,Endgame) - PST(piece_12,from_64,Endgame); // hash key piece_index = RandomPiece + (piece_12^1) * 64; // HACK: ^1 for PolyGlot book hash_xor = RANDOM_64(piece_index+to_64) ^ RANDOM_64(piece_index+from_64); board->key ^= hash_xor; if (PIECE_IS_PAWN(piece)) board->pawn_key ^= hash_xor; } } // end of move_do.cpp fruit-2.1.dfsg-1.orig/src/move.h0000600000175000017500000000411710402400155015776 0ustar oliveroliver // move.h #ifndef MOVE_H #define MOVE_H // includes #include "board.h" #include "util.h" // constants const int MoveNone = 0; // HACK: a1a1 cannot be a legal move const int MoveNull = 11; // HACK: a1d2 cannot be a legal move const int MoveNormal = 0 << 14; const int MoveCastle = 1 << 14; const int MovePromote = 2 << 14; const int MoveEnPassant = 3 << 14; const int MoveFlags = 3 << 14; const int MovePromoteKnight = MovePromote | (0 << 12); const int MovePromoteBishop = MovePromote | (1 << 12); const int MovePromoteRook = MovePromote | (2 << 12); const int MovePromoteQueen = MovePromote | (3 << 12); const int MoveAllFlags = 0xF << 12; const char NullMoveString[] = "null"; // "0000" in UCI // macros #define MOVE_MAKE(from,to) ((SQUARE_TO_64(from)<<6)|SQUARE_TO_64(to)) #define MOVE_MAKE_FLAGS(from,to,flags) ((SQUARE_TO_64(from)<<6)|SQUARE_TO_64(to)|(flags)) #define MOVE_FROM(move) (SQUARE_FROM_64(((move)>>6)&077)) #define MOVE_TO(move) (SQUARE_FROM_64((move)&077)) #define MOVE_IS_SPECIAL(move) (((move)&MoveFlags)!=MoveNormal) #define MOVE_IS_PROMOTE(move) (((move)&MoveFlags)==MovePromote) #define MOVE_IS_EN_PASSANT(move) (((move)&MoveFlags)==MoveEnPassant) #define MOVE_IS_CASTLE(move) (((move)&MoveFlags)==MoveCastle) #define MOVE_PIECE(move,board) ((board)->square[MOVE_FROM(move)]) // types typedef uint16 mv_t; // functions extern bool move_is_ok (int move); extern int move_promote (int move); extern int move_order (int move); extern bool move_is_capture (int move, const board_t * board); extern bool move_is_under_promote (int move); extern bool move_is_tactical (int move, const board_t * board); extern int move_capture (int move, const board_t * board); extern bool move_to_string (int move, char string[], int size); extern int move_from_string (const char string[], const board_t * board); #endif // !defined MOVE_H // end of move.h fruit-2.1.dfsg-1.orig/src/material.cpp0000600000175000017500000003605410402400155017166 0ustar oliveroliver // material.cpp // includes #include #include "board.h" #include "colour.h" #include "hash.h" #include "material.h" #include "option.h" #include "piece.h" #include "protocol.h" #include "square.h" #include "util.h" // constants static const bool UseTable = true; static const uint32 TableSize = 256; // 4kB static const int PawnPhase = 0; static const int KnightPhase = 1; static const int BishopPhase = 1; static const int RookPhase = 2; static const int QueenPhase = 4; static const int TotalPhase = PawnPhase * 16 + KnightPhase * 4 + BishopPhase * 4 + RookPhase * 4 + QueenPhase * 2; // constants and variables static /* const */ int MaterialWeight = 256; // 100% static const int PawnOpening = 80; // was 100 static const int PawnEndgame = 90; // was 100 static const int KnightOpening = 325; static const int KnightEndgame = 325; static const int BishopOpening = 325; static const int BishopEndgame = 325; static const int RookOpening = 500; static const int RookEndgame = 500; static const int QueenOpening = 1000; static const int QueenEndgame = 1000; static const int BishopPairOpening = 50; static const int BishopPairEndgame = 50; // types typedef material_info_t entry_t; struct material_t { entry_t * table; uint32 size; uint32 mask; uint32 used; sint64 read_nb; sint64 read_hit; sint64 write_nb; sint64 write_collision; }; // variables static material_t Material[1]; // prototypes static void material_comp_info (material_info_t * info, const board_t * board); // functions // material_init() void material_init() { // UCI options MaterialWeight = (option_get_int("Material") * 256 + 50) / 100; // material table Material->size = 0; Material->mask = 0; Material->table = NULL; } // material_alloc() void material_alloc() { ASSERT(sizeof(entry_t)==16); if (UseTable) { Material->size = TableSize; Material->mask = TableSize - 1; Material->table = (entry_t *) my_malloc(Material->size*sizeof(entry_t)); material_clear(); } } // material_clear() void material_clear() { if (Material->table != NULL) { memset(Material->table,0,Material->size*sizeof(entry_t)); } Material->used = 0; Material->read_nb = 0; Material->read_hit = 0; Material->write_nb = 0; Material->write_collision = 0; } // material_get_info() void material_get_info(material_info_t * info, const board_t * board) { uint64 key; entry_t * entry; ASSERT(info!=NULL); ASSERT(board!=NULL); // probe if (UseTable) { Material->read_nb++; key = board->material_key; entry = &Material->table[KEY_INDEX(key)&Material->mask]; if (entry->lock == KEY_LOCK(key)) { // found Material->read_hit++; *info = *entry; return; } } // calculation material_comp_info(info,board); // store if (UseTable) { Material->write_nb++; if (entry->lock == 0) { // HACK: assume free entry Material->used++; } else { Material->write_collision++; } *entry = *info; entry->lock = KEY_LOCK(key); } } // material_comp_info() static void material_comp_info(material_info_t * info, const board_t * board) { int wp, wn, wb, wr, wq; int bp, bn, bb, br, bq; int wt, bt; int wm, bm; int colour; int recog; int flags; int cflags[ColourNb]; int mul[ColourNb]; int phase; int opening, endgame; ASSERT(info!=NULL); ASSERT(board!=NULL); // init wp = board->number[WhitePawn12]; wn = board->number[WhiteKnight12]; wb = board->number[WhiteBishop12]; wr = board->number[WhiteRook12]; wq = board->number[WhiteQueen12]; bp = board->number[BlackPawn12]; bn = board->number[BlackKnight12]; bb = board->number[BlackBishop12]; br = board->number[BlackRook12]; bq = board->number[BlackQueen12]; wt = wq + wr + wb + wn + wp; // no king bt = bq + br + bb + bn + bp; // no king wm = wb + wn; bm = bb + bn; // recogniser recog = MAT_NONE; if (false) { } else if (wt == 0 && bt == 0) { recog = MAT_KK; } else if (wt == 1 && bt == 0) { if (wb == 1) recog = MAT_KBK; if (wn == 1) recog = MAT_KNK; if (wp == 1) recog = MAT_KPK; } else if (wt == 0 && bt == 1) { if (bb == 1) recog = MAT_KKB; if (bn == 1) recog = MAT_KKN; if (bp == 1) recog = MAT_KKP; } else if (wt == 1 && bt == 1) { if (wq == 1 && bq == 1) recog = MAT_KQKQ; if (wq == 1 && bp == 1) recog = MAT_KQKP; if (wp == 1 && bq == 1) recog = MAT_KPKQ; if (wr == 1 && br == 1) recog = MAT_KRKR; if (wr == 1 && bp == 1) recog = MAT_KRKP; if (wp == 1 && br == 1) recog = MAT_KPKR; if (wb == 1 && bb == 1) recog = MAT_KBKB; if (wb == 1 && bp == 1) recog = MAT_KBKP; if (wp == 1 && bb == 1) recog = MAT_KPKB; if (wn == 1 && bn == 1) recog = MAT_KNKN; if (wn == 1 && bp == 1) recog = MAT_KNKP; if (wp == 1 && bn == 1) recog = MAT_KPKN; } else if (wt == 2 && bt == 0) { if (wb == 1 && wp == 1) recog = MAT_KBPK; if (wn == 1 && wp == 1) recog = MAT_KNPK; } else if (wt == 0 && bt == 2) { if (bb == 1 && bp == 1) recog = MAT_KKBP; if (bn == 1 && bp == 1) recog = MAT_KKNP; } else if (wt == 2 && bt == 1) { if (wr == 1 && wp == 1 && br == 1) recog = MAT_KRPKR; if (wb == 1 && wp == 1 && bb == 1) recog = MAT_KBPKB; } else if (wt == 1 && bt == 2) { if (wr == 1 && br == 1 && bp == 1) recog = MAT_KRKRP; if (wb == 1 && bb == 1 && bp == 1) recog = MAT_KBKBP; } // draw node (exact-draw recogniser) flags = 0; // TODO: MOVE ME for (colour = 0; colour < ColourNb; colour++) cflags[colour] = 0; if (wq+wr+wp == 0 && bq+br+bp == 0) { // no major piece or pawn if (wm + bm <= 1 // at most one minor => KK, KBK or KNK || recog == MAT_KBKB) { flags |= DrawNodeFlag; } } else if (recog == MAT_KPK || recog == MAT_KKP || recog == MAT_KBPK || recog == MAT_KKBP) { flags |= DrawNodeFlag; } // bishop endgame if (wq+wr+wn == 0 && bq+br+bn == 0) { // only bishops if (wb == 1 && bb == 1) { if (wp-bp >= -2 && wp-bp <= +2) { // pawn diff <= 2 flags |= DrawBishopFlag; } } } // multipliers for (colour = 0; colour < ColourNb; colour++) mul[colour] = 16; // 1 // white multiplier if (wp == 0) { // white has no pawns int w_maj = wq * 2 + wr; int w_min = wb + wn; int w_tot = w_maj * 2 + w_min; int b_maj = bq * 2 + br; int b_min = bb + bn; int b_tot = b_maj * 2 + b_min; if (false) { } else if (w_tot == 1) { ASSERT(w_maj==0); ASSERT(w_min==1); // KBK* or KNK*, always insufficient mul[White] = 0; } else if (w_tot == 2 && wn == 2) { ASSERT(w_maj==0); ASSERT(w_min==2); // KNNK*, usually insufficient if (b_tot != 0 || bp == 0) { mul[White] = 0; } else { // KNNKP+, might not be draw mul[White] = 1; // 1/16 } } else if (w_tot == 2 && wb == 2 && b_tot == 1 && bn == 1) { ASSERT(w_maj==0); ASSERT(w_min==2); ASSERT(b_maj==0); ASSERT(b_min==1); // KBBKN*, barely drawish (not at all?) mul[White] = 8; // 1/2 } else if (w_tot-b_tot <= 1 && w_maj <= 2) { // no more than 1 minor up, drawish mul[White] = 2; // 1/8 } } else if (wp == 1) { // white has one pawn int w_maj = wq * 2 + wr; int w_min = wb + wn; int w_tot = w_maj * 2 + w_min; int b_maj = bq * 2 + br; int b_min = bb + bn; int b_tot = b_maj * 2 + b_min; if (false) { } else if (b_min != 0) { // assume black sacrifices a minor against the lone pawn b_min--; b_tot--; if (false) { } else if (w_tot == 1) { ASSERT(w_maj==0); ASSERT(w_min==1); // KBK* or KNK*, always insufficient mul[White] = 4; // 1/4 } else if (w_tot == 2 && wn == 2) { ASSERT(w_maj==0); ASSERT(w_min==2); // KNNK*, usually insufficient mul[White] = 4; // 1/4 } else if (w_tot-b_tot <= 1 && w_maj <= 2) { // no more than 1 minor up, drawish mul[White] = 8; // 1/2 } } else if (br != 0) { // assume black sacrifices a rook against the lone pawn b_maj--; b_tot -= 2; if (false) { } else if (w_tot == 1) { ASSERT(w_maj==0); ASSERT(w_min==1); // KBK* or KNK*, always insufficient mul[White] = 4; // 1/4 } else if (w_tot == 2 && wn == 2) { ASSERT(w_maj==0); ASSERT(w_min==2); // KNNK*, usually insufficient mul[White] = 4; // 1/4 } else if (w_tot-b_tot <= 1 && w_maj <= 2) { // no more than 1 minor up, drawish mul[White] = 8; // 1/2 } } } // black multiplier if (bp == 0) { // black has no pawns int w_maj = wq * 2 + wr; int w_min = wb + wn; int w_tot = w_maj * 2 + w_min; int b_maj = bq * 2 + br; int b_min = bb + bn; int b_tot = b_maj * 2 + b_min; if (false) { } else if (b_tot == 1) { ASSERT(b_maj==0); ASSERT(b_min==1); // KBK* or KNK*, always insufficient mul[Black] = 0; } else if (b_tot == 2 && bn == 2) { ASSERT(b_maj==0); ASSERT(b_min==2); // KNNK*, usually insufficient if (w_tot != 0 || wp == 0) { mul[Black] = 0; } else { // KNNKP+, might not be draw mul[Black] = 1; // 1/16 } } else if (b_tot == 2 && bb == 2 && w_tot == 1 && wn == 1) { ASSERT(b_maj==0); ASSERT(b_min==2); ASSERT(w_maj==0); ASSERT(w_min==1); // KBBKN*, barely drawish (not at all?) mul[Black] = 8; // 1/2 } else if (b_tot-w_tot <= 1 && b_maj <= 2) { // no more than 1 minor up, drawish mul[Black] = 2; // 1/8 } } else if (bp == 1) { // black has one pawn int w_maj = wq * 2 + wr; int w_min = wb + wn; int w_tot = w_maj * 2 + w_min; int b_maj = bq * 2 + br; int b_min = bb + bn; int b_tot = b_maj * 2 + b_min; if (false) { } else if (w_min != 0) { // assume white sacrifices a minor against the lone pawn w_min--; w_tot--; if (false) { } else if (b_tot == 1) { ASSERT(b_maj==0); ASSERT(b_min==1); // KBK* or KNK*, always insufficient mul[Black] = 4; // 1/4 } else if (b_tot == 2 && bn == 2) { ASSERT(b_maj==0); ASSERT(b_min==2); // KNNK*, usually insufficient mul[Black] = 4; // 1/4 } else if (b_tot-w_tot <= 1 && b_maj <= 2) { // no more than 1 minor up, drawish mul[Black] = 8; // 1/2 } } else if (wr != 0) { // assume white sacrifices a rook against the lone pawn w_maj--; w_tot -= 2; if (false) { } else if (b_tot == 1) { ASSERT(b_maj==0); ASSERT(b_min==1); // KBK* or KNK*, always insufficient mul[Black] = 4; // 1/4 } else if (b_tot == 2 && bn == 2) { ASSERT(b_maj==0); ASSERT(b_min==2); // KNNK*, usually insufficient mul[Black] = 4; // 1/4 } else if (b_tot-w_tot <= 1 && b_maj <= 2) { // no more than 1 minor up, drawish mul[Black] = 8; // 1/2 } } } // potential draw for white if (wt == wb+wp && wp >= 1) cflags[White] |= MatRookPawnFlag; if (wt == wb+wp && wb <= 1 && wp >= 1 && bt > bp) cflags[White] |= MatBishopFlag; if (wt == 2 && wn == 1 && wp == 1 && bt > bp) cflags[White] |= MatKnightFlag; // potential draw for black if (bt == bb+bp && bp >= 1) cflags[Black] |= MatRookPawnFlag; if (bt == bb+bp && bb <= 1 && bp >= 1 && wt > wp) cflags[Black] |= MatBishopFlag; if (bt == 2 && bn == 1 && bp == 1 && wt > wp) cflags[Black] |= MatKnightFlag; // draw leaf (likely draw) if (recog == MAT_KQKQ || recog == MAT_KRKR) { mul[White] = 0; mul[Black] = 0; } // king safety if (bq >= 1 && bq+br+bb+bn >= 2) cflags[White] |= MatKingFlag; if (wq >= 1 && wq+wr+wb+wn >= 2) cflags[Black] |= MatKingFlag; // phase (0: opening -> 256: endgame) phase = TotalPhase; phase -= wp * PawnPhase; phase -= wn * KnightPhase; phase -= wb * BishopPhase; phase -= wr * RookPhase; phase -= wq * QueenPhase; phase -= bp * PawnPhase; phase -= bn * KnightPhase; phase -= bb * BishopPhase; phase -= br * RookPhase; phase -= bq * QueenPhase; if (phase < 0) phase = 0; ASSERT(phase>=0&&phase<=TotalPhase); phase = (phase * 256 + (TotalPhase / 2)) / TotalPhase; ASSERT(phase>=0&&phase<=256); // material opening = 0; endgame = 0; opening += wp * PawnOpening; opening += wn * KnightOpening; opening += wb * BishopOpening; opening += wr * RookOpening; opening += wq * QueenOpening; opening -= bp * PawnOpening; opening -= bn * KnightOpening; opening -= bb * BishopOpening; opening -= br * RookOpening; opening -= bq * QueenOpening; endgame += wp * PawnEndgame; endgame += wn * KnightEndgame; endgame += wb * BishopEndgame; endgame += wr * RookEndgame; endgame += wq * QueenEndgame; endgame -= bp * PawnEndgame; endgame -= bn * KnightEndgame; endgame -= bb * BishopEndgame; endgame -= br * RookEndgame; endgame -= bq * QueenEndgame; // bishop pair if (wb >= 2) { // HACK: assumes different colours opening += BishopPairOpening; endgame += BishopPairEndgame; } if (bb >= 2) { // HACK: assumes different colours opening -= BishopPairOpening; endgame -= BishopPairEndgame; } // store info info->recog = recog; info->flags = flags; for (colour = 0; colour < ColourNb; colour++) info->cflags[colour] = cflags[colour]; for (colour = 0; colour < ColourNb; colour++) info->mul[colour] = mul[colour]; info->phase = phase; info->opening = (opening * MaterialWeight) / 256; info->endgame = (endgame * MaterialWeight) / 256; } // end of material.cpp fruit-2.1.dfsg-1.orig/src/pawn.h0000600000175000017500000000213410402400155015772 0ustar oliveroliver // pawn.h #ifndef PAWN_H #define PAWN_H // includes #include "board.h" #include "colour.h" #include "util.h" // macros #define BIT(n) (BitEQ[n]) #define BIT_FIRST(b) (BitFirst[b]) #define BIT_LAST(b) (BitLast[b]) #define BIT_COUNT(b) (BitCount[b]) // constants const int BackRankFlag = 1 << 0; // types struct pawn_info_t { uint32 lock; sint16 opening; sint16 endgame; uint8 flags[ColourNb]; uint8 passed_bits[ColourNb]; uint8 single_file[ColourNb]; uint16 pad; }; // variables extern int BitEQ[16]; extern int BitLT[16]; extern int BitLE[16]; extern int BitGT[16]; extern int BitGE[16]; extern int BitFirst[0x100]; extern int BitLast[0x100]; extern int BitCount[0x100]; extern int BitRev[0x100]; // functions extern void pawn_init_bit (); extern void pawn_init (); extern void pawn_alloc (); extern void pawn_clear (); extern void pawn_get_info (pawn_info_t * info, const board_t * board); extern int quad (int y_min, int y_max, int x); #endif // !defined PAWN_H // end of pawn.h fruit-2.1.dfsg-1.orig/src/material.h0000600000175000017500000000226710402400155016632 0ustar oliveroliver // material.h #ifndef MATERIAL_H #define MATERIAL_H // includes #include "board.h" #include "colour.h" #include "util.h" // constants enum mat_dummy_t { MAT_NONE, MAT_KK, MAT_KBK, MAT_KKB, MAT_KNK, MAT_KKN, MAT_KPK, MAT_KKP, MAT_KQKQ, MAT_KQKP, MAT_KPKQ, MAT_KRKR, MAT_KRKP, MAT_KPKR, MAT_KBKB, MAT_KBKP, MAT_KPKB, MAT_KBPK, MAT_KKBP, MAT_KNKN, MAT_KNKP, MAT_KPKN, MAT_KNPK, MAT_KKNP, MAT_KRPKR, MAT_KRKRP, MAT_KBPKB, MAT_KBKBP, MAT_NB }; const int DrawNodeFlag = 1 << 0; const int DrawBishopFlag = 1 << 1; const int MatRookPawnFlag = 1 << 0; const int MatBishopFlag = 1 << 1; const int MatKnightFlag = 1 << 2; const int MatKingFlag = 1 << 3; // types struct material_info_t { uint32 lock; uint8 recog; uint8 flags; uint8 cflags[ColourNb]; uint8 mul[ColourNb]; sint16 phase; sint16 opening; sint16 endgame; }; // functions extern void material_init (); extern void material_alloc (); extern void material_clear (); extern void material_get_info (material_info_t * info, const board_t * board); #endif // !defined MATERIAL_H // end of material.h fruit-2.1.dfsg-1.orig/src/value.h0000600000175000017500000000220710402400155016142 0ustar oliveroliver // value.h #ifndef VALUE_H #define VALUE_H // includes #include "piece.h" #include "util.h" // constants const int ValuePawn = 100; // was 100 const int ValueKnight = 325; // was 300 const int ValueBishop = 325; // was 300 const int ValueRook = 500; // was 500 const int ValueQueen = 1000; // was 900 const int ValueKing = 10000; // was 10000 const int ValueNone = -32767; const int ValueDraw = 0; const int ValueMate = 30000; const int ValueInf = ValueMate; const int ValueEvalInf = ValueMate - 256; // handle mates upto 255 plies // macros #define VALUE_MATE(height) (-ValueMate+(height)) #define VALUE_PIECE(piece) (ValuePiece[piece]) // variables extern int ValuePiece[PieceNb]; // functions extern void value_init (); extern bool value_is_ok (int value); extern bool range_is_ok (int min, int max); extern bool value_is_mate (int value); extern int value_to_trans (int value, int height); extern int value_from_trans (int value, int height); extern int value_to_mate (int value); #endif // !defined VALUE_H // end of value.h fruit-2.1.dfsg-1.orig/src/pv.cpp0000600000175000017500000000256010402400155016010 0ustar oliveroliver // pv.cpp // includes #include #include "board.h" #include "move.h" #include "move_do.h" #include "pv.h" #include "util.h" // functions // pv_is_ok() bool pv_is_ok(const mv_t pv[]) { int pos; int move; if (pv == NULL) return false; for (pos = 0; true; pos++) { if (pos >= 256) return false; move = pv[pos]; if (move == MoveNone) return true; if (!move_is_ok(move)) return false; } return true; } // pv_copy() void pv_copy(mv_t dst[], const mv_t src[]) { ASSERT(pv_is_ok(src)); ASSERT(dst!=NULL); while ((*dst++ = *src++) != MoveNone) ; } // pv_cat() void pv_cat(mv_t dst[], const mv_t src[], int move) { ASSERT(pv_is_ok(src)); ASSERT(dst!=NULL); *dst++ = move; while ((*dst++ = *src++) != MoveNone) ; } // pv_to_string() bool pv_to_string(const mv_t pv[], char string[], int size) { int pos; int move; ASSERT(pv_is_ok(pv)); ASSERT(string!=NULL); ASSERT(size>=512); // init if (size < 512) return false; pos = 0; // loop while ((move = *pv++) != MoveNone) { if (pos != 0) string[pos++] = ' '; move_to_string(move,&string[pos],size-pos); pos += strlen(&string[pos]); } string[pos] = '\0'; return true; } // end of pv.cpp fruit-2.1.dfsg-1.orig/src/value.cpp0000600000175000017500000000460310402400155016477 0ustar oliveroliver // value.cpp // includes #include "piece.h" #include "search.h" #include "util.h" #include "value.h" // variables int ValuePiece[PieceNb]; // functions // value_init() void value_init() { int piece; // ValuePiece[] for (piece = 0; piece < PieceNb; piece++) ValuePiece[piece] = -1; ValuePiece[Empty] = 0; // needed? ValuePiece[Edge] = 0; // needed? ValuePiece[WP] = ValuePawn; ValuePiece[WN] = ValueKnight; ValuePiece[WB] = ValueBishop; ValuePiece[WR] = ValueRook; ValuePiece[WQ] = ValueQueen; ValuePiece[WK] = ValueKing; ValuePiece[BP] = ValuePawn; ValuePiece[BN] = ValueKnight; ValuePiece[BB] = ValueBishop; ValuePiece[BR] = ValueRook; ValuePiece[BQ] = ValueQueen; ValuePiece[BK] = ValueKing; } // value_is_ok() bool value_is_ok(int value) { if (value < -ValueInf || value > +ValueInf) return false; return true; } // range_is_ok() bool range_is_ok(int min, int max) { if (!value_is_ok(min)) return false; if (!value_is_ok(max)) return false; if (min >= max) return false; // alpha-beta-like ranges cannot be null return true; } // value_is_mate() bool value_is_mate(int value) { ASSERT(value_is_ok(value)); if (value < -ValueEvalInf || value > +ValueEvalInf) return true; return false; } // value_to_trans() int value_to_trans(int value, int height) { ASSERT(value_is_ok(value)); ASSERT(height_is_ok(height)); if (value < -ValueEvalInf) { value -= height; } else if (value > +ValueEvalInf) { value += height; } ASSERT(value_is_ok(value)); return value; } // value_from_trans() int value_from_trans(int value, int height) { ASSERT(value_is_ok(value)); ASSERT(height_is_ok(height)); if (value < -ValueEvalInf) { value += height; } else if (value > +ValueEvalInf) { value -= height; } ASSERT(value_is_ok(value)); return value; } // value_to_mate() int value_to_mate(int value) { int dist; ASSERT(value_is_ok(value)); if (value < -ValueEvalInf) { dist = (ValueMate + value) / 2; ASSERT(dist>0); return -dist; } else if (value > +ValueEvalInf) { dist = (ValueMate - value + 1) / 2; ASSERT(dist>0); return +dist; } return 0; } // end of value.cpp fruit-2.1.dfsg-1.orig/src/move_gen.cpp0000600000175000017500000004667110402400155017175 0ustar oliveroliver // move_gen.cpp // includes #include "attack.h" #include "board.h" #include "colour.h" #include "list.h" #include "move.h" #include "move_evasion.h" #include "move_gen.h" #include "move_legal.h" #include "piece.h" #include "util.h" // prototypes static void add_moves (list_t * list, const board_t * board); static void add_captures (list_t * list, const board_t * board); static void add_quiet_moves (list_t * list, const board_t * board); static void add_promotes (list_t * list, const board_t * board); static void add_en_passant_captures (list_t * list, const board_t * board); static void add_castle_moves (list_t * list, const board_t * board); // functions // gen_legal_moves() void gen_legal_moves(list_t * list, board_t * board) { attack_t attack[1]; ASSERT(list!=NULL); ASSERT(board!=NULL); attack_set(attack,board); if (ATTACK_IN_CHECK(attack)) { gen_legal_evasions(list,board,attack); } else { gen_moves(list,board); list_filter(list,board,&pseudo_is_legal,true); } // debug ASSERT(list_is_ok(list)); } // gen_moves() void gen_moves(list_t * list, const board_t * board) { ASSERT(list!=NULL); ASSERT(board!=NULL); ASSERT(!board_is_check(board)); LIST_CLEAR(list); add_moves(list,board); add_en_passant_captures(list,board); add_castle_moves(list,board); // debug ASSERT(list_is_ok(list)); } // gen_captures() void gen_captures(list_t * list, const board_t * board) { ASSERT(list!=NULL); ASSERT(board!=NULL); LIST_CLEAR(list); add_captures(list,board); add_en_passant_captures(list,board); // debug ASSERT(list_is_ok(list)); } // gen_quiet_moves() void gen_quiet_moves(list_t * list, const board_t * board) { ASSERT(list!=NULL); ASSERT(board!=NULL); ASSERT(!board_is_check(board)); LIST_CLEAR(list); add_quiet_moves(list,board); add_castle_moves(list,board); // debug ASSERT(list_is_ok(list)); } // add_moves() static void add_moves(list_t * list, const board_t * board) { int me, opp; int opp_flag; const sq_t * ptr; int from, to; int piece, capture; const inc_t * inc_ptr; int inc; ASSERT(list!=NULL); ASSERT(board!=NULL); me = board->turn; opp = COLOUR_OPP(me); opp_flag = COLOUR_FLAG(opp); // piece moves for (ptr = &board->piece[me][0]; (from=*ptr) != SquareNone; ptr++) { piece = board->square[from]; inc_ptr = PIECE_INC(piece); if (PIECE_IS_SLIDER(piece)) { for (; (inc=*inc_ptr) != IncNone; inc_ptr++) { for (to = from+inc; (capture=board->square[to]) == Empty; to += inc) { LIST_ADD(list,MOVE_MAKE(from,to)); } if (FLAG_IS(capture,opp_flag)) { LIST_ADD(list,MOVE_MAKE(from,to)); } } } else { for (; (inc=*inc_ptr) != IncNone; inc_ptr++) { to = from + inc; capture = board->square[to]; if (capture == Empty || FLAG_IS(capture,opp_flag)) { LIST_ADD(list,MOVE_MAKE(from,to)); } } } } // pawn moves inc = PAWN_MOVE_INC(me); for (ptr = &board->pawn[me][0]; (from=*ptr) != SquareNone; ptr++) { to = from + (inc-1); if (FLAG_IS(board->square[to],opp_flag)) { add_pawn_move(list,from,to); } to = from + (inc+1); if (FLAG_IS(board->square[to],opp_flag)) { add_pawn_move(list,from,to); } to = from + inc; if (board->square[to] == Empty) { add_pawn_move(list,from,to); if (PAWN_RANK(from,me) == Rank2) { to = from + (2*inc); if (board->square[to] == Empty) { ASSERT(!SQUARE_IS_PROMOTE(to)); LIST_ADD(list,MOVE_MAKE(from,to)); } } } } } // add_captures() static void add_captures(list_t * list, const board_t * board) { int me, opp; int opp_flag; const sq_t * ptr; int from, to; int piece, capture; ASSERT(list!=NULL); ASSERT(board!=NULL); me = board->turn; opp = COLOUR_OPP(me); opp_flag = COLOUR_FLAG(opp); // piece captures for (ptr = &board->piece[me][0]; (from=*ptr) != SquareNone; ptr++) { piece = board->square[from]; switch (PIECE_TYPE(piece)) { case Knight64: to = from - 33; if (FLAG_IS(board->square[to],opp_flag)) LIST_ADD(list,MOVE_MAKE(from,to)); to = from - 31; if (FLAG_IS(board->square[to],opp_flag)) LIST_ADD(list,MOVE_MAKE(from,to)); to = from - 18; if (FLAG_IS(board->square[to],opp_flag)) LIST_ADD(list,MOVE_MAKE(from,to)); to = from - 14; if (FLAG_IS(board->square[to],opp_flag)) LIST_ADD(list,MOVE_MAKE(from,to)); to = from + 14; if (FLAG_IS(board->square[to],opp_flag)) LIST_ADD(list,MOVE_MAKE(from,to)); to = from + 18; if (FLAG_IS(board->square[to],opp_flag)) LIST_ADD(list,MOVE_MAKE(from,to)); to = from + 31; if (FLAG_IS(board->square[to],opp_flag)) LIST_ADD(list,MOVE_MAKE(from,to)); to = from + 33; if (FLAG_IS(board->square[to],opp_flag)) LIST_ADD(list,MOVE_MAKE(from,to)); break; case Bishop64: for (to = from-17; (capture=board->square[to]) == Empty; to -= 17) ; if (FLAG_IS(capture,opp_flag)) LIST_ADD(list,MOVE_MAKE(from,to)); for (to = from-15; (capture=board->square[to]) == Empty; to -= 15) ; if (FLAG_IS(capture,opp_flag)) LIST_ADD(list,MOVE_MAKE(from,to)); for (to = from+15; (capture=board->square[to]) == Empty; to += 15) ; if (FLAG_IS(capture,opp_flag)) LIST_ADD(list,MOVE_MAKE(from,to)); for (to = from+17; (capture=board->square[to]) == Empty; to += 17) ; if (FLAG_IS(capture,opp_flag)) LIST_ADD(list,MOVE_MAKE(from,to)); break; case Rook64: for (to = from-16; (capture=board->square[to]) == Empty; to -= 16) ; if (FLAG_IS(capture,opp_flag)) LIST_ADD(list,MOVE_MAKE(from,to)); for (to = from-1; (capture=board->square[to]) == Empty; to -= 1) ; if (FLAG_IS(capture,opp_flag)) LIST_ADD(list,MOVE_MAKE(from,to)); for (to = from+1; (capture=board->square[to]) == Empty; to += 1) ; if (FLAG_IS(capture,opp_flag)) LIST_ADD(list,MOVE_MAKE(from,to)); for (to = from+16; (capture=board->square[to]) == Empty; to += 16) ; if (FLAG_IS(capture,opp_flag)) LIST_ADD(list,MOVE_MAKE(from,to)); break; case Queen64: for (to = from-17; (capture=board->square[to]) == Empty; to -= 17) ; if (FLAG_IS(capture,opp_flag)) LIST_ADD(list,MOVE_MAKE(from,to)); for (to = from-16; (capture=board->square[to]) == Empty; to -= 16) ; if (FLAG_IS(capture,opp_flag)) LIST_ADD(list,MOVE_MAKE(from,to)); for (to = from-15; (capture=board->square[to]) == Empty; to -= 15) ; if (FLAG_IS(capture,opp_flag)) LIST_ADD(list,MOVE_MAKE(from,to)); for (to = from-1; (capture=board->square[to]) == Empty; to -= 1) ; if (FLAG_IS(capture,opp_flag)) LIST_ADD(list,MOVE_MAKE(from,to)); for (to = from+1; (capture=board->square[to]) == Empty; to += 1) ; if (FLAG_IS(capture,opp_flag)) LIST_ADD(list,MOVE_MAKE(from,to)); for (to = from+15; (capture=board->square[to]) == Empty; to += 15) ; if (FLAG_IS(capture,opp_flag)) LIST_ADD(list,MOVE_MAKE(from,to)); for (to = from+16; (capture=board->square[to]) == Empty; to += 16) ; if (FLAG_IS(capture,opp_flag)) LIST_ADD(list,MOVE_MAKE(from,to)); for (to = from+17; (capture=board->square[to]) == Empty; to += 17) ; if (FLAG_IS(capture,opp_flag)) LIST_ADD(list,MOVE_MAKE(from,to)); break; case King64: to = from - 17; if (FLAG_IS(board->square[to],opp_flag)) LIST_ADD(list,MOVE_MAKE(from,to)); to = from - 16; if (FLAG_IS(board->square[to],opp_flag)) LIST_ADD(list,MOVE_MAKE(from,to)); to = from - 15; if (FLAG_IS(board->square[to],opp_flag)) LIST_ADD(list,MOVE_MAKE(from,to)); to = from - 1; if (FLAG_IS(board->square[to],opp_flag)) LIST_ADD(list,MOVE_MAKE(from,to)); to = from + 1; if (FLAG_IS(board->square[to],opp_flag)) LIST_ADD(list,MOVE_MAKE(from,to)); to = from + 15; if (FLAG_IS(board->square[to],opp_flag)) LIST_ADD(list,MOVE_MAKE(from,to)); to = from + 16; if (FLAG_IS(board->square[to],opp_flag)) LIST_ADD(list,MOVE_MAKE(from,to)); to = from + 17; if (FLAG_IS(board->square[to],opp_flag)) LIST_ADD(list,MOVE_MAKE(from,to)); break; default: ASSERT(false); break; } } // pawn captures if (COLOUR_IS_WHITE(me)) { for (ptr = &board->pawn[me][0]; (from=*ptr) != SquareNone; ptr++) { to = from + 15; if (FLAG_IS(board->square[to],opp_flag)) add_pawn_move(list,from,to); to = from + 17; if (FLAG_IS(board->square[to],opp_flag)) add_pawn_move(list,from,to); // promote if (SQUARE_RANK(from) == Rank7) { to = from + 16; if (board->square[to] == Empty) { add_promote(list,MOVE_MAKE(from,to)); } } } } else { // black for (ptr = &board->pawn[me][0]; (from=*ptr) != SquareNone; ptr++) { to = from - 17; if (FLAG_IS(board->square[to],opp_flag)) add_pawn_move(list,from,to); to = from - 15; if (FLAG_IS(board->square[to],opp_flag)) add_pawn_move(list,from,to); // promote if (SQUARE_RANK(from) == Rank2) { to = from - 16; if (board->square[to] == Empty) { add_promote(list,MOVE_MAKE(from,to)); } } } } } // add_quiet_moves() static void add_quiet_moves(list_t * list, const board_t * board) { int me; const sq_t * ptr; int from, to; int piece; ASSERT(list!=NULL); ASSERT(board!=NULL); me = board->turn; // piece moves for (ptr = &board->piece[me][0]; (from=*ptr) != SquareNone; ptr++) { piece = board->square[from]; switch (PIECE_TYPE(piece)) { case Knight64: to = from - 33; if (board->square[to] == Empty) LIST_ADD(list,MOVE_MAKE(from,to)); to = from - 31; if (board->square[to] == Empty) LIST_ADD(list,MOVE_MAKE(from,to)); to = from - 18; if (board->square[to] == Empty) LIST_ADD(list,MOVE_MAKE(from,to)); to = from - 14; if (board->square[to] == Empty) LIST_ADD(list,MOVE_MAKE(from,to)); to = from + 14; if (board->square[to] == Empty) LIST_ADD(list,MOVE_MAKE(from,to)); to = from + 18; if (board->square[to] == Empty) LIST_ADD(list,MOVE_MAKE(from,to)); to = from + 31; if (board->square[to] == Empty) LIST_ADD(list,MOVE_MAKE(from,to)); to = from + 33; if (board->square[to] == Empty) LIST_ADD(list,MOVE_MAKE(from,to)); break; case Bishop64: for (to = from-17; board->square[to] == Empty; to -= 17) { LIST_ADD(list,MOVE_MAKE(from,to)); } for (to = from-15; board->square[to] == Empty; to -= 15) { LIST_ADD(list,MOVE_MAKE(from,to)); } for (to = from+15; board->square[to] == Empty; to += 15) { LIST_ADD(list,MOVE_MAKE(from,to)); } for (to = from+17; board->square[to] == Empty; to += 17) { LIST_ADD(list,MOVE_MAKE(from,to)); } break; case Rook64: for (to = from-16; board->square[to] == Empty; to -= 16) { LIST_ADD(list,MOVE_MAKE(from,to)); } for (to = from-1; board->square[to] == Empty; to -= 1) { LIST_ADD(list,MOVE_MAKE(from,to)); } for (to = from+1; board->square[to] == Empty; to += 1) { LIST_ADD(list,MOVE_MAKE(from,to)); } for (to = from+16; board->square[to] == Empty; to += 16) { LIST_ADD(list,MOVE_MAKE(from,to)); } break; case Queen64: for (to = from-17; board->square[to] == Empty; to -= 17) { LIST_ADD(list,MOVE_MAKE(from,to)); } for (to = from-16; board->square[to] == Empty; to -= 16) { LIST_ADD(list,MOVE_MAKE(from,to)); } for (to = from-15; board->square[to] == Empty; to -= 15) { LIST_ADD(list,MOVE_MAKE(from,to)); } for (to = from-1; board->square[to] == Empty; to -= 1) { LIST_ADD(list,MOVE_MAKE(from,to)); } for (to = from+1; board->square[to] == Empty; to += 1) { LIST_ADD(list,MOVE_MAKE(from,to)); } for (to = from+15; board->square[to] == Empty; to += 15) { LIST_ADD(list,MOVE_MAKE(from,to)); } for (to = from+16; board->square[to] == Empty; to += 16) { LIST_ADD(list,MOVE_MAKE(from,to)); } for (to = from+17; board->square[to] == Empty; to += 17) { LIST_ADD(list,MOVE_MAKE(from,to)); } break; case King64: to = from - 17; if (board->square[to] == Empty) LIST_ADD(list,MOVE_MAKE(from,to)); to = from - 16; if (board->square[to] == Empty) LIST_ADD(list,MOVE_MAKE(from,to)); to = from - 15; if (board->square[to] == Empty) LIST_ADD(list,MOVE_MAKE(from,to)); to = from - 1; if (board->square[to] == Empty) LIST_ADD(list,MOVE_MAKE(from,to)); to = from + 1; if (board->square[to] == Empty) LIST_ADD(list,MOVE_MAKE(from,to)); to = from + 15; if (board->square[to] == Empty) LIST_ADD(list,MOVE_MAKE(from,to)); to = from + 16; if (board->square[to] == Empty) LIST_ADD(list,MOVE_MAKE(from,to)); to = from + 17; if (board->square[to] == Empty) LIST_ADD(list,MOVE_MAKE(from,to)); break; default: ASSERT(false); break; } } // pawn moves if (COLOUR_IS_WHITE(me)) { for (ptr = &board->pawn[me][0]; (from=*ptr) != SquareNone; ptr++) { // non promotes if (SQUARE_RANK(from) != Rank7) { to = from + 16; if (board->square[to] == Empty) { ASSERT(!SQUARE_IS_PROMOTE(to)); LIST_ADD(list,MOVE_MAKE(from,to)); if (SQUARE_RANK(from) == Rank2) { to = from + 32; if (board->square[to] == Empty) { ASSERT(!SQUARE_IS_PROMOTE(to)); LIST_ADD(list,MOVE_MAKE(from,to)); } } } } } } else { // black for (ptr = &board->pawn[me][0]; (from=*ptr) != SquareNone; ptr++) { // non promotes if (SQUARE_RANK(from) != Rank2) { to = from - 16; if (board->square[to] == Empty) { ASSERT(!SQUARE_IS_PROMOTE(to)); LIST_ADD(list,MOVE_MAKE(from,to)); if (SQUARE_RANK(from) == Rank7) { to = from - 32; if (board->square[to] == Empty) { ASSERT(!SQUARE_IS_PROMOTE(to)); LIST_ADD(list,MOVE_MAKE(from,to)); } } } } } } } // add_promotes() static void add_promotes(list_t * list, const board_t * board) { int me; int inc; const sq_t * ptr; int from, to; ASSERT(list!=NULL); ASSERT(board!=NULL); me = board->turn; inc = PAWN_MOVE_INC(me); for (ptr = &board->pawn[me][0]; (from=*ptr) != SquareNone; ptr++) { if (PAWN_RANK(from,me) == Rank7) { to = from + inc; if (board->square[to] == Empty) { add_promote(list,MOVE_MAKE(from,to)); } } } } // add_en_passant_captures() static void add_en_passant_captures(list_t * list, const board_t * board) { int from, to; int me; int inc; int pawn; ASSERT(list!=NULL); ASSERT(board!=NULL); to = board->ep_square; if (to != SquareNone) { me = board->turn; inc = PAWN_MOVE_INC(me); pawn = PAWN_MAKE(me); from = to - (inc-1); if (board->square[from] == pawn) { ASSERT(!SQUARE_IS_PROMOTE(to)); LIST_ADD(list,MOVE_MAKE_FLAGS(from,to,MoveEnPassant)); } from = to - (inc+1); if (board->square[from] == pawn) { ASSERT(!SQUARE_IS_PROMOTE(to)); LIST_ADD(list,MOVE_MAKE_FLAGS(from,to,MoveEnPassant)); } } } // add_castle_moves() static void add_castle_moves(list_t * list, const board_t * board) { ASSERT(list!=NULL); ASSERT(board!=NULL); ASSERT(!board_is_check(board)); if (COLOUR_IS_WHITE(board->turn)) { if ((board->flags & FlagsWhiteKingCastle) != 0 && board->square[F1] == Empty && board->square[G1] == Empty && !is_attacked(board,F1,Black)) { LIST_ADD(list,MOVE_MAKE_FLAGS(E1,G1,MoveCastle)); } if ((board->flags & FlagsWhiteQueenCastle) != 0 && board->square[D1] == Empty && board->square[C1] == Empty && board->square[B1] == Empty && !is_attacked(board,D1,Black)) { LIST_ADD(list,MOVE_MAKE_FLAGS(E1,C1,MoveCastle)); } } else { // black if ((board->flags & FlagsBlackKingCastle) != 0 && board->square[F8] == Empty && board->square[G8] == Empty && !is_attacked(board,F8,White)) { LIST_ADD(list,MOVE_MAKE_FLAGS(E8,G8,MoveCastle)); } if ((board->flags & FlagsBlackQueenCastle) != 0 && board->square[D8] == Empty && board->square[C8] == Empty && board->square[B8] == Empty && !is_attacked(board,D8,White)) { LIST_ADD(list,MOVE_MAKE_FLAGS(E8,C8,MoveCastle)); } } } // add_pawn_move() void add_pawn_move(list_t * list, int from, int to) { int move; ASSERT(list!=NULL); ASSERT(SQUARE_IS_OK(from)); ASSERT(SQUARE_IS_OK(to)); move = MOVE_MAKE(from,to); if (SQUARE_IS_PROMOTE(to)) { LIST_ADD(list,move|MovePromoteQueen); LIST_ADD(list,move|MovePromoteKnight); LIST_ADD(list,move|MovePromoteRook); LIST_ADD(list,move|MovePromoteBishop); } else { LIST_ADD(list,move); } } // add_promote() void add_promote(list_t * list, int move) { ASSERT(list!=NULL); ASSERT(move_is_ok(move)); ASSERT((move&~07777)==0); // HACK ASSERT(SQUARE_IS_PROMOTE(MOVE_TO(move))); LIST_ADD(list,move|MovePromoteQueen); LIST_ADD(list,move|MovePromoteKnight); LIST_ADD(list,move|MovePromoteRook); LIST_ADD(list,move|MovePromoteBishop); } // end of move_gen.cpp fruit-2.1.dfsg-1.orig/src/sort.h0000600000175000017500000000215310402400155016015 0ustar oliveroliver // sort.h #ifndef SORT_H #define SORT_H // includes #include "attack.h" #include "board.h" #include "list.h" #include "util.h" // types struct sort_t { int depth; int height; int trans_killer; int killer_1; int killer_2; int gen; int test; int pos; int value; board_t * board; const attack_t * attack; list_t list[1]; list_t bad[1]; }; // functions extern void sort_init (); extern void sort_init (sort_t * sort, board_t * board, const attack_t * attack, int depth, int height, int trans_killer); extern int sort_next (sort_t * sort); extern void sort_init_qs (sort_t * sort, board_t * board, const attack_t * attack, bool check); extern int sort_next_qs (sort_t * sort); extern void good_move (int move, const board_t * board, int depth, int height); extern void history_good (int move, const board_t * board); extern void history_bad (int move, const board_t * board); extern void note_moves (list_t * list, const board_t * board, int height, int trans_killer); #endif // !defined SORT_H // end of sort.h fruit-2.1.dfsg-1.orig/src/util.h0000600000175000017500000000501110402400155015777 0ustar oliveroliver // util.h #ifndef UTIL_H #define UTIL_H // includes #include // constants #undef FALSE #define FALSE 0 #undef TRUE #define TRUE 1 #ifdef DEBUG # undef DEBUG # define DEBUG TRUE #else # define DEBUG FALSE #endif #ifdef _MSC_VER # define S64_FORMAT "%I64d" # define U64_FORMAT "%016I64X" #else # define S64_FORMAT "%lld" # define U64_FORMAT "%016llX" #endif // macros #ifdef _MSC_VER # define S64(u) (u##i64) # define U64(u) (u##ui64) #else # define S64(u) (u##LL) # define U64(u) (u##ULL) #endif #undef ASSERT #if DEBUG # define ASSERT(a) { if (!(a)) my_fatal("file \"%s\", line %d, assertion \"" #a "\" failed\n",__FILE__,__LINE__); } #else # define ASSERT(a) #endif // types typedef signed char sint8; typedef unsigned char uint8; typedef signed short sint16; typedef unsigned short uint16; typedef signed int sint32; typedef unsigned int uint32; #ifdef _MSC_VER typedef signed __int64 sint64; typedef unsigned __int64 uint64; #else typedef signed long long int sint64; typedef unsigned long long int uint64; #endif struct my_timer_t { double start_real; double start_cpu; double elapsed_real; double elapsed_cpu; bool running; }; // functions extern void util_init (); extern void my_random_init (); extern int my_random (int n); extern sint64 my_atoll (const char string[]); extern int my_round (double x); extern void * my_malloc (int size); extern void my_free (void * address); extern void my_fatal (const char format[], ...); extern bool my_file_read_line (FILE * file, char string[], int size); extern bool my_string_empty (const char string[]); extern bool my_string_equal (const char string_1[], const char string_2[]); extern char * my_strdup (const char string[]); extern void my_string_clear (const char * * variable); extern void my_string_set (const char * * variable, const char string[]); extern void my_timer_reset (my_timer_t * timer); extern void my_timer_start (my_timer_t * timer); extern void my_timer_stop (my_timer_t * timer); extern double my_timer_elapsed_real (const my_timer_t * timer); extern double my_timer_elapsed_cpu (const my_timer_t * timer); extern double my_timer_cpu_usage (const my_timer_t * timer); #endif // !defined UTIL_H // end of util.h fruit-2.1.dfsg-1.orig/src/search.cpp0000600000175000017500000002643010402400155016632 0ustar oliveroliver // search.cpp // includes #include #include "attack.h" #include "board.h" #include "book.h" #include "colour.h" #include "list.h" #include "material.h" #include "move.h" #include "move_do.h" #include "move_gen.h" #include "option.h" #include "pawn.h" #include "protocol.h" #include "pv.h" #include "search.h" #include "search_full.h" #include "sort.h" #include "trans.h" #include "util.h" #include "value.h" // constants static const bool UseCpuTime = false; // false static const bool UseEvent = true; // true static const bool UseShortSearch = true; static const int ShortSearchDepth = 1; static const bool DispBest = true; // true static const bool DispDepthStart = true; // true static const bool DispDepthEnd = true; // true static const bool DispRoot = true; // true static const bool DispStat = true; // true static const bool UseEasy = true; // singular move static const int EasyThreshold = 150; static const double EasyRatio = 0.20; static const bool UseEarly = true; // early iteration end static const double EarlyRatio = 0.60; static const bool UseBad = true; static const int BadThreshold = 50; // 50 static const bool UseExtension = true; // variables search_input_t SearchInput[1]; search_info_t SearchInfo[1]; search_root_t SearchRoot[1]; search_current_t SearchCurrent[1]; search_best_t SearchBest[1]; // prototypes static void search_send_stat (); // functions // depth_is_ok() bool depth_is_ok(int depth) { return depth > -128 && depth < DepthMax; } // height_is_ok() bool height_is_ok(int height) { return height >= 0 && height < HeightMax; } // search_clear() void search_clear() { // SearchInput SearchInput->infinite = false; SearchInput->depth_is_limited = false; SearchInput->depth_limit = 0; SearchInput->time_is_limited = false; SearchInput->time_limit_1 = 0.0; SearchInput->time_limit_2 = 0.0; // SearchInfo SearchInfo->can_stop = false; SearchInfo->stop = false; SearchInfo->check_nb = 10000; // was 100000 SearchInfo->check_inc = 10000; // was 100000 SearchInfo->last_time = 0.0; // SearchBest SearchBest->move = MoveNone; SearchBest->value = 0; SearchBest->flags = SearchUnknown; PV_CLEAR(SearchBest->pv); // SearchRoot SearchRoot->depth = 0; SearchRoot->move = MoveNone; SearchRoot->move_pos = 0; SearchRoot->move_nb = 0; SearchRoot->last_value = 0; SearchRoot->bad_1 = false; SearchRoot->bad_2 = false; SearchRoot->change = false; SearchRoot->easy = false; SearchRoot->flag = false; // SearchCurrent SearchCurrent->max_depth = 0; SearchCurrent->node_nb = 0; SearchCurrent->time = 0.0; SearchCurrent->speed = 0.0; SearchCurrent->cpu = 0.0; } // search() void search() { int move; int depth; ASSERT(board_is_ok(SearchInput->board)); // opening book if (option_get_bool("OwnBook") && !SearchInput->infinite) { move = book_move(SearchInput->board); if (move != MoveNone) { // play book move SearchBest->move = move; SearchBest->value = 1; SearchBest->flags = SearchExact; SearchBest->depth = 1; SearchBest->pv[0] = move; SearchBest->pv[1] = MoveNone; search_update_best(); return; } } // SearchInput gen_legal_moves(SearchInput->list,SearchInput->board); if (LIST_SIZE(SearchInput->list) <= 1) { SearchInput->depth_is_limited = true; SearchInput->depth_limit = 4; // was 1 } // SearchInfo if (setjmp(SearchInfo->buf) != 0) { ASSERT(SearchInfo->can_stop); ASSERT(SearchBest->move!=MoveNone); search_update_current(); return; } // SearchRoot list_copy(SearchRoot->list,SearchInput->list); // SearchCurrent board_copy(SearchCurrent->board,SearchInput->board); my_timer_reset(SearchCurrent->timer); my_timer_start(SearchCurrent->timer); // init trans_inc_date(Trans); sort_init(); search_full_init(SearchRoot->list,SearchCurrent->board); // iterative deepening for (depth = 1; depth < DepthMax; depth++) { if (DispDepthStart) send("info depth %d",depth); SearchRoot->bad_1 = false; SearchRoot->change = false; board_copy(SearchCurrent->board,SearchInput->board); if (UseShortSearch && depth <= ShortSearchDepth) { search_full_root(SearchRoot->list,SearchCurrent->board,depth,SearchShort); } else { search_full_root(SearchRoot->list,SearchCurrent->board,depth,SearchNormal); } search_update_current(); if (DispDepthEnd) { send("info depth %d seldepth %d time %.0f nodes " S64_FORMAT " nps %.0f",depth,SearchCurrent->max_depth,SearchCurrent->time*1000.0,SearchCurrent->node_nb,SearchCurrent->speed); } // update search info if (depth >= 1) SearchInfo->can_stop = true; if (depth == 1 && LIST_SIZE(SearchRoot->list) >= 2 && LIST_VALUE(SearchRoot->list,0) >= LIST_VALUE(SearchRoot->list,1) + EasyThreshold) { SearchRoot->easy = true; } if (UseBad && depth > 1) { SearchRoot->bad_2 = SearchRoot->bad_1; SearchRoot->bad_1 = false; ASSERT(SearchRoot->bad_2==(SearchBest->value<=SearchRoot->last_value-BadThreshold)); } SearchRoot->last_value = SearchBest->value; // stop search? if (SearchInput->depth_is_limited && depth >= SearchInput->depth_limit) { SearchRoot->flag = true; } if (SearchInput->time_is_limited && SearchCurrent->time >= SearchInput->time_limit_1 && !SearchRoot->bad_2) { SearchRoot->flag = true; } if (UseEasy && SearchInput->time_is_limited && SearchCurrent->time >= SearchInput->time_limit_1 * EasyRatio && SearchRoot->easy) { ASSERT(!SearchRoot->bad_2); ASSERT(!SearchRoot->change); SearchRoot->flag = true; } if (UseEarly && SearchInput->time_is_limited && SearchCurrent->time >= SearchInput->time_limit_1 * EarlyRatio && !SearchRoot->bad_2 && !SearchRoot->change) { SearchRoot->flag = true; } if (SearchInfo->can_stop && (SearchInfo->stop || (SearchRoot->flag && !SearchInput->infinite))) { break; } } } // search_update_best() void search_update_best() { int move, value, flags, depth, max_depth; const mv_t * pv; double time; sint64 node_nb; int mate; char move_string[256], pv_string[512]; search_update_current(); if (DispBest) { move = SearchBest->move; value = SearchBest->value; flags = SearchBest->flags; depth = SearchBest->depth; pv = SearchBest->pv; max_depth = SearchCurrent->max_depth; time = SearchCurrent->time; node_nb = SearchCurrent->node_nb; move_to_string(move,move_string,256); pv_to_string(pv,pv_string,512); mate = value_to_mate(value); if (mate == 0) { // normal evaluation if (false) { } else if (flags == SearchExact) { send("info depth %d seldepth %d score cp %d time %.0f nodes " S64_FORMAT " pv %s",depth,max_depth,value,time*1000.0,node_nb,pv_string); } else if (flags == SearchLower) { send("info depth %d seldepth %d score cp %d lowerbound time %.0f nodes " S64_FORMAT " pv %s",depth,max_depth,value,time*1000.0,node_nb,pv_string); } else if (flags == SearchUpper) { send("info depth %d seldepth %d score cp %d upperbound time %.0f nodes " S64_FORMAT " pv %s",depth,max_depth,value,time*1000.0,node_nb,pv_string); } } else { // mate announcement if (false) { } else if (flags == SearchExact) { send("info depth %d seldepth %d score mate %d time %.0f nodes " S64_FORMAT " pv %s",depth,max_depth,mate,time*1000.0,node_nb,pv_string); } else if (flags == SearchLower) { send("info depth %d seldepth %d score mate %d lowerbound time %.0f nodes " S64_FORMAT " pv %s",depth,max_depth,mate,time*1000.0,node_nb,pv_string); } else if (flags == SearchUpper) { send("info depth %d seldepth %d score mate %d upperbound time %.0f nodes " S64_FORMAT " pv %s",depth,max_depth,mate,time*1000.0,node_nb,pv_string); } } } // update time-management info if (UseBad && SearchBest->depth > 1) { if (SearchBest->value <= SearchRoot->last_value - BadThreshold) { SearchRoot->bad_1 = true; SearchRoot->easy = false; SearchRoot->flag = false; } else { SearchRoot->bad_1 = false; } } } // search_update_root() void search_update_root() { int move, move_pos, move_nb; double time; sint64 node_nb; char move_string[256]; if (DispRoot) { search_update_current(); if (SearchCurrent->time >= 1.0) { move = SearchRoot->move; move_pos = SearchRoot->move_pos; move_nb = SearchRoot->move_nb; time = SearchCurrent->time; node_nb = SearchCurrent->node_nb; move_to_string(move,move_string,256); send("info currmove %s currmovenumber %d",move_string,move_pos+1); } } } // search_update_current() void search_update_current() { my_timer_t *timer; sint64 node_nb; double time, speed, cpu; timer = SearchCurrent->timer; node_nb = SearchCurrent->node_nb; time = (UseCpuTime) ? my_timer_elapsed_cpu(timer) : my_timer_elapsed_real(timer); speed = (time >= 1.0) ? double(node_nb) / time : 0.0; cpu = my_timer_cpu_usage(timer); SearchCurrent->time = time; SearchCurrent->speed = speed; SearchCurrent->cpu = cpu; } // search_check() void search_check() { search_send_stat(); if (UseEvent) event(); if (SearchInput->depth_is_limited && SearchRoot->depth > SearchInput->depth_limit) { SearchRoot->flag = true; } if (SearchInput->time_is_limited && SearchCurrent->time >= SearchInput->time_limit_2) { SearchRoot->flag = true; } if (SearchInput->time_is_limited && SearchCurrent->time >= SearchInput->time_limit_1 && !SearchRoot->bad_1 && !SearchRoot->bad_2 && (!UseExtension || SearchRoot->move_pos == 0)) { SearchRoot->flag = true; } if (SearchInfo->can_stop && (SearchInfo->stop || (SearchRoot->flag && !SearchInput->infinite))) { longjmp(SearchInfo->buf,1); } } // search_send_stat() static void search_send_stat() { double time, speed, cpu; sint64 node_nb; search_update_current(); if (DispStat && SearchCurrent->time >= SearchInfo->last_time + 1.0) { // at least one-second gap SearchInfo->last_time = SearchCurrent->time; time = SearchCurrent->time; speed = SearchCurrent->speed; cpu = SearchCurrent->cpu; node_nb = SearchCurrent->node_nb; send("info time %.0f nodes " S64_FORMAT " nps %.0f cpuload %.0f",time*1000.0,node_nb,speed,cpu*1000.0); trans_stats(Trans); } } // end of search.cpp fruit-2.1.dfsg-1.orig/src/attack.cpp0000600000175000017500000002632110402400155016633 0ustar oliveroliver // attack.cpp // includes #include "attack.h" #include "board.h" #include "colour.h" #include "move.h" #include "piece.h" #include "util.h" #include "vector.h" // variables int DeltaIncLine[DeltaNb]; int DeltaIncAll[DeltaNb]; int DeltaMask[DeltaNb]; int IncMask[IncNb]; static int PieceCode[PieceNb]; static int PieceDeltaSize[4][256]; // 4kB static int PieceDeltaDelta[4][256][4]; // 16 kB // prototypes static void add_attack (int piece, int king, int target); // functions // attack_init() void attack_init() { int delta, inc; int piece; int dir, dist; int size; int king; int from, to; int pos; // clear for (delta = 0; delta < DeltaNb; delta++) { DeltaIncLine[delta] = IncNone; DeltaIncAll[delta] = IncNone; DeltaMask[delta] = 0; } for (inc = 0; inc < IncNb; inc++) { IncMask[inc] = 0; } // pawn attacks DeltaMask[DeltaOffset-17] |= BlackPawnFlag; DeltaMask[DeltaOffset-15] |= BlackPawnFlag; DeltaMask[DeltaOffset+15] |= WhitePawnFlag; DeltaMask[DeltaOffset+17] |= WhitePawnFlag; // knight attacks for (dir = 0; dir < 8; dir++) { delta = KnightInc[dir]; ASSERT(delta_is_ok(delta)); ASSERT(DeltaIncAll[DeltaOffset+delta]==IncNone); DeltaIncAll[DeltaOffset+delta] = delta; DeltaMask[DeltaOffset+delta] |= KnightFlag; } // bishop/queen attacks for (dir = 0; dir < 4; dir++) { inc = BishopInc[dir]; ASSERT(inc!=IncNone); IncMask[IncOffset+inc] |= BishopFlag; for (dist = 1; dist < 8; dist++) { delta = inc*dist; ASSERT(delta_is_ok(delta)); ASSERT(DeltaIncLine[DeltaOffset+delta]==IncNone); DeltaIncLine[DeltaOffset+delta] = inc; ASSERT(DeltaIncAll[DeltaOffset+delta]==IncNone); DeltaIncAll[DeltaOffset+delta] = inc; DeltaMask[DeltaOffset+delta] |= BishopFlag; } } // rook/queen attacks for (dir = 0; dir < 4; dir++) { inc = RookInc[dir]; ASSERT(inc!=IncNone); IncMask[IncOffset+inc] |= RookFlag; for (dist = 1; dist < 8; dist++) { delta = inc*dist; ASSERT(delta_is_ok(delta)); ASSERT(DeltaIncLine[DeltaOffset+delta]==IncNone); DeltaIncLine[DeltaOffset+delta] = inc; ASSERT(DeltaIncAll[DeltaOffset+delta]==IncNone); DeltaIncAll[DeltaOffset+delta] = inc; DeltaMask[DeltaOffset+delta] |= RookFlag; } } // king attacks for (dir = 0; dir < 8; dir++) { delta = KingInc[dir]; ASSERT(delta_is_ok(delta)); DeltaMask[DeltaOffset+delta] |= KingFlag; } // PieceCode[] for (piece = 0; piece < PieceNb; piece++) { PieceCode[piece] = -1; } PieceCode[WN] = 0; PieceCode[WB] = 1; PieceCode[WR] = 2; PieceCode[WQ] = 3; PieceCode[BN] = 0; PieceCode[BB] = 1; PieceCode[BR] = 2; PieceCode[BQ] = 3; // PieceDeltaSize[][] & PieceDeltaDelta[][][] for (piece = 0; piece < 4; piece++) { for (delta = 0; delta < 256; delta++) { PieceDeltaSize[piece][delta] = 0; } } for (king = 0; king < SquareNb; king++) { if (SQUARE_IS_OK(king)) { for (from = 0; from < SquareNb; from++) { if (SQUARE_IS_OK(from)) { // knight for (pos = 0; (inc=KnightInc[pos]) != IncNone; pos++) { to = from + inc; if (SQUARE_IS_OK(to) && DISTANCE(to,king) == 1) { add_attack(0,king-from,to-from); } } // bishop for (pos = 0; (inc=BishopInc[pos]) != IncNone; pos++) { for (to = from+inc; SQUARE_IS_OK(to); to += inc) { if (DISTANCE(to,king) == 1) { add_attack(1,king-from,to-from); break; } } } // rook for (pos = 0; (inc=RookInc[pos]) != IncNone; pos++) { for (to = from+inc; SQUARE_IS_OK(to); to += inc) { if (DISTANCE(to,king) == 1) { add_attack(2,king-from,to-from); break; } } } // queen for (pos = 0; (inc=QueenInc[pos]) != IncNone; pos++) { for (to = from+inc; SQUARE_IS_OK(to); to += inc) { if (DISTANCE(to,king) == 1) { add_attack(3,king-from,to-from); break; } } } } } } } for (piece = 0; piece < 4; piece++) { for (delta = 0; delta < 256; delta++) { size = PieceDeltaSize[piece][delta]; ASSERT(size>=0&&size<3); PieceDeltaDelta[piece][delta][size] = DeltaNone; } } } // add_attack() static void add_attack(int piece, int king, int target) { int size; int i; ASSERT(piece>=0&&piece<4); ASSERT(delta_is_ok(king)); ASSERT(delta_is_ok(target)); size = PieceDeltaSize[piece][DeltaOffset+king]; ASSERT(size>=0&&size<3); for (i = 0; i < size; i++) { if (PieceDeltaDelta[piece][DeltaOffset+king][i] == target) return; // already in the table } if (size < 2) { PieceDeltaDelta[piece][DeltaOffset+king][size] = target; size++; PieceDeltaSize[piece][DeltaOffset+king] = size; } } // is_attacked() bool is_attacked(const board_t * board, int to, int colour) { int inc; int pawn; const sq_t * ptr; int from; int piece; int delta; int sq; ASSERT(board!=NULL); ASSERT(SQUARE_IS_OK(to)); ASSERT(COLOUR_IS_OK(colour)); // pawn attack inc = PAWN_MOVE_INC(colour); pawn = PAWN_MAKE(colour); if (board->square[to-(inc-1)] == pawn) return true; if (board->square[to-(inc+1)] == pawn) return true; // piece attack for (ptr = &board->piece[colour][0]; (from=*ptr) != SquareNone; ptr++) { piece = board->square[from]; delta = to - from; if (PSEUDO_ATTACK(piece,delta)) { inc = DELTA_INC_ALL(delta); ASSERT(inc!=IncNone); sq = from; do { sq += inc; if (sq == to) return true; } while (board->square[sq] == Empty); } } return false; } // line_is_empty() bool line_is_empty(const board_t * board, int from, int to) { int delta; int inc, sq; ASSERT(board!=NULL); ASSERT(SQUARE_IS_OK(from)); ASSERT(SQUARE_IS_OK(to)); delta = to - from; ASSERT(delta_is_ok(delta)); inc = DELTA_INC_ALL(delta); ASSERT(inc!=IncNone); sq = from; do { sq += inc; if (sq == to) return true; } while (board->square[sq] == Empty); return false; // blocker } // is_pinned() bool is_pinned(const board_t * board, int square, int colour) { int from, to; int inc; int sq, piece; ASSERT(board!=NULL); ASSERT(SQUARE_IS_OK(square)); ASSERT(COLOUR_IS_OK(colour)); from = square; to = KING_POS(board,colour); inc = DELTA_INC_LINE(to-from); if (inc == IncNone) return false; // not a line sq = from; do sq += inc; while (board->square[sq] == Empty); if (sq != to) return false; // blocker sq = from; do sq -= inc; while ((piece=board->square[sq]) == Empty); return COLOUR_IS(piece,COLOUR_OPP(colour)) && SLIDER_ATTACK(piece,inc); } // attack_is_ok() bool attack_is_ok(const attack_t * attack) { int i; int sq, inc; if (attack == NULL) return false; // checks if (attack->dn < 0 || attack->dn > 2) return false; for (i = 0; i < attack->dn; i++) { sq = attack->ds[i]; if (!SQUARE_IS_OK(sq)) return false; inc = attack->di[i]; if (inc != IncNone && !inc_is_ok(inc)) return false; } if (attack->ds[attack->dn] != SquareNone) return false; if (attack->di[attack->dn] != IncNone) return false; return true; } // attack_set() void attack_set(attack_t * attack, const board_t * board) { int me, opp; const sq_t * ptr; int from, to; int inc; int pawn; int delta, piece; int sq; ASSERT(attack!=NULL); ASSERT(board!=NULL); // init attack->dn = 0; me = board->turn; opp = COLOUR_OPP(me); to = KING_POS(board,me); // pawn attacks inc = PAWN_MOVE_INC(opp); pawn = PAWN_MAKE(opp); from = to - (inc-1); if (board->square[from] == pawn) { attack->ds[attack->dn] = from; attack->di[attack->dn] = IncNone; attack->dn++; } from = to - (inc+1); if (board->square[from] == pawn) { attack->ds[attack->dn] = from; attack->di[attack->dn] = IncNone; attack->dn++; } // piece attacks for (ptr = &board->piece[opp][1]; (from=*ptr) != SquareNone; ptr++) { // HACK: no king piece = board->square[from]; delta = to - from; ASSERT(delta_is_ok(delta)); if (PSEUDO_ATTACK(piece,delta)) { inc = IncNone; if (PIECE_IS_SLIDER(piece)) { // check for blockers inc = DELTA_INC_LINE(delta); ASSERT(inc!=IncNone); sq = from; do sq += inc; while (board->square[sq] == Empty); if (sq != to) continue; // blocker => next attacker } attack->ds[attack->dn] = from; attack->di[attack->dn] = -inc; // HACK attack->dn++; } } attack->ds[attack->dn] = SquareNone; attack->di[attack->dn] = IncNone; // debug ASSERT(attack_is_ok(attack)); } // piece_attack_king() bool piece_attack_king(const board_t * board, int piece, int from, int king) { const inc_t * inc_ptr; int code; const int * delta_ptr; int delta, inc; int to; int sq; ASSERT(board!=NULL); ASSERT(piece_is_ok(piece)); ASSERT(SQUARE_IS_OK(from)); ASSERT(SQUARE_IS_OK(king)); inc_ptr = PIECE_INC(piece); code = PieceCode[piece]; ASSERT(code>=0&&code<4); if (PIECE_IS_SLIDER(piece)) { for (delta_ptr = PieceDeltaDelta[code][DeltaOffset+(king-from)]; (delta=*delta_ptr) != DeltaNone; delta_ptr++) { ASSERT(delta_is_ok(delta)); inc = DeltaIncLine[DeltaOffset+delta]; ASSERT(inc!=IncNone); to = from + delta; sq = from; do { sq += inc; if (sq == to && SQUARE_IS_OK(to)) { ASSERT(DISTANCE(to,king)==1); return true; } } while (board->square[sq] == Empty); } } else { // non-slider for (delta_ptr = PieceDeltaDelta[code][DeltaOffset+(king-from)]; (delta=*delta_ptr) != DeltaNone; delta_ptr++) { ASSERT(delta_is_ok(delta)); to = from + delta; if (SQUARE_IS_OK(to)) { ASSERT(DISTANCE(to,king)==1); return true; } } } return false; } // end of attack.cpp fruit-2.1.dfsg-1.orig/src/move_evasion.h0000600000175000017500000000102510402400155017515 0ustar oliveroliver // move_evasion.h #ifndef MOVE_EVASION_H #define MOVE_EVASION_H // includes #include "attack.h" #include "board.h" #include "list.h" #include "util.h" // functions extern void gen_legal_evasions (list_t * list, const board_t * board, const attack_t * attack); extern void gen_pseudo_evasions (list_t * list, const board_t * board, const attack_t * attack); extern bool legal_evasion_exist (const board_t * board, const attack_t * attack); #endif // !defined MOVE_EVASION_H // end of move_evasion.h fruit-2.1.dfsg-1.orig/src/piece.cpp0000600000175000017500000000526610402400155016456 0ustar oliveroliver // piece.cpp // includes #include #include "colour.h" #include "piece.h" #include "util.h" // "constants" const int PawnMake[ColourNb] = { WhitePawn256, BlackPawn256 }; const int PieceFrom12[12] = { WhitePawn256, BlackPawn256, WhiteKnight256, BlackKnight256, WhiteBishop256, BlackBishop256, WhiteRook256, BlackRook256, WhiteQueen256, BlackQueen256, WhiteKing256, BlackKing256, }; static const char PieceString[12+1] = "PpNnBbRrQqKk"; const inc_t PawnMoveInc[ColourNb] = { +16, -16, }; const inc_t KnightInc[8+1] = { -33, -31, -18, -14, +14, +18, +31, +33, 0 }; const inc_t BishopInc[4+1] = { -17, -15, +15, +17, 0 }; const inc_t RookInc[4+1] = { -16, -1, +1, +16, 0 }; const inc_t QueenInc[8+1] = { -17, -16, -15, -1, +1, +15, +16, +17, 0 }; const inc_t KingInc[8+1] = { -17, -16, -15, -1, +1, +15, +16, +17, 0 }; // variables int PieceTo12[PieceNb]; int PieceOrder[PieceNb]; const inc_t * PieceInc[PieceNb]; // functions // piece_init() void piece_init() { int piece, piece_12; // PieceTo12[] for (piece = 0; piece < PieceNb; piece++) PieceTo12[piece] = -1; for (piece_12 = 0; piece_12 < 12; piece_12++) { PieceTo12[PieceFrom12[piece_12]] = piece_12; } // PieceOrder[] for (piece = 0; piece < PieceNb; piece++) PieceOrder[piece] = -1; for (piece_12 = 0; piece_12 < 12; piece_12++) { PieceOrder[PieceFrom12[piece_12]] = piece_12 >> 1; } // PieceInc[] for (piece = 0; piece < PieceNb; piece++) { PieceInc[piece] = NULL; } PieceInc[WhiteKnight256] = KnightInc; PieceInc[WhiteBishop256] = BishopInc; PieceInc[WhiteRook256] = RookInc; PieceInc[WhiteQueen256] = QueenInc; PieceInc[WhiteKing256] = KingInc; PieceInc[BlackKnight256] = KnightInc; PieceInc[BlackBishop256] = BishopInc; PieceInc[BlackRook256] = RookInc; PieceInc[BlackQueen256] = QueenInc; PieceInc[BlackKing256] = KingInc; } // piece_is_ok() bool piece_is_ok(int piece) { if (piece < 0 || piece >= PieceNb) return false; if (PieceTo12[piece] < 0) return false; return true; } // piece_from_12() int piece_from_12(int piece_12) { ASSERT(piece_12>=0&&piece_12<12); return PieceFrom12[piece_12]; } // piece_to_char() int piece_to_char(int piece) { ASSERT(piece_is_ok(piece)); return PieceString[PIECE_TO_12(piece)]; } // piece_from_char() int piece_from_char(int c) { const char *ptr; ptr = strchr(PieceString,c); if (ptr == NULL) return PieceNone256; return piece_from_12(ptr-PieceString); } // end of piece.cpp fruit-2.1.dfsg-1.orig/src/piece.h0000600000175000017500000000660510402400155016121 0ustar oliveroliver // piece.h #ifndef PIECE_H #define PIECE_H // includes #include "colour.h" #include "util.h" // constants const int WhitePawnFlag = 1 << 2; const int BlackPawnFlag = 1 << 3; const int KnightFlag = 1 << 4; const int BishopFlag = 1 << 5; const int RookFlag = 1 << 6; const int KingFlag = 1 << 7; const int PawnFlags = WhitePawnFlag | BlackPawnFlag; const int QueenFlags = BishopFlag | RookFlag; const int PieceNone64 = 0; const int WhitePawn64 = WhitePawnFlag; const int BlackPawn64 = BlackPawnFlag; const int Knight64 = KnightFlag; const int Bishop64 = BishopFlag; const int Rook64 = RookFlag; const int Queen64 = QueenFlags; const int King64 = KingFlag; const int PieceNone256 = 0; const int WhitePawn256 = WhitePawn64 | WhiteFlag; const int BlackPawn256 = BlackPawn64 | BlackFlag; const int WhiteKnight256 = Knight64 | WhiteFlag; const int BlackKnight256 = Knight64 | BlackFlag; const int WhiteBishop256 = Bishop64 | WhiteFlag; const int BlackBishop256 = Bishop64 | BlackFlag; const int WhiteRook256 = Rook64 | WhiteFlag; const int BlackRook256 = Rook64 | BlackFlag; const int WhiteQueen256 = Queen64 | WhiteFlag; const int BlackQueen256 = Queen64 | BlackFlag; const int WhiteKing256 = King64 | WhiteFlag; const int BlackKing256 = King64 | BlackFlag; const int PieceNb = 256; const int WhitePawn12 = 0; const int BlackPawn12 = 1; const int WhiteKnight12 = 2; const int BlackKnight12 = 3; const int WhiteBishop12 = 4; const int BlackBishop12 = 5; const int WhiteRook12 = 6; const int BlackRook12 = 7; const int WhiteQueen12 = 8; const int BlackQueen12 = 9; const int WhiteKing12 = 10; const int BlackKing12 = 11; // macros #define PAWN_MAKE(colour) (PawnMake[colour]) #define PAWN_OPP(pawn) ((pawn)^(WhitePawn256^BlackPawn256)) #define PIECE_COLOUR(piece) (((piece)&3)-1) #define PIECE_TYPE(piece) ((piece)&~3) #define PIECE_IS_PAWN(piece) (((piece)&PawnFlags)!=0) #define PIECE_IS_KNIGHT(piece) (((piece)&KnightFlag)!=0) #define PIECE_IS_BISHOP(piece) (((piece)&QueenFlags)==BishopFlag) #define PIECE_IS_ROOK(piece) (((piece)&QueenFlags)==RookFlag) #define PIECE_IS_QUEEN(piece) (((piece)&QueenFlags)==QueenFlags) #define PIECE_IS_KING(piece) (((piece)&KingFlag)!=0) #define PIECE_IS_SLIDER(piece) (((piece)&QueenFlags)!=0) #define PIECE_TO_12(piece) (PieceTo12[piece]) #define PIECE_ORDER(piece) (PieceOrder[piece]) #define PAWN_MOVE_INC(colour) (PawnMoveInc[colour]) #define PIECE_INC(piece) (PieceInc[piece]) // types typedef int inc_t; // "constants" extern const int PawnMake[ColourNb]; extern const int PieceFrom12[12]; extern const inc_t PawnMoveInc[ColourNb]; extern const inc_t KnightInc[8+1]; extern const inc_t BishopInc[4+1]; extern const inc_t RookInc[4+1]; extern const inc_t QueenInc[8+1]; extern const inc_t KingInc[8+1]; // variables extern int PieceTo12[PieceNb]; extern int PieceOrder[PieceNb]; extern const inc_t * PieceInc[PieceNb]; // functions extern void piece_init (); extern bool piece_is_ok (int piece); extern int piece_from_12 (int piece_12); extern int piece_to_char (int piece); extern int piece_from_char (int c); #endif // !defined PIECE_H // end of piece.h fruit-2.1.dfsg-1.orig/src/option.h0000600000175000017500000000106510402400155016337 0ustar oliveroliver // option.h #ifndef OPTION_H #define OPTION_H // includes #include "util.h" // functions extern void option_init (); extern void option_list (); extern bool option_set (const char var[], const char val[]); extern const char * option_get (const char var[]); extern bool option_get_bool (const char var[]); extern int option_get_int (const char var[]); extern const char * option_get_string (const char var[]); #endif // !defined OPTION_H // end of option.h fruit-2.1.dfsg-1.orig/src/board.h0000600000175000017500000000436510402400155016124 0ustar oliveroliver // board.h #ifndef BOARD_H #define BOARD_H // includes #include "colour.h" #include "piece.h" #include "square.h" #include "util.h" // constants const int Empty = 0; const int Edge = Knight64; // HACK: uncoloured knight const int WP = WhitePawn256; const int WN = WhiteKnight256; const int WB = WhiteBishop256; const int WR = WhiteRook256; const int WQ = WhiteQueen256; const int WK = WhiteKing256; const int BP = BlackPawn256; const int BN = BlackKnight256; const int BB = BlackBishop256; const int BR = BlackRook256; const int BQ = BlackQueen256; const int BK = BlackKing256; const int FlagsNone = 0; const int FlagsWhiteKingCastle = 1 << 0; const int FlagsWhiteQueenCastle = 1 << 1; const int FlagsBlackKingCastle = 1 << 2; const int FlagsBlackQueenCastle = 1 << 3; const int StackSize = 4096; // macros #define KING_POS(board,colour) ((board)->piece[colour][0]) // types struct board_t { int square[SquareNb]; int pos[SquareNb]; sq_t piece[ColourNb][32]; // only 17 are needed int piece_size[ColourNb]; sq_t pawn[ColourNb][16]; // only 9 are needed int pawn_size[ColourNb]; int piece_nb; int number[16]; // only 12 are needed int pawn_file[ColourNb][FileNb]; int turn; int flags; int ep_square; int ply_nb; int sp; // TODO: MOVE ME? int cap_sq; int opening; int endgame; uint64 key; uint64 pawn_key; uint64 material_key; uint64 stack[StackSize]; }; // functions extern bool board_is_ok (const board_t * board); extern void board_clear (board_t * board); extern void board_copy (board_t * dst, const board_t * src); extern void board_init_list (board_t * board); extern bool board_is_legal (const board_t * board); extern bool board_is_check (const board_t * board); extern bool board_is_mate (const board_t * board); extern bool board_is_stalemate (board_t * board); extern bool board_is_repetition (const board_t * board); extern int board_material (const board_t * board); extern int board_opening (const board_t * board); extern int board_endgame (const board_t * board); #endif // !defined BOARD_H // end of board.h fruit-2.1.dfsg-1.orig/src/book.cpp0000600000175000017500000000771410402400155016323 0ustar oliveroliver // book.cpp // includes #include #include #include #include #include "board.h" #include "book.h" #include "move.h" #include "move_gen.h" #include "util.h" // types struct entry_t { uint64 key; uint16 move; uint16 count; uint16 n; uint16 sum; }; // variables static FILE * BookFile; static int BookSize; // prototypes static int find_pos (uint64 key); static void read_entry (entry_t * entry, int n); static uint64 read_integer (FILE * file, int size); // functions // book_init() void book_init() { BookFile = NULL; BookSize = 0; } // book_open() void book_open(const char file_name[]) { ASSERT(file_name!=NULL); BookFile = fopen(file_name,"rb"); if (BookFile != NULL) { if (fseek(BookFile,0,SEEK_END) == -1) { my_fatal("book_open(): fseek(): %s\n",strerror(errno)); } BookSize = ftell(BookFile) / 16; if (BookSize == -1) my_fatal("book_open(): ftell(): %s\n",strerror(errno)); } } // book_close() void book_close() { if (BookFile != NULL && fclose(BookFile) == EOF) { my_fatal("book_close(): fclose(): %s\n",strerror(errno)); } } // book_move() int book_move(board_t * board) { int best_move; int best_score; int pos; entry_t entry[1]; int move; int score; list_t list[1]; int i; ASSERT(board!=NULL); if (BookFile != NULL && BookSize != 0) { // draw a move according to a fixed probability distribution best_move = MoveNone; best_score = 0; for (pos = find_pos(board->key); pos < BookSize; pos++) { read_entry(entry,pos); if (entry->key != board->key) break; move = entry->move; score = entry->count; // pick this move? ASSERT(score>0); best_score += score; if (my_random(best_score) < score) best_move = move; } if (best_move != MoveNone) { // convert PolyGlot move into Fruit move; TODO: handle promotes gen_legal_moves(list,board); for (i = 0; i < list->size; i++) { move = list->move[i]; if ((move & 07777) == best_move) return move; } } } return MoveNone; } // find_pos() static int find_pos(uint64 key) { int left, right, mid; entry_t entry[1]; // binary search (finds the leftmost entry) left = 0; right = BookSize-1; ASSERT(left<=right); while (left < right) { mid = (left + right) / 2; ASSERT(mid>=left&&midkey) { right = mid; } else { left = mid+1; } } ASSERT(left==right); read_entry(entry,left); return (entry->key == key) ? left : BookSize; } // read_entry() static void read_entry(entry_t * entry, int n) { ASSERT(entry!=NULL); ASSERT(n>=0&&nkey = read_integer(BookFile,8); entry->move = read_integer(BookFile,2); entry->count = read_integer(BookFile,2); entry->n = read_integer(BookFile,2); entry->sum = read_integer(BookFile,2); } // read_integer() static uint64 read_integer(FILE * file, int size) { uint64 n; int i; int b; ASSERT(file!=NULL); ASSERT(size>0&&size<=8); n = 0; for (i = 0; i < size; i++) { b = fgetc(file); if (b == EOF) { if (feof(file)) { my_fatal("read_integer(): fgetc(): EOF reached\n"); } else { // error my_fatal("read_integer(): fgetc(): %s\n",strerror(errno)); } } ASSERT(b>=0&&b<256); n = (n << 8) | b; } return n; } // end of book.cpp fruit-2.1.dfsg-1.orig/src/board.cpp0000600000175000017500000002765610402400155016467 0ustar oliveroliver // board.cpp // includes #include "attack.h" #include "board.h" #include "colour.h" #include "fen.h" #include "hash.h" #include "list.h" #include "move.h" #include "move_do.h" #include "move_evasion.h" #include "move_gen.h" #include "move_legal.h" #include "pawn.h" // TODO: bit.h #include "piece.h" #include "pst.h" #include "util.h" #include "value.h" // constants static const bool UseSlowDebug = false; // functions // board_is_ok() bool board_is_ok(const board_t * board) { int sq, piece, colour; int size, pos; if (board == NULL) return false; // optional heavy DEBUG mode if (!UseSlowDebug) return true; // squares for (sq = 0; sq < SquareNb; sq++) { piece = board->square[sq]; pos = board->pos[sq]; if (SQUARE_IS_OK(sq)) { // inside square if (piece == Empty) { if (pos != -1) return false; } else { if (!piece_is_ok(piece)) return false; if (!PIECE_IS_PAWN(piece)) { colour = PIECE_COLOUR(piece); if (pos < 0 || pos >= board->piece_size[colour]) return false; if (board->piece[colour][pos] != sq) return false; } else { // pawn if (SQUARE_IS_PROMOTE(sq)) return false; colour = PIECE_COLOUR(piece); if (pos < 0 || pos >= board->pawn_size[colour]) return false; if (board->pawn[colour][pos] != sq) return false; } } } else { // edge square if (piece != Edge) return false; if (pos != -1) return false; } } // piece lists for (colour = 0; colour < ColourNb; colour++) { // piece list size = board->piece_size[colour]; if (size < 1 || size > 16) return false; for (pos = 0; pos < size; pos++) { sq = board->piece[colour][pos]; if (!SQUARE_IS_OK(sq)) return false; if (board->pos[sq] != pos) return false; piece = board->square[sq]; if (!COLOUR_IS(piece,colour)) return false; if (pos == 0 && !PIECE_IS_KING(piece)) return false; if (pos != 0 && PIECE_IS_KING(piece)) return false; if (pos != 0 && PIECE_ORDER(piece) > PIECE_ORDER(board->square[board->piece[colour][pos-1]])) { return false; } } sq = board->piece[colour][size]; if (sq != SquareNone) return false; // pawn list size = board->pawn_size[colour]; if (size < 0 || size > 8) return false; for (pos = 0; pos < size; pos++) { sq = board->pawn[colour][pos]; if (!SQUARE_IS_OK(sq)) return false; if (SQUARE_IS_PROMOTE(sq)) return false; if (board->pos[sq] != pos) return false; piece = board->square[sq]; if (!COLOUR_IS(piece,colour)) return false; if (!PIECE_IS_PAWN(piece)) return false; } sq = board->pawn[colour][size]; if (sq != SquareNone) return false; // piece total if (board->piece_size[colour] + board->pawn_size[colour] > 16) return false; } // material if (board->piece_nb != board->piece_size[White] + board->pawn_size[White] + board->piece_size[Black] + board->pawn_size[Black]) { return false; } if (board->number[WhitePawn12] != board->pawn_size[White]) return false; if (board->number[BlackPawn12] != board->pawn_size[Black]) return false; if (board->number[WhiteKing12] != 1) return false; if (board->number[BlackKing12] != 1) return false; // misc if (!COLOUR_IS_OK(board->turn)) return false; if (board->ply_nb < 0) return false; if (board->sp < board->ply_nb) return false; if (board->cap_sq != SquareNone && !SQUARE_IS_OK(board->cap_sq)) return false; if (board->opening != board_opening(board)) return false; if (board->endgame != board_endgame(board)) return false; if (board->key != hash_key(board)) return false; if (board->pawn_key != hash_pawn_key(board)) return false; if (board->material_key != hash_material_key(board)) return false; return true; } // board_clear() void board_clear(board_t * board) { int sq, sq_64; ASSERT(board!=NULL); // edge squares for (sq = 0; sq < SquareNb; sq++) { board->square[sq] = Edge; } // empty squares for (sq_64 = 0; sq_64 < 64; sq_64++) { sq = SQUARE_FROM_64(sq_64); board->square[sq] = Empty; } // misc board->turn = ColourNone; board->flags = FlagsNone; board->ep_square = SquareNone; board->ply_nb = 0; } // board_copy() void board_copy(board_t * dst, const board_t * src) { ASSERT(dst!=NULL); ASSERT(board_is_ok(src)); *dst = *src; } // board_init_list() void board_init_list(board_t * board) { int sq_64, sq, piece; int colour, pos; int i, size; int square; int order; int file; ASSERT(board!=NULL); // init for (sq = 0; sq < SquareNb; sq++) { board->pos[sq] = -1; } board->piece_nb = 0; for (piece = 0; piece < 12; piece++) board->number[piece] = 0; // piece lists for (colour = 0; colour < ColourNb; colour++) { // piece list pos = 0; for (sq_64 = 0; sq_64 < 64; sq_64++) { sq = SQUARE_FROM_64(sq_64); piece = board->square[sq]; if (piece != Empty && !piece_is_ok(piece)) my_fatal("board_init_list(): illegal position\n"); if (COLOUR_IS(piece,colour) && !PIECE_IS_PAWN(piece)) { if (pos >= 16) my_fatal("board_init_list(): illegal position\n"); ASSERT(pos>=0&&pos<16); board->pos[sq] = pos; board->piece[colour][pos] = sq; pos++; board->piece_nb++; board->number[PIECE_TO_12(piece)]++; } } if (board->number[COLOUR_IS_WHITE(colour)?WhiteKing12:BlackKing12] != 1) my_fatal("board_init_list(): illegal position\n"); ASSERT(pos>=1&&pos<=16); board->piece[colour][pos] = SquareNone; board->piece_size[colour] = pos; // MV sort size = board->piece_size[colour]; for (i = 1; i < size; i++) { square = board->piece[colour][i]; piece = board->square[square]; order = PIECE_ORDER(piece); for (pos = i; pos > 0 && order > PIECE_ORDER(board->square[(sq=board->piece[colour][pos-1])]); pos--) { ASSERT(pos>0&&pospiece[colour][pos] = sq; ASSERT(board->pos[sq]==pos-1); board->pos[sq] = pos; } ASSERT(pos>=0&&pospiece[colour][pos] = square; ASSERT(board->pos[square]==i); board->pos[square] = pos; } // debug if (DEBUG) { for (i = 0; i < board->piece_size[colour]; i++) { sq = board->piece[colour][i]; ASSERT(board->pos[sq]==i); if (i == 0) { // king ASSERT(PIECE_IS_KING(board->square[sq])); } else { ASSERT(!PIECE_IS_KING(board->square[sq])); ASSERT(PIECE_ORDER(board->square[board->piece[colour][i]])<=PIECE_ORDER(board->square[board->piece[colour][i-1]])); } } } // pawn list for (file = 0; file < FileNb; file++) { board->pawn_file[colour][file] = 0; } pos = 0; for (sq_64 = 0; sq_64 < 64; sq_64++) { sq = SQUARE_FROM_64(sq_64); piece = board->square[sq]; if (COLOUR_IS(piece,colour) && PIECE_IS_PAWN(piece)) { if (pos >= 8 || SQUARE_IS_PROMOTE(sq)) my_fatal("board_init_list(): illegal position\n"); ASSERT(pos>=0&&pos<8); board->pos[sq] = pos; board->pawn[colour][pos] = sq; pos++; board->piece_nb++; board->number[PIECE_TO_12(piece)]++; board->pawn_file[colour][SQUARE_FILE(sq)] |= BIT(PAWN_RANK(sq,colour)); } } ASSERT(pos>=0&&pos<=8); board->pawn[colour][pos] = SquareNone; board->pawn_size[colour] = pos; if (board->piece_size[colour] + board->pawn_size[colour] > 16) my_fatal("board_init_list(): illegal position\n"); } // last square board->cap_sq = SquareNone; // PST board->opening = board_opening(board); board->endgame = board_endgame(board); // hash key for (i = 0; i < board->ply_nb; i++) board->stack[i] = 0; // HACK board->sp = board->ply_nb; board->key = hash_key(board); board->pawn_key = hash_pawn_key(board); board->material_key = hash_material_key(board); // legality if (!board_is_legal(board)) my_fatal("board_init_list(): illegal position\n"); // debug ASSERT(board_is_ok(board)); } // board_is_legal() bool board_is_legal(const board_t * board) { ASSERT(board!=NULL); return !IS_IN_CHECK(board,COLOUR_OPP(board->turn)); } // board_is_check() bool board_is_check(const board_t * board) { ASSERT(board!=NULL); return IS_IN_CHECK(board,board->turn); } // board_is_mate() bool board_is_mate(const board_t * board) { attack_t attack[1]; ASSERT(board!=NULL); attack_set(attack,board); if (!ATTACK_IN_CHECK(attack)) return false; // not in check => not mate if (legal_evasion_exist(board,attack)) return false; // legal move => not mate return true; // in check and no legal move => mate } // board_is_stalemate() bool board_is_stalemate(board_t * board) { list_t list[1]; int i, move; ASSERT(board!=NULL); // init if (IS_IN_CHECK(board,board->turn)) return false; // in check => not stalemate // move loop gen_moves(list,board); for (i = 0; i < LIST_SIZE(list); i++) { move = LIST_MOVE(list,i); if (pseudo_is_legal(move,board)) return false; // legal move => not stalemate } return true; // in check and no legal move => mate } // board_is_repetition() bool board_is_repetition(const board_t * board) { int i; ASSERT(board!=NULL); // 50-move rule if (board->ply_nb >= 100) { // potential draw if (board->ply_nb > 100) return true; ASSERT(board->ply_nb==100); return !board_is_mate(board); } // position repetition ASSERT(board->sp>=board->ply_nb); for (i = 4; i <= board->ply_nb; i += 2) { if (board->stack[board->sp-i] == board->key) return true; } return false; } // board_opening() int board_opening(const board_t * board) { int opening; int colour; const sq_t * ptr; int sq, piece; ASSERT(board!=NULL); opening = 0; for (colour = 0; colour < ColourNb; colour++) { for (ptr = &board->piece[colour][0]; (sq=*ptr) != SquareNone; ptr++) { piece = board->square[sq]; opening += PST(PIECE_TO_12(piece),SQUARE_TO_64(sq),Opening); } for (ptr = &board->pawn[colour][0]; (sq=*ptr) != SquareNone; ptr++) { piece = board->square[sq]; opening += PST(PIECE_TO_12(piece),SQUARE_TO_64(sq),Opening); } } return opening; } // board_endgame() int board_endgame(const board_t * board) { int endgame; int colour; const sq_t * ptr; int sq, piece; ASSERT(board!=NULL); endgame = 0; for (colour = 0; colour < ColourNb; colour++) { for (ptr = &board->piece[colour][0]; (sq=*ptr) != SquareNone; ptr++) { piece = board->square[sq]; endgame += PST(PIECE_TO_12(piece),SQUARE_TO_64(sq),Endgame); } for (ptr = &board->pawn[colour][0]; (sq=*ptr) != SquareNone; ptr++) { piece = board->square[sq]; endgame += PST(PIECE_TO_12(piece),SQUARE_TO_64(sq),Endgame); } } return endgame; } // end of board.cpp fruit-2.1.dfsg-1.orig/src/move_evasion.cpp0000600000175000017500000001563010402400155020057 0ustar oliveroliver // move_evasion.cpp // includes #include "attack.h" #include "board.h" #include "colour.h" #include "list.h" #include "move.h" #include "move_evasion.h" #include "move_gen.h" #include "piece.h" #include "util.h" // prototypes static bool gen_evasions (list_t * list, const board_t * board, const attack_t * attack, bool legal, bool stop); static bool add_pawn_moves (list_t * list, const board_t * board, int to, bool legal, bool stop); static bool add_pawn_captures (list_t * list, const board_t * board, int to, bool legal, bool stop); static bool add_piece_moves (list_t * list, const board_t * board, int to, bool legal, bool stop); // functions // gen_legal_evasions() void gen_legal_evasions(list_t * list, const board_t * board, const attack_t * attack) { ASSERT(list!=NULL); ASSERT(board!=NULL); ASSERT(attack!=NULL); gen_evasions(list,board,attack,true,false); // debug ASSERT(list_is_ok(list)); } // gen_pseudo_evasions() void gen_pseudo_evasions(list_t * list, const board_t * board, const attack_t * attack) { ASSERT(list!=NULL); ASSERT(board!=NULL); ASSERT(attack!=NULL); gen_evasions(list,board,attack,false,false); // debug ASSERT(list_is_ok(list)); } // legal_evasion_exist() bool legal_evasion_exist(const board_t * board, const attack_t * attack) { list_t list[1]; // dummy ASSERT(board!=NULL); ASSERT(attack!=NULL); return gen_evasions(list,board,attack,true,true); } // gen_evasions() static bool gen_evasions(list_t * list, const board_t * board, const attack_t * attack, bool legal, bool stop) { int me, opp; int opp_flag; int king; const inc_t * inc_ptr; int inc; int to; int piece; ASSERT(list!=NULL); ASSERT(board!=NULL); ASSERT(attack!=NULL); ASSERT(legal==true||legal==false); ASSERT(stop==true||stop==false); ASSERT(board_is_check(board)); ASSERT(ATTACK_IN_CHECK(attack)); // init LIST_CLEAR(list); me = board->turn; opp = COLOUR_OPP(me); opp_flag = COLOUR_FLAG(opp); king = KING_POS(board,me); for (inc_ptr = KingInc; (inc=*inc_ptr) != IncNone; inc_ptr++) { if (inc != -attack->di[0] && inc != -attack->di[1]) { // avoid escaping along a check line to = king + inc; piece = board->square[to]; if (piece == Empty || FLAG_IS(piece,opp_flag)) { if (!legal || !is_attacked(board,to,opp)) { if (stop) return true; LIST_ADD(list,MOVE_MAKE(king,to)); } } } } if (attack->dn >= 2) return false; // double check, we are done // single check ASSERT(attack->dn==1); // capture the checking piece if (add_pawn_captures(list,board,attack->ds[0],legal,stop) && stop) return true; if (add_piece_moves(list,board,attack->ds[0],legal,stop) && stop) return true; // interpose a piece inc = attack->di[0]; if (inc != IncNone) { // line for (to = king+inc; to != attack->ds[0]; to += inc) { ASSERT(SQUARE_IS_OK(to)); ASSERT(board->square[to]==Empty); if (add_pawn_moves(list,board,to,legal,stop) && stop) return true; if (add_piece_moves(list,board,to,legal,stop) && stop) return true; } } return false; } // add_pawn_moves() static bool add_pawn_moves(list_t * list, const board_t * board, int to, bool legal, bool stop) { int me; int inc; int pawn; int from; int piece; ASSERT(list!=NULL); ASSERT(board!=NULL); ASSERT(SQUARE_IS_OK(to)); ASSERT(legal==true||legal==false); ASSERT(stop==true||stop==false); ASSERT(board->square[to]==Empty); me = board->turn; inc = PAWN_MOVE_INC(me); pawn = PAWN_MAKE(me); from = to - inc; piece = board->square[from]; if (piece == pawn) { // single push if (!legal || !is_pinned(board,from,me)) { if (stop) return true; add_pawn_move(list,from,to); } } else if (piece == Empty && PAWN_RANK(to,me) == Rank4) { // double push from = to - (2*inc); if (board->square[from] == pawn) { if (!legal || !is_pinned(board,from,me)) { if (stop) return true; ASSERT(!SQUARE_IS_PROMOTE(to)); LIST_ADD(list,MOVE_MAKE(from,to)); } } } return false; } // add_pawn_captures() static bool add_pawn_captures(list_t * list, const board_t * board, int to, bool legal, bool stop) { int me; int inc; int pawn; int from; ASSERT(list!=NULL); ASSERT(board!=NULL); ASSERT(SQUARE_IS_OK(to)); ASSERT(legal==true||legal==false); ASSERT(stop==true||stop==false); ASSERT(COLOUR_IS(board->square[to],COLOUR_OPP(board->turn))); me = board->turn; inc = PAWN_MOVE_INC(me); pawn = PAWN_MAKE(me); from = to - (inc-1); if (board->square[from] == pawn) { if (!legal || !is_pinned(board,from,me)) { if (stop) return true; add_pawn_move(list,from,to); } } from = to - (inc+1); if (board->square[from] == pawn) { if (!legal || !is_pinned(board,from,me)) { if (stop) return true; add_pawn_move(list,from,to); } } if (board->ep_square != SquareNone && to == SQUARE_EP_DUAL(board->ep_square)) { ASSERT(PAWN_RANK(to,me)==Rank5); ASSERT(PIECE_IS_PAWN(board->square[to])); to = board->ep_square; ASSERT(PAWN_RANK(to,me)==Rank6); ASSERT(board->square[to]==Empty); from = to - (inc-1); if (board->square[from] == pawn) { if (!legal || !is_pinned(board,from,me)) { if (stop) return true; ASSERT(!SQUARE_IS_PROMOTE(to)); LIST_ADD(list,MOVE_MAKE_FLAGS(from,to,MoveEnPassant)); } } from = to - (inc+1); if (board->square[from] == pawn) { if (!legal || !is_pinned(board,from,me)) { if (stop) return true; ASSERT(!SQUARE_IS_PROMOTE(to)); LIST_ADD(list,MOVE_MAKE_FLAGS(from,to,MoveEnPassant)); } } } return false; } // add_piece_moves() static bool add_piece_moves(list_t * list, const board_t * board, int to, bool legal, bool stop) { int me; const sq_t * ptr; int from, piece; ASSERT(list!=NULL); ASSERT(board!=NULL); ASSERT(SQUARE_IS_OK(to)); ASSERT(legal==true||legal==false); ASSERT(stop==true||stop==false); me = board->turn; for (ptr = &board->piece[me][1]; (from=*ptr) != SquareNone; ptr++) { // HACK: no king piece = board->square[from]; if (PIECE_ATTACK(board,piece,from,to)) { if (!legal || !is_pinned(board,from,me)) { if (stop) return true; LIST_ADD(list,MOVE_MAKE(from,to)); } } } return false; } // end of move_evasion.cpp fruit-2.1.dfsg-1.orig/src/posix.h0000600000175000017500000000041010402400155016162 0ustar oliveroliver // posix.h #ifndef POSIX_H #define POSIX_H // includes #include "util.h" // functions extern bool input_available (); extern double now_real (); extern double now_cpu (); #endif // !defined POSIX_H // end of posix.h fruit-2.1.dfsg-1.orig/src/util.cpp0000600000175000017500000001155710402400155016346 0ustar oliveroliver // util.cpp // includes #include #include #include #include #include #include #include #include #include "posix.h" #include "util.h" // functions // util_init() void util_init() { setvbuf(stdin,NULL,_IONBF,0); setvbuf(stdout,NULL,_IONBF,0); // _IOLBF breaks on Windows! } // my_random_init() void my_random_init() { srand(time(NULL)); } // my_random() int my_random(int n) { double r; ASSERT(n>0); r = double(rand()) / (double(RAND_MAX) + 1.0); return int(floor(r*double(n))); } // my_atoll() sint64 my_atoll(const char string[]) { sint64 n; sscanf(string,S64_FORMAT,&n); return n; } // my_round() int my_round(double x) { return int(floor(x+0.5)); } // my_malloc() void * my_malloc(int size) { void * address; ASSERT(size>0); address = malloc(size); if (address == NULL) my_fatal("my_malloc(): malloc(): %s\n",strerror(errno)); return address; } // my_free() void my_free(void * address) { ASSERT(address!=NULL); free(address); } // my_fatal() void my_fatal(const char format[], ...) { va_list ap; ASSERT(format!=NULL); va_start(ap,format); vfprintf(stderr,format,ap); va_end(ap); exit(EXIT_FAILURE); // abort(); } // my_file_read_line() bool my_file_read_line(FILE * file, char string[], int size) { char * ptr; ASSERT(file!=NULL); ASSERT(string!=NULL); ASSERT(size>0); if (fgets(string,size,file) == NULL) { if (feof(file)) { return false; } else { // error my_fatal("my_file_read_line(): fgets(): %s\n",strerror(errno)); } } // suppress '\n' ptr = strchr(string,'\n'); if (ptr != NULL) *ptr = '\0'; return true; } // my_string_empty() bool my_string_empty(const char string[]) { return string == NULL || string[0] == '\0'; } // my_string_equal() bool my_string_equal(const char string_1[], const char string_2[]) { int c1, c2; ASSERT(string_1!=NULL); ASSERT(string_2!=NULL); while (true) { c1 = *string_1++; c2 = *string_2++; if (tolower(c1) != tolower(c2)) return false; if (c1 == '\0') return true; } return false; } // my_strdup() char * my_strdup(const char string[]) { char * address; ASSERT(string!=NULL); // strdup() is not ANSI C address = (char *) my_malloc(strlen(string)+1); strcpy(address,string); return address; } // my_string_clear() void my_string_clear(const char * * variable) { ASSERT(variable!=NULL); if (*variable != NULL) { my_free((void*)(*variable)); *variable = NULL; } } // my_string_set() void my_string_set(const char * * variable, const char string[]) { ASSERT(variable!=NULL); ASSERT(string!=NULL); if (*variable != NULL) my_free((void*)(*variable)); *variable = my_strdup(string); } // my_timer_reset() void my_timer_reset(my_timer_t * timer) { ASSERT(timer!=NULL); timer->start_real = 0.0; timer->start_cpu = 0.0; timer->elapsed_real = 0.0; timer->elapsed_cpu = 0.0; timer->running = false; } // my_timer_start() void my_timer_start(my_timer_t * timer) { ASSERT(timer!=NULL); ASSERT(timer->start_real==0.0); ASSERT(timer->start_cpu==0.0); ASSERT(!timer->running); timer->running = true; timer->start_real = now_real(); timer->start_cpu = now_cpu(); } // my_timer_stop() void my_timer_stop(my_timer_t * timer) { ASSERT(timer!=NULL); ASSERT(timer->running); timer->elapsed_real += now_real() - timer->start_real; timer->elapsed_cpu += now_cpu() - timer->start_cpu; timer->start_real = 0.0; timer->start_cpu = 0.0; timer->running = false; } // my_timer_elapsed_real() double my_timer_elapsed_real(const my_timer_t * timer) { double elapsed; ASSERT(timer!=NULL); elapsed = timer->elapsed_real; if (timer->running) elapsed += now_real() - timer->start_real; if (elapsed < 0.0) elapsed = 0.0; return elapsed; } // my_timer_elapsed_cpu() double my_timer_elapsed_cpu(const my_timer_t * timer) { double elapsed; ASSERT(timer!=NULL); elapsed = timer->elapsed_cpu; if (timer->running) elapsed += now_cpu() - timer->start_cpu; if (elapsed < 0.0) elapsed = 0.0; return elapsed; } // my_timer_cpu_usage() double my_timer_cpu_usage(const my_timer_t * timer) { double real, cpu; double usage; ASSERT(timer!=NULL); real = my_timer_elapsed_real(timer); cpu = my_timer_elapsed_cpu(timer); if (real <= 0.0 || cpu <= 0.0) return 0.0; usage = cpu / real; if (usage >= 1.0) usage = 1.0; return usage; } // end of util.cpp fruit-2.1.dfsg-1.orig/src/pst.cpp0000600000175000017500000002075010402400155016172 0ustar oliveroliver // pst.cpp // includes #include "option.h" #include "piece.h" #include "pst.h" #include "util.h" // macros #define P(piece_12,square_64,stage) (Pst[(piece_12)][(square_64)][(stage)]) // constants static const int A1=000, B1=001, C1=002, D1=003, E1=004, F1=005, G1=006, H1=007; static const int A2=010, B2=011, C2=012, D2=013, E2=014, F2=015, G2=016, H2=017; static const int A3=020, B3=021, C3=022, D3=023, E3=024, F3=025, G3=026, H3=027; static const int A4=030, B4=031, C4=032, D4=033, E4=034, F4=035, G4=036, H4=037; static const int A5=040, B5=041, C5=042, D5=043, E5=044, F5=045, G5=046, H5=047; static const int A6=050, B6=051, C6=052, D6=053, E6=054, F6=055, G6=056, H6=057; static const int A7=060, B7=061, C7=062, D7=063, E7=064, F7=065, G7=066, H7=067; static const int A8=070, B8=071, C8=072, D8=073, E8=074, F8=075, G8=076, H8=077; // constants and variables static /* const */ int PieceActivityWeight = 256; // 100% static /* const */ int KingSafetyWeight = 256; // 100% static /* const */ int PawnStructureWeight = 256; // 100% static const int PawnFileOpening = 5; static const int KnightCentreOpening = 5; static const int KnightCentreEndgame = 5; static const int KnightRankOpening = 5; static const int KnightBackRankOpening = 0; static const int KnightTrapped = 100; static const int BishopCentreOpening = 2; static const int BishopCentreEndgame = 3; static const int BishopBackRankOpening = 10; static const int BishopDiagonalOpening = 4; static const int RookFileOpening = 3; static const int QueenCentreOpening = 0; static const int QueenCentreEndgame = 4; static const int QueenBackRankOpening = 5; static const int KingCentreEndgame = 12; static const int KingFileOpening = 10; static const int KingRankOpening = 10; // "constants" static const int PawnFile[8] = { -3, -1, +0, +1, +1, +0, -1, -3, }; static const int KnightLine[8] = { -4, -2, +0, +1, +1, +0, -2, -4, }; static const int KnightRank[8] = { -2, -1, +0, +1, +2, +3, +2, +1, }; static const int BishopLine[8] = { -3, -1, +0, +1, +1, +0, -1, -3, }; static const int RookFile[8] = { -2, -1, +0, +1, +1, +0, -1, -2, }; static const int QueenLine[8] = { -3, -1, +0, +1, +1, +0, -1, -3, }; static const int KingLine[8] = { -3, -1, +0, +1, +1, +0, -1, -3, }; static const int KingFile[8] = { +3, +4, +2, +0, +0, +2, +4, +3, }; static const int KingRank[8] = { +1, +0, -2, -3, -4, -5, -6, -7, }; // variables sint16 Pst[12][64][StageNb]; // prototypes static int square_make (int file, int rank); static int square_file (int square); static int square_rank (int square); static int square_opp (int square); // functions // pst_init() void pst_init() { int i; int piece, sq, stage; // UCI options PieceActivityWeight = (option_get_int("Piece Activity") * 256 + 50) / 100; KingSafetyWeight = (option_get_int("King Safety") * 256 + 50) / 100; PawnStructureWeight = (option_get_int("Pawn Structure") * 256 + 50) / 100; // init for (piece = 0; piece < 12; piece++) { for (sq = 0; sq < 64; sq++) { for (stage = 0; stage < StageNb; stage++) { P(piece,sq,stage) = 0; } } } // pawns piece = WhitePawn12; // file for (sq = 0; sq < 64; sq++) { P(piece,sq,Opening) += PawnFile[square_file(sq)] * PawnFileOpening; } // centre control P(piece,D3,Opening) += 10; P(piece,E3,Opening) += 10; P(piece,D4,Opening) += 20; P(piece,E4,Opening) += 20; P(piece,D5,Opening) += 10; P(piece,E5,Opening) += 10; // weight for (sq = 0; sq < 64; sq++) { P(piece,sq,Opening) = (P(piece,sq,Opening) * PawnStructureWeight) / 256; P(piece,sq,Endgame) = (P(piece,sq,Endgame) * PawnStructureWeight) / 256; } // knights piece = WhiteKnight12; // centre for (sq = 0; sq < 64; sq++) { P(piece,sq,Opening) += KnightLine[square_file(sq)] * KnightCentreOpening; P(piece,sq,Opening) += KnightLine[square_rank(sq)] * KnightCentreOpening; P(piece,sq,Endgame) += KnightLine[square_file(sq)] * KnightCentreEndgame; P(piece,sq,Endgame) += KnightLine[square_rank(sq)] * KnightCentreEndgame; } // rank for (sq = 0; sq < 64; sq++) { P(piece,sq,Opening) += KnightRank[square_rank(sq)] * KnightRankOpening; } // back rank for (sq = A1; sq <= H1; sq++) { // HACK: only first rank P(piece,sq,Opening) -= KnightBackRankOpening; } // "trapped" P(piece,A8,Opening) -= KnightTrapped; P(piece,H8,Opening) -= KnightTrapped; // weight for (sq = 0; sq < 64; sq++) { P(piece,sq,Opening) = (P(piece,sq,Opening) * PieceActivityWeight) / 256; P(piece,sq,Endgame) = (P(piece,sq,Endgame) * PieceActivityWeight) / 256; } // bishops piece = WhiteBishop12; // centre for (sq = 0; sq < 64; sq++) { P(piece,sq,Opening) += BishopLine[square_file(sq)] * BishopCentreOpening; P(piece,sq,Opening) += BishopLine[square_rank(sq)] * BishopCentreOpening; P(piece,sq,Endgame) += BishopLine[square_file(sq)] * BishopCentreEndgame; P(piece,sq,Endgame) += BishopLine[square_rank(sq)] * BishopCentreEndgame; } // back rank for (sq = A1; sq <= H1; sq++) { // HACK: only first rank P(piece,sq,Opening) -= BishopBackRankOpening; } // main diagonals for (i = 0; i < 8; i++) { sq = square_make(i,i); P(piece,sq,Opening) += BishopDiagonalOpening; P(piece,square_opp(sq),Opening) += BishopDiagonalOpening; } // weight for (sq = 0; sq < 64; sq++) { P(piece,sq,Opening) = (P(piece,sq,Opening) * PieceActivityWeight) / 256; P(piece,sq,Endgame) = (P(piece,sq,Endgame) * PieceActivityWeight) / 256; } // rooks piece = WhiteRook12; // file for (sq = 0; sq < 64; sq++) { P(piece,sq,Opening) += RookFile[square_file(sq)] * RookFileOpening; } // weight for (sq = 0; sq < 64; sq++) { P(piece,sq,Opening) = (P(piece,sq,Opening) * PieceActivityWeight) / 256; P(piece,sq,Endgame) = (P(piece,sq,Endgame) * PieceActivityWeight) / 256; } // queens piece = WhiteQueen12; // centre for (sq = 0; sq < 64; sq++) { P(piece,sq,Opening) += QueenLine[square_file(sq)] * QueenCentreOpening; P(piece,sq,Opening) += QueenLine[square_rank(sq)] * QueenCentreOpening; P(piece,sq,Endgame) += QueenLine[square_file(sq)] * QueenCentreEndgame; P(piece,sq,Endgame) += QueenLine[square_rank(sq)] * QueenCentreEndgame; } // back rank for (sq = A1; sq <= H1; sq++) { // HACK: only first rank P(piece,sq,Opening) -= QueenBackRankOpening; } // weight for (sq = 0; sq < 64; sq++) { P(piece,sq,Opening) = (P(piece,sq,Opening) * PieceActivityWeight) / 256; P(piece,sq,Endgame) = (P(piece,sq,Endgame) * PieceActivityWeight) / 256; } // kings piece = WhiteKing12; // centre for (sq = 0; sq < 64; sq++) { P(piece,sq,Endgame) += KingLine[square_file(sq)] * KingCentreEndgame; P(piece,sq,Endgame) += KingLine[square_rank(sq)] * KingCentreEndgame; } // file for (sq = 0; sq < 64; sq++) { P(piece,sq,Opening) += KingFile[square_file(sq)] * KingFileOpening; } // rank for (sq = 0; sq < 64; sq++) { P(piece,sq,Opening) += KingRank[square_rank(sq)] * KingRankOpening; } // weight for (sq = 0; sq < 64; sq++) { P(piece,sq,Opening) = (P(piece,sq,Opening) * KingSafetyWeight) / 256; P(piece,sq,Endgame) = (P(piece,sq,Endgame) * PieceActivityWeight) / 256; } // symmetry copy for black for (piece = 0; piece < 12; piece += 2) { // HACK for (sq = 0; sq < 64; sq++) { for (stage = 0; stage < StageNb; stage++) { P(piece+1,sq,stage) = -P(piece,square_opp(sq),stage); // HACK } } } } // square_make() static int square_make(int file, int rank) { ASSERT(file>=0&&file<8); ASSERT(rank>=0&&rank<8); return (rank << 3) | file; } // square_file() static int square_file(int square) { ASSERT(square>=0&&square<64); return square & 7; } // square_rank() static int square_rank(int square) { ASSERT(square>=0&&square<64); return square >> 3; } // square_opp() static int square_opp(int square) { ASSERT(square>=0&&square<64); return square ^ 070; } // end of pst.cpp fruit-2.1.dfsg-1.orig/book_small.bin0000600000175000017500000172726010402400155016720 0ustar oliveroliverHutP#Z6( cJ1"?yK ΩP*9Na-)ym@W ( l!;gݐ#Ї a$跷[,G%{-& .f (Yv.f (Yj.f (Y (5!L:r \65&76R7}[U[;Tf`:zj;Tf`:zt <:!=h,=ry ?I" Bg]? jBGD GG!G LM,ڒ LM# cN[=PK?yJ RD1X(r7j^ܔYrp ^ܔYrp_0vuC _0vuC b'g⎟Dg⎟g⎟jh>K ahj*䤨qeV s;x$ujoA jzBh {#cS|Igwnո$3t<ո$3 *`9> ciM!BlOhi "Tn jcJ cJj cJH g0Roɑ(, ‚DKKqS)-KqS)sKqS) KqS) iBg $w>)DPs1>m EdzZާnV@>'V@ V@ +zO1R+zO1+zO1#jV T  xW$ u0M_N5u. 5s jבwjבwkL<.}O,Dd O,DdRs}4Us}4R$ѯ1tN1,Dhe8[C $ &H"wz}' ,n. (Җtg p+Yp+U_JXJ}KW_JXJ} $2"SZ ,cp7Yg@|2g/Kl8sv DCӝ+TU0a,5 g_>TcT\ {Z&/a[m# vnO R+OR R+O :m.,ckB~/LĆ̍ /LĆ̍/LĆ̍s@bl ]xr iz#1> R<"ݻQ&$,cĹ&= ,H&= &=+餜v2[8$4?vA`X{ $A}c{!A|RFQf A|RFQf B)Z DPsp DBZGcm?[J0u M H"= PhV"EPXjQ~ $T?ВdXiM_ \^װ%)i[^װ%)i`/ 4u&sb;v b;vb;vg↑hM@>iH1jr2f j3/V l^1Rm)(n}xk] *ynL zG  zG  %ؙ 7%7%!7% f 2^r2z/y -Fz/y SSj S>S iS \YKȽ萾a  t \S)5D)5DˑˑdˑS.1 k4-k4m؏ Ŋm ŊmDC\>r'};&xa&}#tҢcaV& 3 + Qìd pW 2P6>(bB(bB>һ͘]oKY5Aq? Lp s3slDAⰽbpscxP 97< -6<YG/b~: #3b$Iwh iPm s1c\QY c\QYh $ H e}C GPPٞ (3#f C7R}<ٔr7ï[ LZ0##f'.{k8+Pq3)D8IF>ӮA o{vBuL8 -@ClCtXCtBDaβDbn3 EwFaĖedL)NSM:Rg%.O{WFlAVҭ|jVҭ|WRFf^# WRFf^#6WRFf^# WRFf^#tWRFf^#X1 Z34FY \< \< hVhV$l/hbmr?5|qg2s gnsC43sC4wevĜAz7~C z7~}97=-1 Ł- ؛oZg\yQ_\7_\YgStZ͞KC> > , j ж/ж ж6CtR #R se{ jfʾB{'O _jdsv<:Fqְxix4)h;_  nѥOU yD'[JnXT= 5)NrO##ϰ\[ +|~R[ +|~R[ƴ1& WD}AǻʪCegX ͠,o<ބ>8 F+>T ݲH>kxDs@kxDj&kxD kxD JR. aQ UN:tN:Y0"h: ?du!`D:" T? \K+tNi L H[{ H[{>ϥ ϥz    -g2C  fy  ` \ `> }^5S[AT.rpTN `% HG*ho~X'Ys'Y #u $`O'isr[)YgI)YgI)k n )k n i) ,73O ( ,73Ot ,73OY-k4]5 @S6!s]X>8h $8h 8jTO 9y= i:ɪr mq ]Frob IvzMR ,IL CJNLd9{M!}\NaϹ P- Q<RQ2_SER(TKfWBRX&:|) iX&:|)>^%;p`Gv] #`~Kf?a2hRlInpP c muIot n n!d<naOoiXta tQ{lve]v8t> xBY~h |9!| jua?P`;<^/;<^/aDu , aDu aDu aDu aDu iaDu aDu aDu aSc1a pIfS:#6=ϸ#7 U0sAZ<R ԼMw- vN}.aV nS+j3i.!{ru !$˖/[ ;Um |<[4jL4>glUK;) _<YtD? sk3z+ ,F XdLtv=`YNėgS únKɿ0[o,:ŋ_@,J 3M1D5Ѳ" H2E ဖG HՖDN,HՖDHՖDQ 5N5 5R~?Sf4~|T>^L Y6oDR”l ($cQK (/:mYP>k bdwC@!a^f;_XuqW! lY Wc Wc /!_wY qU) qU] "c Mb_= _=RB6?RB6?YٹW"v/"v"aR+kɩˮ.jR2*_m4*'M27Q*O 7Q*O81~ :Axd:s*e&:s*e :s*e?hևP?_oChdCh ChDFOJPGZFvIו eMy1L"vP!RQQ*aT| aQTjQXWYQXWjQܸ6/ $ T=CR[Fv>_k hP_k hPaRфXbc+*I $iM[O0sLH"˭| ּp.sI' R-5leqש'3;& er#{*cA&c' NO[IMNO[INO[INO[IsS$pY pVHQg[ơQ Q6 4}ɾh}ɾSu0r-UxK> UxK#4Gc @ ;Lm;dƋ s )(Ct-G Ƶ4$ #]GT7Q_;]ݴ=B {iLp x M)M)&:YQ^ 7d V9鯄@ ? o3qEq F ݈w ) *^ "o d o d r c?w z{ 3J:3J:  R  Lwo %ws C}'1{]>̬?LN̬?LN["&Zm>%X/&y &0U> T*\Ŭ*f03w,V* c.W| ,2i۷+ z:#PF+:V'D<>W ;=ڙhV|@`[JBք%E! E! mFY1F'"HXM$:KMvL-λLߘqj #MQSMQSOmpnO l̖ QR9Ry S>R`3 Ui $Uޜ uAV!KV1gZ eW!\m)SY`#/][uy16\~\oHn^+ s_Via+;Oa%S bl}^zb`is0= 3jSnX+A \oSoSr{riͤ+5tpC uA7"j z1`R{l>|{ $|c/}(Z:}p}pK|{G>Iƾ] [UB Uk< EgJ}>E u:Ah\ m"H[SS`c[ۃ[;3 srl Ejaz_ \̈t@h bn`R F`by.Oٳj.Oٳ mwZZA "cc$>-N] i] : `[ bfufC|N fC|~^Ī a8j8j,|3 \ ,|3v?R5!wt_r ڨ n\Z G[KƋRkpWR*pWN }F7dPZ[(i ^R8{I*g}\Ncϕt6Y *rS EU d\4 %*{'c?>? ͖?c8yJ $R& -ԇ-"S@B"S@K"S@D#K`7 )ΉQ_0"3:3%3%5n:5n: 6?]P@>A 2Bgo G:#p"tIM=0)7jNlO!OuQ tEQ\RZյI\P3k][NB^CHKC^CHKC_,Y$ 6_U]at' ab i abjdo81d dpd#dRdi/6j-f̴8D-l*1l;,l*1l;)l*1l;or2t"oi w7D|5Wth;E Y;;35p $ ]Fo w &,>ȋ X ,>ȋ Z U %  AFB%bU|Hڸ? ڸ?/ {u \릸6*e"t*e" 3h"8ق MLSeJ&~D (#) #d{G ]T"3hk   y]()/x"/xK/xJאZJאn1;{%1l.>V6/\ >{-U-N|ʇ 3%rnQ|$ǚ. j *_2n!Y #PW bY^ (<S#X Q2ԅo՞}4 bE܈% f al ٧N ?$ 3 ڞ] ^fPv+n<߉E~>2?7xRao R0R0XC w sL ,-RjJЌj³ڈNS(S(S(kS(eN $N<LN<PN<ʻ艀 mbUΤ=|< iV vw.owXTX#[ VSǾH~ +! Zo\%ǁu ǁu 'z~v)'z~OU &8.: ( XR58ݣ ScC  u#u  u#u    -Rj0t?R2KA[gܟ5 s O 2{nT >4!Ҕ{Y2#2c%/ަ ,'XR(AݦQ*})ZP *})Z,wq)@:k/gҐ>319G 9G ;Y=!Ǣ>t.@GVh A< Bxό׮ 1 -0=C  0tb# b|r6ejo rQv" 30E 0Edrh8 Ie7~7~N_ߺ>+CZKjGA,_ ʁ ̐nQK# - i -M , % pL % pZ _.8 W0/~i> XHF   O=?h] O͡b0 Ru U{q"U U{q"D& U{q"Q ^m of=rR `Xz)a c߭\(0L fd3 f1B= i|~ i|~ jbs:) mq>GX n4eW pS"h pS"h p϶ q$gP ! rO֫ u, w `Z#] wc1Yy x\p¶t }qCK :D C/: -9f  3O„j " L 6,Yө P b . 1 s j 5@g DH#_ : L< R =A Xb  0q4  =ZW*S {U)[ 4qs  +   ;2 |z; ȈI  ȬV͗BX V  'A4x M_v 2+?N Pf  XuT  fA c ؎¤#\ Ƣ%ZDa o atD o at  ޤޑ ; Aƅ "] ׷> V> v& ! v&  9% ? ,. ?j XZK o1  n - Aw c p/@  xl;  xl; Fږ(L hL~7 #ՍC )^/uD  }n3 m  ɤ  ɤ Ͷ> Ͷt Ͷ , ,J "tMcwq \ *v  ,M4 -i|H/'@ " 0<R 2aeha 7E '1O_ 9|>L $ 9|>L> :iM :iM =xR U AlZ[ He+ I xWs LBWȤ OlT Qۻ?8 RN WxvpN [x  \ QC \e&Sp ]# c@g5I  eFvt&_ f4 h( ,+ h( h( iV:*Σj nVn(% oX  oXj q]w=0e  r8 v 3 h zC:v zGI za^S zD))[ `d8 | mMKs )CY 6 gٮy \ i] " qBq C Rʣ%  2d  һ9 jj j ; {x  * Y> ]z̩ m Ðs  }|K }| N{G  |) [ 6VH ! ug8 j hpW_ .V _N-  #5^C (/ML u~ $ [R* b ܁T ,' ܁T ܁Ti kS[ 5:U n 5:U \ 5:U ^ bF Фu ׻ \ ׻ , s+C :~R :~ \kl Y " N3&$ ea 、\k ]3ė h2C "s] "s] XH] c ^e 6(+ա*P OL xe6&  /t틩| )\*t c ӽ߼P /F+ sX sX P  5v BIt ( \W  ntYa  #  c Bׅ *  ]dNb ' ' a Azy:i0N f4N ԗ Po4  Po4  O r (1K{' )ED)Q )byy  +^)t +jw 8Dԝ+ , 8Dԝ+ 8Dԝ+ ( 8Dԝ+ 9XڵuN :޹Ӽt >+ E N c HޛX ( HޛX  Lp NNۏ0 Oc g Rs͛$$ SlwBf U, Zg܀g Zg܀g [s$& ]7^`N aflr,OD bj$ b b , hKEW6: hKEW6  oj ߔ p(ƾ sbp0 sbp0 v,ﰙ  y>  |3@d> ~yt  9x Uك"k # F;!j E}  o ޯz [ `'Wv @-j( @- , IӦ^  tb Jڑs QvݠGt W7z d &$Wt Y M d' AOoj u׋ u׋ Lb2 VLԠ ` h6C ½l8v P/< + 5J  Զ~ ́#<Y ́#< ́#<  ́#< ͞RٛC λbl K 䜧  p!-= ۶Dfhs H 7 xD'x ! ݒ0N\ - = 0 U L S  ]   /SgG + oy c Z3  躧lf  躧lf  %n$J [] + R H  v)%(: 2 r ( gi7&> C ҉ a Br 6 K " 8쌯 ŖȜ @N  ĝ I,Ѥf "9+<\P #%^{ %] '  &$rN &$r 'e7{ +/hD i -.j -. 62} 7X> t 80) 8@Lo :H =rE ?.;[EN A# f'L F9&  IΤ IΤ IΤK Iּv QX = R2GO> RW,  UTTUsb UTTUs UTTUs] UTTUs ^Z1P< `]FOW{ kGT@@ $ k{c[ kSO  msw oʅ  pueUk pbQR qFKB:  q, =R s rs/6> uT.  uk < vK}:  w)k wd')FR wfMs5 yYKlY yHظ= \ ~L.  ~b}: ~b}9 f'Q $ y  y sڭf q;$ b o@G $ G9  z֜5 VTs UX s H$K6a H$K6 v|E v|E Bk_E Z  # ws qj l \ls  8s " j "o1K `:_ , WZS <}+L Gj# IgK R B$ ӵ6v  _' u a [ //*zQ ZZ -c$ %@l %@lD Q1ϋ Pil\  C =F 0 U z>f  !L , ܛܜ|` l^U l^@ l^L$ l^ l^ l^ l^] 8)8 H cٔ ۺ`U !e@t lr V  :{h> 쮢Ca  a ΋ Fq< $ T" \ /dR YA9/9 u 鎶 H  ?Ij I^ g| E+gt E+g  E+g  E+gb g's  g's C tW 2C s Ň c 䅶N 5AK `m:?j К/^ К/^ g էNh u#R $ Y0 xTW=  xTW=b xTW= y-xv #n1 #n . #n , gu~! sK$ %"0<j %"0<> 'sy ,nj/ /|&Q 0s,Wz j 3B}V0 5vq5? ;_ dZ;XMscȅ [F,$}Re: qCc l_r1|1#ƈ'OrXP )PtO)Pt[,q :0 R3a8;3a8:3RY3R'3R3R3R3R3w~3HLj?3HL>3HL 3ƻK93:G?=ImSAsAc B0Y^G2SI:HiLeLKx+GSN{)ZZO\a]R[Xs% R[Xs%Y-R[Xs% *RܘCWpD,RZ^q:k [uܤN^ K-{ ^ K-{^ K-{bݵkFe&B~Q ,g-Y,XU gj~z am-mAm-mAo'Z  Go'Z tqY[s؆K v2D>xu2"/9yed {Q|y G; ~| -~|~| f_ /dR:y% x:FLM ٤Ȼ&sJxs\>/Jxs\L~j, l @* $_3e$yn%EX˩F  Cr $+^`2[c2ʖc2ʖ v#Yv#v#v#L]̅j St* St*dlJ80ւF|X`KRb-$ $A<jbj rL;W9 _ςS c϶qo N>SZo #:ִ1{C@/\Uܯ4?]>Zby¾ Gs Mxo \񜐶*UKt% \#S-L#S- J:I:v &)<ҸD^XHe ,^XHejmr8;"ں}l;"ں} ۦj > RkIT;HRʆ7MSӭx Lӭx TRNA%J)F^.qH udd cJQ $\ $%@V' kN*c+,7m/YoYi1֟(i 17%)M7)ݎuP 9 K 9q:b!t?9HU lDfѕ EP"JHz-.p -ILj4J&vJ& J[9U7hRY1th\>ر\i`'S ]0"odva8ua֋|$q a֋|$qjfS1ɴDfi^Do Ӣ u.Gx8xESquә' % 4oş%j ^ُ$:# ^ͦ pC\w$UNe Xθ F hJ $t{h9)8=9)8= | JF_)r@ .z4x aŲ5 Ų5 gdH4aO1`F}b O1`F}b>zL/ ̭2{ݔ>ЇV? ˮ#'D[GX'&DߴL2:> 2:>b $EX-"PMDy14jcDZ  $ݗvYqa YqZJ,ר_Jۈ oo=P./?7ݦ9?7ݦ?7ݦ $?7ݦ ?0gpDY ?0gpDY@K A~޹ Fvђ-\Fvђ-+Fvђ-RFvђ-Fvђ- Fvђ-Hq. (JpYN J /OMGE;EKOʂTS55i UqUKVA/wW7 YTv6hYTv6s\.f2d]/AsbxGbxbxUbxebxbx bxbxb[cb`#БjsayN_j jsayN_ , k| XElq_Ց/* 2l"~JrHpSv7nBv:J 3weo)&weo)weo) weo)c yÞO; 9|Ơ+ ~j[{veZbn:"{nM^hS],;0>YBkR{v ! FB [D~NVl10 ']D>[ !`h{0:s jDlI- ,* a0Yi #'Pc'>([ v[[h&r \[h&r 6JC b@ fTXQk%Pc†ggbQ}j ɸW s3W yw¥ aB阎 |hz9ĒEL'ҶK׌]H%uDָ00  ٵ|wK1@ٵ|wK1ٵ|wK1ٵ|wK1dhU! ߜ4(Ĵ@P{=LN$ xiZM> ds ,)4"EJ]5S 솑 $` bs7BTBTBTRBTBTD R # ,$@[$!cOV (AcOV _?KLP^b Lʹ ocȖ  ";!| QIǯ}4Ks_`  Ks_`  N^ [ƌns2W޶Djc,jcL{skpR{k?5>$ p8 , p8 $".GN{#¢ Y )8}8 (-Lh-Lh5484rU7A&>7A&> 8<L]=zf-j@A$@վ ( A$@վA$@վDWڡDWڡGv6 ,HW鷟CNkkWR01 WR01CWݩ#WݩD WݩQWݩR].K_y. uƦX,ƦX,hDRD9^Af*#k*#VqWUWʮ ΑI|Џ_Zy 5yu7QH H H H _~_| ]`ojsf8 fpvZh ű  Rfb"=ZU d4Ny(4N< sZ \̫꾩Sd!J qx' c/}  &~N: "4 Ϥ*j9GY>cj]2KJ0 B$9:A'ީ 4 T7O\ "$޹ "$޹ "$޹ \+HOt+~ .XX8R18 ;m 3]3]3]R3]4 Y4)79&"?TdHDB8DB8B8H'=qAF LIAʐ]Lh};mLTA[QiH TM 6i TΎ UJ9C Wu"UX$' |ZJ&j\\P1)]l ^J"c7$sd=nid鈴Af>?. hR!m3w>$mB$ mB$ow tpz,˔p{y` pǶ9驽[s£W xFy>~c)6!>iSt'=>޸&cIS[t>> t>j2 i2jۿۿN<` aN<` sOPijf&Emgf&Em <f&Em ,f&Em ~ MƬVNƬVR5oj?ь< g%(*cLvϼsq"ȡ? N? :~T]dzIL>IL ILsPȊ#B ;GP,ހK f4=,/רlSG:EWXD{ez%0դn9ZNe(}Q Rv:`R7O. ;Od~o4|O b7>r  6 ,% 6 68N_ o6~B \{|WMGSX[M#ic QYZ+Q   SG iD SG i"DK~$)er'No{g(_G'2 -/=]c*1KZr"8_:iaX);_K >Ele=EKsbTtH#J޹C H&CPK O =yCR S SS<0BHY-)8Y}3Y-)8Y} Y(0>\S\V ]da.1!UI gkk,k lcM1S rtBa 3v+dzp/]|nG'Lu \~`x^$]unD4U>D$OnhY'C0o1~Pj i XL[i  Plv (v'2RT Q!K aKJ;UQJ;UF< ?, $ֺF D M Th|;  $򅌗C Yqz~ >KaZ ޚ^ Cޚ^ a4򊃟1? #I C%vIZXmcLZXmcSZXmc ϼ@QrѰ)TѰ)TQQ#ks ӠgH f {|fXQ$fXQ߃zrh#( {, 4>vmQRMCYC:YoN WVZ h:'j | ˄ ,(;,(;QzkQ ]fVfOL;5 :zl abc2sCK)>Z)>Z)>ZP"!l$P ]}~S %T> -M* k< RR. 1ke43l~ %=X\=8ML S} ]xK7VbD0#h=pY N+X#*9FK&Koa&Ko+\=qX`,}vj/2q i8=3P:8 -;1<1.Y;h@=c2c=L6O=Uy` ==>xWN?#BORW%Dɍ'4$GwH&AF_f>IDh%z JD*BMD 3P![S@+mS@+ S@+S@+ V$7 VkS8 X6 Z-2:]SHXGJ^_bH` _R13D_R13D_rq `0-`ܩ_4;fL-W-.itCsjX9slN mH6q3mH6q$n-<)Nb9;n# pM>sU \x$.3Zz[Ӌ@|V~Y/!vR'''L\ ihpk_# 13B $9yH9շ1ӐHq]$3?Ck&PyG  eWpDbu.! thь$j{"$Dd. Nܡ }R5}}Q4Ѩ *R!aH(\RHh`e \TKO ~{!~{!a-~{!Ry~{!CX: lBM- "ȃ>L9F^DǷfsjLɅ6) a ̩SޯA ̰ qgsSҴP|KnG$ {hJ(g ~bpz1vmBsXok sɹ>cGcG%CH  ^&Z[׈'4 " x Pq1z)Ww-󑫨 ,"f^˖˖xMxMRb߹4J o sBCB @M@M ]7Y  ]7Y $|%ңRR7O ea<5KN:haS5 5 ##H$1#H$1$YA[d.$YA[d.'7# '7# ()?LO=-˃>OǛJ WdWd9Wd Wd WdXt4 c aAk3% aAk3%bo9lgdd4h2;:lYi ,i (Ji ii;n 8lTZ[XQmbF n~!xobj3 Upu rj !yUDyOn4}m }m]~X#/Kk!RkdY;ƴtG| h}   ,|=s 9|އ GԂjC>S%bX1QN&bX1Qxc9|>u&f? j0fR8ڝΙ|꫾|{% !Q}o }o UԐ:R6 lY  L nj _"yz,ZjDؔ#ӒNKƃpNKƃpNҀ{4 354 35 8r X+` Xt  X ( >h fQN8i` r Y Q`'w{*Z;8؟ [>I:" >Sd" A6}J B; B; bF*/wAI%j:Jbi NNӋ ZO2<0 S|yTw(,RU.k,U;_ |Yһ%Ŏ]ly&_@m|R nbSn<ˆ diL i$j}F&slPSr_1$ ft 'tt ' (u͓Ez] |Til }Ahns_*QznG0<RMx1+=Ҍ.%t!]#A18~Qv 1fj E r7c~ | +GkPu-QtI_tI_tI__MFSI-IZ&IMw sD¤rSMϤ4zb 39)4ǚx>T&tL` ۰v= Oojs  Oojcs   &QtL68j濄U G \4w}\ EM)+oW" sW"되na (ehj1p] ^}e  |DC DC 4 "qg  YQt'2P` 6r2w Wu2ƅ;It;;'t;'sTUY)!WkyABvZe !D{"l:N<"!#~~Z $BQ%PBc %Z_W+u b/R6K 0Dd0DdM2=n=2=n=2=n= 3ul= ]6['τ7/ΐ7Xv|>8w@E9Y @D"2 Bº #FЈtJ-_ ;tOFvB Or\ "XLhYnvsa+za+a+a+Ra+c C":nr t2\zn b{ A{&g | _f4 c5`?* Jf:vB2[b@ q} fԑ 3} fԑjÀ3YS3uwsf_jxU1VsbW {wnAL~F 5KWn5*4WkjLmM$G9"i!vc d/ov]/urU*K /urU*/urU*°ޞ ՒZ6 +g)xF(KYǾFɖ4J s"G!GxS: 6DfԪ&+*]*]Í/܋- =LD> :YN.j T/%>T/%>6Eɇj4u|7vH0h|jEU xa< ,@#']@iM&>[̴A;i/wKƛ#eqs8Xss8Xt؞ e؞ ؞k4h* - F f/ Ĵ !5H,  `R  `$ &1sۃ {(,ל)l#=K*26![Q.dֵ 0=0Ejh1:26{D3۶B3#ʫ5XӇ5XӇ5XӇ5XӇQ5XӇ8鰘x9Mڎ9͚==>~Z=2R-=mCD=mCDR=mCDU=mCD5Eaz sFUN fH+6oR&H+6oIKhS?OhMtRO 9P?J RePdS\PzSFhMVC~zNVM̛*YkAtRZ <Ó]]pK \d1"Sd ;m;Rd ;m;ad ;m;f6\ڢ&ia<NoKte+*Suāp Ruāp z/fz/ B{)%.:zF onQh (onQhonQhonQh ,Ѹ TLŰ#Ks' ,Kӝ\S>!V+9 zດe zດe s80id15=j 15=|QxEj:ʃ[9 9Mؙt |j c0uRR~50a>&GƄ ,ǔbob Nϑ{ C6 XFSl2#Э&;<[t̥Kc11 -bbSP bbSpnpLpnp% ia3 FF44]M%}R ٟvz}NRn' ޝUtvçM* çM*  5  5 #VxvJ(/2H ʰ+ʰ+ʰ+R+h_nS\k +gTˏU w #>ˏU w ŋFPL% ɣy$7  q.m ?@i@?@iK&?@i ?@i 5} M> $!^A)'BR'B`'J @R(ZݾD(Zݾ(i)D} #)+v),OAa|-OH". (w. /"Lo 2y:95.ћhn9d$=}? ~k? ~k @{@>EOEFpIMvsIMvtKcլ]K-NWY5)WӮܨ s[ŲF\~r\~r_^VS c\&ߚ]je -th+ h+  iE_v`>iu$Kk2|G li%, l%bDn^rp*3Z˹3F9Nޢ 8 V,T( /:{L Uj4_Pcdk-( nn+C)DEMx 7o! 9( #/ҿhP#Or>#Ors([9F0S-{ 0:~)t7 `8mF~>Beʋ iBeʋ C%vHAw JıWsD|K?@! 1N^erX (Sb SßB L SßB  Vfե x WG2{WBh5YG])U\(ú \V7k]q1fhm ?0hpTx"Z x@$ xuX  xuX xyxN|lnd}y~,)Kst F9w)s 9w) =k3.j čXX  čXXt  čXX $ U|wm\i ,\Lg6vg6 `+*t(qp8>]ÏIP iթ(6 թ(6g9 g9j$](C(L$](C(+$](C(ۥQ{ i{ (G~Ew`ɞCD\ "/QT&SL - C7\?'F^@ jӏvzZj` m,wRbs\>pT q)W e (q%Z4Ȝzg+ lC2h慠1wC9\>&@Sd \ @Sd 1C01AD#tDv~qF~qR c]܌ ,H~3)PH~3) ZJo=d6 l 3N i e4 ˳mks[lI iFFb$^/|⛟ JL $  $$ v2W%T7|-N>:S Od .<,l B@!K@RE+BxE-o,;F{˝RL4s+q$pFN*ޒF5 NfvNfQSʶ [Q3"(sS :S :La;N? aa;N?a;N? erI (nRo- ~frVw?"rb[O) tL"(vunde"vvKb$*v򂟶t xljzΠW>{i},IZX{ }@0Qy #~&?8bM~&?8:hgYȳ%( ,ȳ%( .&4mQY Ǿ&> þ{ aDkDV*!1;ǮudI dJQ 98}pfଅv ^W'tJFX*S JFX*LJFX*G  -rJt;xrn aGwLd x] @ $M_RNP'vF9?^h  !v ,:QJ ( #3jȘ ?w Ș ?w ,Q-s,Q-Q-Yk"l #DZ,\ YILe YILet׆ f\81 ۟5.߃re t8%hJ; >~d~뢴Ul ×HF^iY *Q qQ ZRk Yz&rgէ % ,8ʺj 5p  RL#q aZa ep̠>`Q!?7 d6nZ"]Z"Z":Y1; "!FR~y"KڌS' &k)b1*oޭ -19D$19D#68j8N88R?Gf+U{LCP^V:Me NN:  QK\DQP<SJV73ViXsErR*>Z})q Z})qZq[ Zq[ \^,a *aRb`6ߢfVQCRfc}v)fc}vhWjI2>jI2 kb" m9޻ + s/2{㈇,  g U-Kp>QXp3"Uic"UicF8q{9qZEء"SD-"SD-jDc N#6[mL ,Cxv')O>T+Ajd qƥb=Qw%őQ|մkv&?[m&?ŧg7 Aߛ -7Cţ'wrR+=KFC+=KFFCvAtSd ځGځG ?VƛOHH0 ֈ` tԉFԉFZ٩s})o r hmۗ>#k;/ ,|u:g0Ak>m  m  JYt7 ,*D tʈfʈf*OvmUd mUdCOof  $:Oof  Oof j Oof  (Oof sOof   Ԩ=s'qX3Y|R \Иyfzx|~3 k5N a@2 [7M<{C K aK  0C.  V* : V*  ʷ ʴfU ʴfUyaKjRBJnkSޘe#2^ #2^%o6t%o6K &:ͫ((B'.; /@KG1Y" #1Y"18t1O -t3\]g`ڕZ 6(A@s8Zk$;8ssA3j& #Du$K cFn&K(e%KLKra ^KraLP@MSy`WFYjZېŽ[["瓯 -]T| X%5'D[w\FP]eũa _ e_c> sc q| g4'xP;gͩ/9 iGl[rjockt$ԋqL w 1{t 1{ aa6 VTl}!OC aJ&<9$T;N9$T;jt Kն >bl}- 4_/*sK( aL%E(g? g? g?q(K \%q(K ,#q(K "q(K q(K !I OCR>OCR =IS Ե5& n |JV>@'%\ؠa&ا/v/5b G$GHM(;Z$Uj$R+q]AwNEiͼ40c*~q iHBtF sUtFkЩ93V W7  bG ů6>C S҉tw xͯl>=̴q}TQ W8H $-CKk%HUzOHH+:S1p]Do #3% _ 318j ;]-qD \>/\ʲ>t)ú@ũncdBطuY$Dͨ ^EʺT>ILuMg\l R Q('|Q)4{$Ze˅ $\L _" _!MY cg{kd<<g6Yg.H (iMjj/L^j/j/qKaudx(!Ժa 7T0O ,kݐ9RE= RE=RP/QpS. \xBsZ N3Vm \%_<]kE8 c f.]? f.] f.]  f.]R 61FXi_л#dI?Fx["iYls]·PwW~PwW~ 6K֐x S0O5Dd&~=9TQŶӳ*ǃeGǃeGfoN:ΰ䄽 cBqy$ta b@(0vD;b@(0v_b@(0vwN6?R6?R lڛL@ bc@ bX&RD5U:Բ +BgЋ1 BgЋ1t-B:v@o 6y\ r& {[ejJ 'QN 'QNmftu -u -ib/!= \:` |- e |-Y   +\dj ,,{ 0= 2oΧ 3q\] 80E c ;[+Ns% ;[+N ;|_j>4 ;|_j > F} > Fk A[, BGs R)L UC Y& \_1go  a  a : a‹zz) a‹zz a‹zzd a‹zz* e= Xks i ,7G l m_sf  nsx> q`j}v rG |  upEbl l wY+ $ y> +2 015̳  Q ~ ` 3/ct M M !L  aq` aq` $ aq` , ; {˹. &NtE &N2 &N u ./ X 3us GvG& ,87L# jư ha \ hah ha  l2< 2? ~}. l0  *f  ^h>R@ ^h>U Ŕ Z = keo tB'8A ͚}_> ԭND ݼ$;t >~m & g9 Q:f D  ]5t + [ C?ݾAt ^([B ^([K >-Rq! ]c)-#! j !n!n!n!n!Bar!J )o!:f!V;t! m i!'RiVCt !^@$!!%2R!}sΪͲ !@ k !@ !@ s!R+o` !#$x!$8#.!'frj!-a@bT !-a@bT !-ωNY!-ω!.D@!.XN (!/۩S !1E!1EF!4@DJ!:)e!:)ej!:)e (!;pS !AUoަE!Hi3> $!NFc!OͨM4!UQ%"ϓO !V$|ʸ (!XQʿ. ![[9C;kj!\}Y̸!^8 !^8 !bõS!hJP e!kdN!nmӤ4!nmӤ4 *!qB>)!rz;s!w !y|n a!y .uybQ !y  !yHBq!{h)f$!|%YS!|%YS !|%YS (!|/W6!Ld_R!U7J!hEs!hE|!6Y!hJM !6鋵 !8ek !>O !D5R!v)|! Xw (!tWB0( !ndQ,!ju!` !`R!`!ә!Vzj>!.Ɩ !c-!0^_ >!Nã>!߼[!|<>!|<>!k!$B5!$B {!$Bk!$B !i9w!Ē)'p<!e&#!3Su*!.3Y!f:>v!t4ob!斵oR!6J>!튛Ro!Pm !Ԣ` !,=ǒh$ !/nq!/nR!/n! ‹C ! ‹Ct"Wos"RYt "}6"o({K"Z " a#fY $" 3d"fH]ҡB"fH]ҡ"9j"9 "85>"# z["$wrO \"%]"5?pm"5ĎBP"7q3"7|K p4 3"7L"8>2g9"9AJU ":KO";HG`"?cqOM "@c?)Z0D"B<v"CBK!R "D#Zш"E $"E "FeV""HP0Z"P/`"P?! 8;"Up^3,"V@g "X܌[g"\HϺH"]=["^Lɸ "_<}&k9"aY="b Wqt"bd@H\"bd@H\"cAx;T"iZqP"j&Ϋj "m~L&"sJNtN"t2%"uxa"{i+J "|VN "|廰c"~DS3"~DS|"c|"^ "k"AC"A"AR"ɔW;>"εWQ"#NbQ"Θ"&)VU"qbKڿ"@ K"{":1 ":1 a":1R":1 g":٨k "T״|"T״"xp"xp ";aM"R "RR1"R"R "R" 29>"s)JbQ"ˁ"ˁ"^/\=+ "=[h'" <K"ӌ ":"ɑ> "Q"CP<":*:"bu>"bu i "thI"AD"DlY"؂0,Y"i?i"i?i>"wTa" e "7Z[k`"p!"BT{ 5"7"*>"7"* "c'4 "JzqLJb"ɇF#@Z{L #4ID# nf#l1 (#O_uR#ɲ\?v#?b ##.@/m#YMR% , #YMR% #YMR%#7*Y#!3!' "##HmؒK ##Hmؒ##]#(gz#(gzQ#(gzY#+1O&|#+1O&#+̔ #/\&&HN#0B #8, #8#4|#9c(r #:p#<5!y(#Bҫ #Bҫ C#D6GG6 #Fe{>#HdxO#J0<]~O#J1q /#L$t|#L$tj#N Chz[#O/ #O8NWDF j#T?7ɻN #\Cxn #\Cxn ( #\Cxn ,#]M=~#a;sP#cgV<#fQ05#hݠ" #l- q !#uJ#wh@ #xs?#xsK#z̞#z9,#}vy#$r%&R %#C # B# Э#hk8 #pY_#Zd1 #Zd1#Zd1]#ŷ,ۧ:#v~e#h#*Zu5 #ϰn\#7 $#w_ׁ# Y#APZf*#Mh0# -K #gz##Zg.+#Zg.R#Zg.#Zg. #Zg.#wTk1#wTk1#L`^#W' h#) a#&D#} Z#k;#\[}>a#@(#ŸfcQ#1 #XoT#ίvxvl>#HGޕ ,#HGޕ#u.Sp#u.SG#u.S*#u.S%#xϞb_ #*8tg#, M*N#$S'D#vϛ#UV#tY7 #]J/xut#ǘ>$#ǘ #ǘs#AJUL #AJUL #AJUL #ʧ#! ^#E#N‰#Jj$0$ 7 $ z: $ DR$ ü\H: $w[$Dom $`$$ʜ$΄̝ $RJ% ($YDJ $G_$G_$/%,d $ADb t t$C7@2R$Ex>R$E>FS$Iu丼E$J&wq ,$Kr 9C$Ow*~o s$Roh֬$STx^ a$YԱe$]$]$_>H $`Bjj'$`MvDt$aeD$ae$g$R$i $i$n fd $nC,i *s $p[0m a$p`NF-$stĄ c$wRIy$x%:$y $TTR${. $Ԧ$($Ԧ$5.$7J t$j?@$ab$#[ZY$ůW$Bj$Bv $az 2$az $J-$Q ":Ǎ $D@ (6$D@ a"$D@$/B#&v$rM[0%$A!LM 3$-v}jN7$m/3$m/3* $MG[#$MG[$$V=S& $V=S&$­-} $#]] a $Y,Bݭ s$u df>$N}/$̹$^U1 $_r *$x$aVz +$X_'n$݉O$](f #%)E%m[ %%m[ %m[%[  %ڌ,O% F%/b%D %g;%uU%"p%#FZ:w #%'.yW%)bc Y%*;F]%,$H"j%,$H"j1%,$H"j%-|^i %/4 >e%0O Ũ ! %0O Ũ ,%15s %2S/c ,%3&xd%3X.bi:%4L1%6%ٍX.v %X%U25?4%%IR l%/*c%j B%WZoN%C;*%2? %;E R"%;E  %;E d %ˁ /C1%f%j]% i+%Mԥ ,%_.d&!nf5 g&!nf5 & "5C m&;3&/7u +&#ht&-r&fM_eh&(H&(H &(H& I&&H), c&'rԌ&(ͯ=L$ &)(=cq'&)(=cq&*+h!&-| &/$Nط&/V%} &1={'J&:_w&;Ƽ&=}Y&=ێ>]X *&A! &H6&p # &I, &M8$>&Qtt&Qt &Qt&Q|&#&R%Ӄބ&Sŏds&Y9*&YC܅5>&[c q&\zؖDh -&]F*#L&_tJ[&bgAE &da]% &e_Q&hȘ * &iT![&k ј&l,I &n,U c&qeK7/[&r? c&t9# &v,pV&zAhk c&zAhk #&z5&}wa>U|&~8|U0&JԸe[?&(&(&(U&&1D[&&1DZ&&1D&'[ c&'/&ĈR&st&Z<&0|( &g8ާV&#G&TaX&3M &e|hH&e|hH&c%,&Doy;&Gq&!8&t~ġ&t~ġ]&S{Ҏ&wC|&ǩdXk_&x~}K&ۡj# \&ۡj# &ۡj#|&ۡj# &3.`? &3.`? &X4&}[L_>&د &ٙbk &ܼ;^E_>&JKP&>С &>С$&s&^GVR& Dh|&|m\&(9:D&vY* l'ZfH s'; 'E 'aZ.O'aZ.O]'aZ.OZ'aZ.O#'aZ.O'aZ.O'&O!' K'EV q'EV ,>'EV 'EV']yU']y''Z@''%o'%T , ''J] _''J] ''V^[') ! '+:b :R'+:b :',TkwQa 1E',TkwQa ',''/QUiD'87-x ': ';I6QO ';I6QOh'?i!tP'@Kۃ"'Ez~7 c'G*ߢ&'HQ` 'Kޅ]'Mjm|(>'Nԛ% 'TEGŐ'TEGŐ3'TEGŐ ''TEGŐ 'TEGŐt'TEGŐs'T̛3v $'X\)# '^ +yx'b:'cBb,'dm#fg'k'l}'nZM.>"'u#CNf'x@rS 'zYzʟW'~"餖'~jj'kU-f ('R3dq'7 ' _B, -'*6j'fp[>''em8hJ'em8h 'em8h'em8h'.c -'aߨj'Zpt0>'IR'> '&и'C/ j'8 ^'RBr)c['$g a'Xj 2'8%m_v.'9B '~n'pRCa'ĵ@ 'ĵ@ #'s@ 'Ƣ/d1K'̽0R~ ,'>2p2'Y'-p19'Ͽ˒'PGk1R'"x '@v '+^R'ؠQj'F6i ,'F6is'.roU'F=5D'!'ҍtB':ȳ =';զ $'Bv(o7 x(rx?1(tQ D(u꺀e(}\4;JN(~Fz"(~^(טBte({UQ~~ (Q-g(X(5 (ݷ$t i(qhe(ӂ( (I(pQ(p(K3;(4`K(Z~ (4Z a( XpB(t*Jk(t*Jt(ug (}\(Eަ\ (T.A(iY*Oh (K g($L (ztCV 9(|O3M(3'Hw (~#(˽==/&(. X (. X (fzq (׏}(00jQ(غ Uin(.90((Fj?K(ެ׈ (ެ׈(ެ׈( b(mvQֽ ,N(mvQֽj)(mvQֽ (uM(ﻸr (;: $>({6W (PEp1L(IP(?)(/b)y^K )y^) z 2+4L) F ) F e )+W )Mq )#B)E )E )Jv)~1$)'- $)!F})"r>)"rs)"þr )%`=zh1)/i  )/i |)0>X2} )7CGJzk)8Z滚ڑ ):41y>):41y ):41y):Y%)<"=l)=: )A3Cw$ )Be%1j l)Em3)M8w )Pr T)U 0Z=)W.}R)Xз@x)ZQ8$q)ZQ8$q )^׹A5)^6i6)`B,wS )d# )e Uh)e Uh )fB)g3 ,)gE))hO}j)hO} ()kDNK&)n6#U)o>,*)q(h>)q(h>)q;55d)t"ؕ)tmcK )t/yO )uu]*KyR)uu]*Ky)yL戻)yz;^ g)|_gS+v)~ uH);N)-^>)>q; )>q; )+z i)}R)Yc a)F޽):*K)q˹ )DI )/Xf>)+13Y)y )읹 e)R5hB )4Z8)4Z8)Wt-HQ)aФf)o6*d)o6*)h)GW )5Pzc)nO`;N )nO`;)Csx)Csx ) ($9) ($ U)V` )(B)"5xW)QMg)S^v)?3K)ͮKN )@W+ HTN)%KUF8)zB").{dd)C):% Q^)ӄ?k)َF)'"|)-KL)–"$)–"D )lNˆ~)Tub)?+KS ) y56 ))f)jQ )*ʢL*X *S/$s*zWw ,*) IA* eLs6Xo* wA + v* Dj* (ͨS*jX*g՛S*ގi%*M&*ZuN,[ *Wk*i JM*i J* sצj*$G0İ *%7 *&T.hB*'BM*)EnC7N *+>X (*/R$` *2IUZ *6ZYe*7գ2t*7Ȇ0K*8#`\*;Z2TV.*;Z2TV #*<]aU*@ *@|b& j*D/Rs*FOt|*|*FpQ#A*Fhu7 p*G=Vip ,*Kg*M'RXKs*M'RXK *M'RXK|*PΌ*-+*לN * V+t:* V+t *t{To*2NMI *2t*K]* voB e*+*+ϴR*L#* > *vp[6>*o.*;W,u*eE*:u ***7*nKz*nKz*z4oiY** * \ *qӕPQ *X=eIt *E> *$* *aVD*aVDZ*@VR*koh> a*}~>*P ?+"UtV!+ڋ+ڋ+ #+*3+ Q8{R+5mi +2+j36+G9+aB + mVbpY + mVbpY + u +!!8 SvD+*^ Ă+*Q ++7 d+-$^ +-PFL+6f4R+8#R1 "+:tch+/=+xטG +xטG+xטG+}ħ+~1=+n+RD #+0#Pd+&=+@d+b~0| +zXtt+v xD+~F (+UD Y+%y +yo+dnpX+VfPK+F_RWI +z8> + hN+U3ݭU +]  c +oj+bq+Es+!OO~R n+KƧA+KƧA+z7 ,+z7 +{F_}Y+˺[-[+ڄ};yh+ڄ};ys+jcR+OT}6t+Ӫ={+gI9 +@^+ +ڼ7p+ݭbt w+ߺh\4+'U+iov+c2vN +zQ+~+ `I +]@u+=)#+_:%P+M +M +$r*x ,z#|,t4 3I, 89( U, 89(>, ^g>S, kY, ?>,?- ,a| ,,4u,>2 a, BH@ 5, _D,,"&ϴA:,%"vN,&=8 ,&U G,(.WfN,)* _,-GbZ,-GbZ,-GbZ$,. f j,1T ,7ϐu l,: x,<ݎ$QL,<1Xz`S!,= R,?ǗB+K,B' v ,B<\Q,Cȩ6;#,G~L,H.o,J ֠L,L#n,NxX#,Noc,P={W ,UoUmS ,UoUm,VĒ,VĒ,Wʵ*K,X؋uue,ZD $,\LL~ |,]Ɯ:B,^+Nr1 c,`[O,bDφ,g} >,iؒ\,iؒ\RF,iؒ\%,je Av5,m%,oq2'<|,q_ǥc,q_ǥc,q=R,tQ<$,tQ<Q,tQ< ,tQ<K,|~2Bo i,}+ʎ>,qSfԱ,vlgo ,vlgo g ,{&ZS,0\~ %,Y+B ,, h ,BrQR , d,1$: j,1$:,kop (,&ޖB ,q,VQ| 0,VQ| ,VQ|v,Z[/,:X ,t ,!M,WKz,aX,WMK,Oܷ,I*R,uu,b` ,b` ,d ,dh ,B ,;,n?, Z, +,bE & ,mSpL,7 ^,,tb\,S3y=,Z ,~{5W q,^5 ,^5 n,ЬS,ѳx넎6,ҝ/f^,^S #Z,^S7,u` 1,֋qm}v,œ 3 r ,`x,(i|,@;a),T,늒X ,؆P,Lwl,Lwl, i zd,oS ,oS>,͕F&t,Me ,Me],f5.2,»[ ,»[ , K%, K% ,2e-]d-50-f!\-=:O0 -- r%\,* - r%\,*-n7 -n7-.hQ-.hQ-.hQ-9WR-S➸-@߼ -+0F)-c--#p-)-BoK-" A+: -"c -*CNr-,P/$-/bf-0UV(P>-1t!|j -5N-8aJ>M-8aJ ?-8aJ -:jiyZ-=l=W->=-a-@eu]"-@;o:-Ej D-HiA[!-I3"cR-Idq[-MR -M-N._ -Q}ד-SvѷD -U; -WO-Xn =-[%F-[2jA*J-] S -^z2y-b`/)-c?U{-eFt-fp=k-f]%s-f܊v-g --i? -j׺2a Y-j׺2a Q-j׺2a L-k :-l].-lpY-w;1-w;-y|ȶV )-z m_d-{ꏏ` |-|1{Q(s-|E_@qW-|E_@q -}⳥ls -1: -1:-q|-iYN,|-u!),Ln-{|qj-`#gYK-.Sr`-l' -C];K -37jq,-37jq,j-s s-a'q%-jZ-Juf -2PR-( b-5JB| 2-xvU{ -b R-I-2+ $- -%-%-F7 |-F7>'->ik-2(*v--2(* t-d+=-d+-f u-@-@-ƭl:K-(7v-݇#s@-݇#-'Υ-џj -m(9u- -ާlA -6N>-ߥR8 -.& Ev-z>06 - # -کq- U - U-2uk-LhR--tJ-ʾZQ.G .ɅK.a b{.vGot.lTP.lTP.V .fCdb.i!_W[ . CN. ) . ű) \.2n.S0.S0.yv |.=b.uw .uw .uw e.uw .uw i.)q6.) {= .) {=.*|,!w .8g}%!,Z.:ed.<఼ #.C6Xk$.CЯ!J.CрQ ".F'Ս&.Hȫc.Li.N*th .Q`LhoK .TDO c.V%{.V`j.ZAl V_ .]Fb>._I 8]._g^3ݖ.ch%*7.d^A30.e~kp".fYX.g; ,.iڪΩ l.j): .kwSR .m#.n!w3U.oH(4.p/V7ő.p/V7ő.pJ[.t{L᾽.z$ 2X .z}ϮR.|8 ^.}/+.}/+.}/+ i.~ %.~zqh.Hf.>H$.d!Q.CR?W.5]F .5]F .2.1݊.D.I#I: (.I#I:.QY.f 2.tS .t.t].C Y .C .oV.6UC.z$&b.z$& g.--.VW.~k.Ąi .jA;9>.͔hٗ.͔hٗd.͔hٗ.  .AQK.ZQ.ՄtqS .V .uaFK(.+ńˌ.ژ[ .ژ[ .68[P .zR@Bz.݀n .GEN .k . Q}.f%.b&Sa.b&S.Ё*l>.Kg}6s /s/e l/mMQ=/Nus/ /3NL/_:x /42~/42~/?@ i/&@zdV'/~X /&.>P/&]e#7 -/*1cSR/+8Z/-Ban//հ /3C:Z/4 ߸/>e8Z/AP:/ES2!J /E >/F.i|/F^3 /FOБ/I8 /L /Mb v \/MP߀.9vC/PPZ /PPZ /Q˔}=U/X>5[/XWgS/^LnJ/a/iT /jaS/jkgos /jkgosN/nv~/qr&[ /r/u\]/u/vVa ./|E y/YZDgU/ /Gk܅ /01v/!j j/?A:/`Y3u /A# '/A# /A#t/~/k~HW/Cm`l/g-h&d/1i/ ozD #/J:</HFt[/7;8Ť>/xE}/xE}t /xE}s/'ţ /i#I/|My/C L/xجV/ٶ9/oŒET/͹8/]SvN/]SvNj/˅BQ /= /= /=t/΢եO i/.YA/ҼA (/K /̧> /TFkS/TFk /TFk/H*Ym /:5h/:5s/፮6,///L`i /mYq?j/(hW//m /.;0znS/f4'/f4'/2% h/2j0ˋ%0X0_m 0 @0 F/50 F/50  0=Tѱ 0 96t0 96 0ֈbC; 0o^0o^0T>0mg ,0M.000.}r0/Z01/Q05FZ 07ҡnQ09aޯ (0:N,0=3}vs 0?bѻBm0?&Y0@j:/4Q0A+4wm0Aky2J30In7W1S 0Iv0N{.{(0N{.{0O-L<0P@ǩ 0QET.S0TVb^U0TVb^0TVb^0Tns{0W]?0XEƣf0[uO) 0d&#v0d0e]fY0gv"v0hozR0hD"py 0my&DN0pk%*A0u~>D0v+z ,0z tmi0~>M0Bo@@fVt0Q rT0yrh 0+ SaI0_* u0U[ 0n0.iϣ0a`/ ^0240yc 0eҞ0eҞKb0eҞR0gD m0sO 0*^f0J )0iUC0])r%0 ˇ?B0 ˇ?B0DpmOb0K00;I= 00;I=s 0$ "0<2j 0i{^0t0>0>0HvM (05CS0ĥe, 0ݛpk0ݛpkR0˚ozxRt0ȉR~0͏Q0͏Q 0ϡ#`]N0ƈ̮5D0ҧTo"+ <0?F505890{#w 0O 0yy4c~0q&m0SQ0 0] 0~y v0kZ 0(E8C0W$B0\wuP 0dݮ (0mY!+.s0zN0XB 0$1]R1!1! 1SI, 1bϽ1uڊHd1h %s10gj-1 d1kށ!1K^ 1 ^. 1W 5z1%E1&5S;1'kib1(OV$ 13[e2N 14X0N18bh19?19lG1=R:1=s7ÕR91=s7Õ1BzbhQyK1Dz[1EKS1L J1N=mR.1Pk  1P& ?1P& ?1Qqq1dp1dk ]v1ijE>1kUwDi1pz 4K 1rއf1~F 81~F 1_2=>1Аr16Œ3R1B1k a1,C 1 I/J1ݫt1ZjR1F Vt1F V 1X<1.c1'Q 1CS t1*) g1?~ 1?~1at,s 1MLˀ1N 1F]1C8ꎖ N 1{v-2t1B[R12>u2TK 12>u2TK12>u2TK1K)v1ʠ >1ʠ $1R鎜bZ1҅zk1 1H  1a11)k>gD1٥"v -1KcR 1[1 1֓1pN1T^) 1Pl:7:1Pl:7 n1&~4 1 ͻk2WL2>3 2>3Q2(G w21d %26 d2 j%A[+2G#v2_r2f%2&* 2"`!õ 2#ƈdx i2$?{iCh2%/8*f2'*52'*52'*52(bScS2*srv2-#'2-#K2-#d2-#2-#2-#2.ݩc121>kt023* 24+25EDq 25Dm28H~2==o s2==o|2==o 2?OKP *2A"Nhx+2A"Nhx2Bo6l2DLcd2Fi N2Gs%s2Gs%t2HY~V,2MK32N4FD2Szmޝ42Z%b.>I2Z%b. 2Z%b.2[id@]} :2[id@]}>2[4q2\I=2]=vR"x2_ZY 2_~Ygwv2cU)` 2eܖc.2f&A@ .2j #2mlۋF12nhpG"2n2A2qQv2r89l2t=bLS #2|a2N)2T}uL2/h׳2`2ZUt2})2})D2ծ2- 2@z2zd2H>E 2џyqY2Is9 $2Rڿj26CbR2ʆ͋*2 1 c2~Ҡ 2՘;"^4 26\n>2.~*d2322%@&a2,-l i2)r2XNK2y3Ck2š|lfN2qH2Lp9] (22Lp9]j)2Lp9] 2I . 27o|2HM$N2#$J2R$2ϯOp z2eH2YgG 2! 8dQ2#cU4 $2#cU4h2ᇧSr2ᇧSL2ᇧSZ2)2%+[t2Whst2Whs 2_3D 2_3D a2^e[>R2Bpd$25Ijj 25Ijj25Ijj2ŪS D2T$.!AL2=;/ 22ȔO=2+| o2+|>24sMG 2I04 2 O 3gzs 3_s|3e\ 3e\3 uX 3'H3[5S3r . 3q28Jh:3w3rPX 3}-jc3}-jc3# 3#aJ!3)u#^}A i3+{-i3+{-i3,8$3-4q{Vs3-4q{Vt32Jj 33* #34;37*Ї - 3:qm3;Ib1R3<~9I(, -3<~9I(, e3<~9I(, 3<~9I(, 3=oij 3>Z$ 3C0,(D3C0,(3GfKe3H>3I\5'i5 3PK=:>3Q XR53Vt% 3XS)'Y c3[M 3\%vV3\%vO 3e\ 3e\3e^x3j/!zj3q 43q 43r4f 3ut3v@ + 3yh3yh3yh3{f3~HE30 (3B"B3|`34D3 ( 3!>3! 3Oaj 393Igq3> $3mn 3L iY3)S3\Z# 3Z[3ibiR30nק3+ 3IeR3Ie36G %353EA!3XB 3XB3yj3y e3s&'2S 3XL 3n30pAN3J(+3J(+3h_ 3N3˝ 3sr锳13S3;V 3>a3wFP 3{L[3rƇtg9>3 G-_]3@1 3@1 3ҪF"L3ҪF" 3ҪF"3z3#9 3ݪ9G3ޘ\3*jsX3_), 3S3A3{S7H3*m+{3ˠ3kVk3(Υ3C\i3AY3Pe.K4nSlQ4B%d a4ik^e ,4?4fFWJ4(? 2t4 ?.uC&4 ?.uCZ4 H4KM4A4KM44\4nݜ4CI4Wqh 4ڮՔ4ڮՔQ4ڮՔ4ڮՔ4>º4h 5eK4B\ #4ZJ~4ZJ~4S;I 4S;I4e Y 4#Ì4#w_ .4&r=4(ʙFqk$4(xRR4,X< 4.& "47%m1347%m1,47%m1"47%m1]47%m1a47_d}4:O:Lxs4=D3xn4>0wv4BJD4B4DVu 4E@C]4Ho 4J9G,*D4Mv,4RӨ4T t@_4U4-U4b-!4> (4 ]4D6jp ,4vt=e4 tγ4` (4q 4x>YZ 49 Y,4C]f2,4m`qd4=PS4Yɞ4`WY\4lEf4͒䔄B4͒䔄4͒䔄4vIx 4Mm̈́4g04k?64eo 4 4 ֐ 4̽ 4t44 44 4u 4Ο74k 4Ο_4 LgTR4}BP c 4ӎbٹNR4t 74t +4t (4t 4t 4ؽQ4j *~ 4.@D 4'liR4m.j4m. (4m.4m. 4:4}[J 4霭 4W a4!8m4 46L)48 45v< ,4qpd 44*aU 4w 4li4] LTV4ݲ',a G4ݲ',a4ݲ',a> 5"5GީP5Gީ53Q (5@SS5V=5=h^,>5=h^,5 #44F56 X5p^?5\Iy$K5oƒ 5~95~95#p 5%#8| 5% 5( @ 5)aN)5)(c 5,B!L65,Z5ɋ51S: S51S: Z57r>58^:59伧 v5=FPr L5>,F; 5?:-45?S=n \5Bc(o5Cl|M 5D= 5D.D5H\ B (5IF 25M ,!5NIW$5NIW$Y5Oo:pT)5Oo:pT5Oo:pT5Oo:pT5PL0G 5PL0GR5SR0s 5Y;5Z/J5]"%UO5]"%UO5bCa 5e,_vq m5kh9  5kh95vnx J5y> 5{~÷|^ $5~&[}s5ik5E-: *5gy5= 5-ܘ5@WM i 5@WM5@WMj5@WM a5/5sNOKy5sNOK ,$5sNOK ( 5sNOK5sNOK 5Sm. 5L5ΞZ 5* 5~?5= a 56r5 qF5JhV5&*5rf5T/{ 5'b 5tJ9B59ြc65j؅75ȹ5k5ʄɹ}5geZ5ltho5ltho|5Y!S5γy`wd5;Q@N5;Q@NU5{5ֲ]Y5L7\:[5-ql5 `n d5vSKs \5ߧC֐!5Sx 54c 5cx)5o5"W 5$j!ޯ5" Te 5 ykG5 X~ :5X 5X (5o$5PA5&p6)EUN6Qd| y{6n #) 6YM k6:$_>6IX6 K``#6 Q6RbN6&AKl6)a96*R6.+6/K돃NR61 l5.v66>6;GuDR?L6qsx # 6D+6H.UO-6M֔DB 6MHv= 6Q^Ȋh6QZse4t 6QZse46VSbxwG <6_V*~6c6eP \ 6vI`6z߃1; 6zvdIt6&pS16&p6&pa6&pd6_/7Z 6^ձu6R $6ԣ` 6WS@S{6_`6<= S6GntĬ6ύ瓱6>6ad 6]196(Z6"3ar j6/3 $$6/3 e6/3 6:06]$nv 6~3 \6~36~~\R6oTi6$۠jt6~V٣ 6qHgj}C6Z 6 o86 o862h6 ZF 36_:|6=cQ6P1U 6P1U 6P1U6bP-6bP 6´NNN6[ā K6;]|68K6 KcJ 6n36Ȋ3 6ȏCPp6ȕ8[)6̀ٺY6̀ٺY6Ʃ;wW \6S>I)6N^L-[ 6 * U6+R6K"yP6׊Do_ m6ۚ gR6ۚ gR6ݳRf6^TN6;QC c65eك[6shw96}Pp 6}Pp6LW g"6fvk6fv c6fv (67_z6ע 6ע \6S/6  37 i7 i g 7wIL 7~YPob 7 Yh7 79o7@ht 7bu N7eR7µd{j76>s( a7.M7"KL7 (yf7 (yf7tO' 7@`n ;7hVX7 G7",a&+7#6h 7%"V\r)7%##t@7%:]7%:]7&݄|7+U:* c7-{R~ 7/='?x473}zvt76* c,77a7<.τR7<.τL7<.τQ7<;ܧkG 7=z8 c7G u 7H%At7I A7I AR7I A7I A7Mxj,L7^єIx 7g [7h‹V6N?7h‹V6R7n{> 7n{ 7s: 7ta6j#7ta6 ,7utǩR7wYE3 7x&xZu7x&xZu7y`ނo I7~]*7tO7~]*7t-7~]*7t],7~]*7t7~]*7t7~]*7tU7?bD 7,Ck7{L][ g 7d-<7bʾ& 7zui?> 7m"5 \7IA 7udͯH7c 7c 7Z87a.:k7B7Ֆ ,7 !t 7g7g7g7gR7Ycp e 7Ycp7S7'Y@7m e7)1>7hY7E,47j (#7jj!7j 7j7jY7p7p 7(GQ I7DD-Mk7z& !7JyE ( 7JyE e7JyE i7JyEs7h l7kH7̓?7ZU=?Q7}7 7 K 7M<7:aJ 7:aJ 7ۻwu5.7ﰑa7߳ۑ$ n7}@D7潬ޥR7潬ޥ76= 7 ( n7V[ 7V[ $7:{7a< 7̟?gK 7P7;8|V (7p 7vT%$/8>-f 8]#8]#8ty8 :s47k8 j1 8 j1 8߶ 8߶86Ee86Eed8<#j81 |BJ8j=HR8"\8%P'd8&r-8&T{t8'o(3R>8'>%80kJGK82 85$K 87s/j 8<]".L8>" 8JIjR8Jd8Km 8LM+]=8LR1$8Nkas8Rw8Su 7j8U,^'8V588X ,8Z7dL8[}8]>l 8^D8d|> 8d>8dTj-?8eF 8fhXb 8gtZP_8o)(.8qnE7]8r ɇN8t258tct8tBa 8tBZ8v 8v0x4d8}f_M׎8~õ|N8~õ|R/8]a ( &8-[ 8@=>8@= 8VDQ8O8S8wg8b8Au':8!Od 8B\u!08Nv8nB+8fS8/8c8̾ԏV8@ 8{= 8)2 j8EI8Ɓ?Xɡ \8خI58ڗ:8ζ@88q8׵0P{8a׿kj8ކI\h ,8x0͡8`2t8`2ts8X֪҆[8v>%8vh8vb 8v8vj8/_N 8{=<8A38A3 8-uO 8窱)d8ALQ}k,8ALQ}k e 8ALQ}kk8|' \8"I/8;vW|RX8;vW|8򇍎p2 8ӕ^ 8ӕ^L8ӕ^8ӕ^S8D : D8^m9ȗJ 903C.79D9-S9Bԡ"N9Bԡ"9vmg>9Î}b9c)v>9c)v \9`>:9G))(N9@ŀ9Vn] ?9!fR ,9#Z\XN9&C354 \9,qw 9,qw 9,qw 9-}QYL91<MO; 95$QA $96Os i96b> T<|9:hhQ9@d 9CǐHR 9Gn4`k s9Jݚ9Jȫ#X9KI0 9KRm 9KRm$9M0&};9Mj'2f( v9OX>|9PpR9Q¹BtE9W"4ИG.9W"4ИG9Y\ 9ZE 9[*7: 9\ߊD 9\ߊDj9]tw}9]Nzu9aqR-9cqME_ 9c N9dR9fm7ȱ -9g;ɾ89g;ɾ8R9i9xR9l`^(:9l`^(c9mꬴ 9o:~99r&!9r=1݁ !9ux)9v$S99vԜ|9}k28 ,9dz(c492HU39$ޣr9*9 F z9+L&pQ 9KNB-89KNB-93 .9*W9^ԓ9]l 9]lD 9R -)ڙj9qP> &9qP>9Td9{v79r)+9+4 9ʜjiݓ]91aG\d9`PH \s9`PH \9–Hb>9鲚HY9/KjG9/Kj9灡0 9_s2`D92ێ92ێ9/ij 9ɍ[Ϲ g9('N9('9&a|k #9ͭ'_ 9ϝ>;19Ӌ`u s9t4] |9b֌[9ڀՈ.9S 9݈Aq9<؆m l9SJ9,7{f9(9MG59ʺQ j9]ni9\^Z9$9%5)cK9 (9'S9p?KL 9?n9sSփZ:Xi(D$:Q; :ץ:oj { : б: A: 26Y: XcP:X44@:X44@:Ĝ :J:w0t:S :'끮h|:)\+x:*/S@:, a :,!S:00%b:1~!:1~!:5KcW :5KcW \:<J :=ms:><:><:><:><R:?fz ^:BjA:Fk({G i+:Fk({G \.:Fk({Gs:HDÖ:HDÖ:Iz:Nf:NW?Z:OaIV=:Olމ}j:Q_0 (:Qa.3[:TJbf:TJbf:V!Fp{ e:X.c{@:Y5}ԟ:Z8K}^:[SBӧ.:[zFz1 :[Zc :_q:FY:`}2 |:eD&;k:h`2 p:l 2 F:lL\B:ll71:n`2>R:tDnF:ubŊ^:uaZs:uaZs :y2i*ɸ:y':ze5|:_g! :_g!a:fhk:fh i:Rs:ӟ5 (:^Sr :kowYb:Z(b`>:ӢU-5b:: : 454 \:1C \:. \a:fDwv :D:p:L,A :TuF :TuF-:Wlt:/:0 ,:0:vt ZV:T> C#:O e:RmN:z6%Fs:\q1!gQ :˅Wl $:R^O:Τ>:4]':~HZ :息=9:8:k>:k :1:>6$#:>6$$:RxϢ :RxϢ:£kfR:pB:*aI:"3 :#hG:ss;m(* ; p/;ހ^;`';2 a$;DE5^Y;09; HVH; B5; 2u(PR; ;XWR;lBiP; ?; ;o7m;dAy ;-Hc; ¿MY; ¿MYL;!A뾂a;"(Of1;#q ;(zht;,}- ;-6~O;.Iq  ;1N͘;2l*:s;3 ;8q@ ;:d;;lXǔH ,;;lXǔH ;B ˬ v;GmZ ;OOAtz;WJ;t $;\1ܒ;_Yۮ( ;b O;bM4#UilL ;c#%TM_8;c#%TMS ;is|;kM&Q6 5;n$ݯr;n߉k>;oe c;oU { l;q -;q -;q b;rDE()(R;r6av ;rR;}#0 ;} j;;mvJA;9 ;djY$8L;djY$8 ;~RgK;VN;Y] K ;[pd;>7 ;wap ";2l;&NlF4;<T;3 ;TB;(6 ;\K]B i;[g#ت ;04>"~;X9#;[KP;sPi;s_H;>I|b;xr@lY;ɨP%h;\; ;ch5 \;D7 c;oR e;R;փ< ;ײ{d,;طKl ;K h_ e;J;b ; ] ;:CS;{w\y=j;笗 v c;GDy ;9ȗhR;`eϟ ;Ckv7K ;Ckv7K>;r);-i[ i;LpÐf;į5;ĹB)D, <M]Ap <Q<Q \< :{?<DᓷC<brF. <ƊA<,a (<isz<6KmX'<6Km[ <6KmZ<S̔<Q#SI <Q#SI<Q#SI<Pk<Uh <0GxMj<0 ,<38f+ s<4̚КQ<7;| Y&<<0gG <=pώ8 ,X) #<7uR<ȐSTT<%$-<f #<p < Ч1s <2<7zv<#bR)<#b<#bF<#bQ<s4  a=#&=.i,q=6]  =G5=;w= X;&) ==@XG=YӻN=D&i=q! $=>Hg(>===_hs= \=#0d=#0d=&1ele=)N}`Z=,i}iVQ=..\j- (=3tsg,=4Uˌd=51=9W# =<%`> =<%` \=>J> =?).G/=@w$ s=E?ޕg=I$U=NO<\=Q?=Q8E 3=U>fs=Vټ>=XB4iv=[!(e֌>=[2v =\fl|m[=\i`k` =]%j`=^׊p6=^>p=_-W/RIR=_AN =_AN =bLa =bLa=c Uz Z=g&bEV]=g&bEVN=iQN1=UK 1 e=vcD=V_`y =sՠ>=l6q,=j =[K xY=[K xt =K[=[7Ql=[7Qs=u]Y[=J=9X ==_fF3 =RU"E  =RU"E D=%e _4=˹u= U:v=ͱ2L c=ѨV2]Z=Ծfj =أb -=تׯ8 $ =ٚH&3h=Fž= p=ejlC=lD+dT=Clu=pY=,3 =ؐ\=X [=u#o>S v>S v>+> 7  >?9;Fd>d'OkT |>P>P>>cv[ >q< >a#ZRMR>!r|>"0 <>$ޫ >$؉>&Wo >(A/: (>(A/:>)+Jd >)+JR>-q#y i>/#xQ>1" s>1Boj>4 >4 >4Y>4 >7i?g>;DLD>< >=nn~^/ >=V.>@0@[v>@f@t (>A =p >DI.x5>Gԏ3>Gԏ3>IzA + >JL.|>>JkLt>L/b{>L쩱Ͻ 2>NQ>TQz07 >TiT >V0i~ŊL>Z:0{h{>` 6c$ >av/ #>c+y>f$R >jRas>jRa>ra+ >ro ->s{S",B>x[ >x[>x[U>x}>xP"åT>yYDu>";7: 5>Q>Q$>'NS>Pnxt>(2K>9t8>nZ>7R>_' s>߽@[ #>6}:{>@Hp> +-%> +->ޔ*S \>.$ $>Rq}! >oR >N*XY>%q/d>{& >zX>0Eվz ->3, 4 >~S >@>k4+j>k=l>Zzazt;>Zzaz">ZzazY>c c>kt>NUU>O)">>^5 a>ϕEul>e5 />e5 >pWD>ߢ^(.>ߨXz>ЮsE > ųbY>ރ7K7>)[2 >9m  >#,>$ vZ>N:L"; b>ϝQ6>][F - >/\Β >[j>=Z>l% >CeM+ >p >=)> 8->>Em B ?{w>ݧd?6Ѭ#?sc? HiӻG? ~Y? D2V>? D2V ?f-v ?VA`?Ks?nQ>?@!2c\?%c- ?"LKk?# @ ?(P ?(PU?,8 ?0~?16Xq ?1$_?3f8F -?9/L?:$%$?<cҡV h?= v?>?b/?A˸ ?CKK?J*5IN?JFAߥ ,?NW@>S ?NyN ?R)^*"?]w*{?cRc  ?cRc  ?h$ҞU{ ?nuO?q O?uhNq ba?uhNq b)?xjk!t?xs*L ?zB\?z+ ?z+ ?z+ ?|Np?|?}) k?}e ?}a/(?}a/( c?}a/(?~/bN e?~yehj?o*(>?J`go??R?gIY?~ ?; j?-NL?\噿?Q &?CK?EK?E?x$R?$ ?n+L?N ? o? oZ?`QMz ? 0K?1k?1 ?D̿:"?D̿ ?D̿9?D̿ e?D̿ a?ytʓ ?2aK?SN f?[s.?\!,s?U SW?'O.v ^?Fxx?Fxx ? ? ?($?c\[%?\oh{ ?t2>Y?_-z?pjFv m?pjFvt?tc?[*?[ z?PV?`'3 ?`'3 ?DKj?.P ?EN? K?%iG ?-GmH]?-GmHU?S'9?4 ?a#?a#?￯?/zcp ?Y?h ?Y?h?i6 @E @>vs@ gXR@ gXK@틊" @틊"@&k@r{v@ ' @YL@߆ v@bH+v@bH+vK@,Ŧ @!>@'p @,n=e@5K@E @F.f #@P @RϽ@Rݝ-L#@TJ @Wj@X l.@[8qP^D@[j @`v{RT@`v{@`v{ @`v{@`q*e@eFx m@ng_ nL@rY\@whwx@xq @|JZ"{@~iE{{n@BS+@~LHR , @?IxK@|JO7o@|JO7oQ@|JO7o@l T@ݒ$ ,@ -{ @:ÌN @NAJ@ 4 @'Ӓ:#@'Ӓ:f@'Ӓ:@1̕*V@5(@b,vR@|G,@0ؑU @o^EdS@xtxǝe@kú@0D8iZ@AF@d \@t?~ @4s`@ >m@v~@͕Hq@6 @%l•m #@t&`vL@M0:k !@cfgB@cfg @cfg@cfg@/J @)Es@۩(b@XV2vj @XV2v @[ eR@e(@e@_o@8[Q@8[X@辧V^u @  @?tW o@ aȆJ @R ,I@<^A p :A p  (A H4A lh A NAYA 'BA ;AK[*KbAK[*KjAK[*K A{bFA{=A{YAG?H (ADAA>A>cALga AVH A,!,VRA#qӽwA#,5bhA$G9A'U* RA-![@"A0݃pnYA8;M A92*W~A@AK3G>AKZE_ AM,`5bAN/? APdAQKPAV}/dm eAV?;>mY -AX,PJ8AZ< H sA]{!D]A_ţ o| A_ţ o e A_ţ oAa^vvAg'G lAgAk4 ,Ak4 Al>jAp% kAs#38As)AAtr gpdAvA0u$AvD|#Az*npkA}h0AT?MAiկ Aiկ ASN47AE l+A$UA S AD A&DA&A A- lA7ad A7ad]A>A4|گvA4|گ #A'S:A9 vAC~GAN AǹpaA'[G iA[Cs A.kM^m ,A=LK8A=LK8 A6h.$A6h.LA6h.eAvs ,A9{E:A,LA67НnA)Aa, A˝i# Aοk$ AW#nAW#nA慨A/2Fd AWvSAjIeA?LACA?Hi" A[2f A, = Ap{n|A~ڢ*+UAo߶6AAxhvAg1oA$H%A} iA AǭG zAǭG *Am|BRP BRPtBSXB]V|B Dx B Dx B DH B DHtB ݢJB@91a B@91B@91SBn>B֖+B| BNAͩB'B ) (B )B ιxD$ B&kr}t ^ B)_ ,B,B B0%~䘁M;B0@nB21B6ҳQB8 B9ẁRB9ẁ B=gB8o #BCZao \BC֗ԩ BFeTB mBK\Up+jBMK^iCBM Y dBRjLBSyd=BSyd=BSyd=BU)d9sBU)d9B[i B[i B\VEB]d:mKB^)BdUgBhW[cYBojqk,)ByVbcB| ZG| lB}=VPBaU*vBj@lBE-TsnB$ B$Bb绕nB,q^v BgfTBEG eBEG Bz# cBӵ ? ,B6[BE.TsB8 0B߅E>BbҮ[ BbҮDBbҮBJۊkB/%.Bi BlMoM~ BX_zBt:%<BaERBْjYBW:BZ&QB^aB=jB8 ^Bk#B"uX&B㥛/u)sBnQ"@<Bu.HBLA.Pg B:Ajh BM4'>BWKe#BqMIBB̑-xB'b5BhIORBMϼkBMϼB#eP}CS CV@krn[Cp= Co&.;aCKjFC ]j COc*~ CHj:CTC(]MjC{ eUC'CBk>CBkC$|MtRC$|MtKC(Lv2 (C(@m^FjC)]C)]RC)]C-9lC-doskC-rs" C2ňl C:*JC<_ȉ:E>CCl+% Cm-Fe9t>Cp%J~ ,CqvR_pCu_dI6C|k7 C|k7 C' CujC 8PDRC>CJYCʲ_ -CF,$CiH:CaWdCS\C C>m.*CC5sC` 4 Crd CIN rCXw Cf^$zCA C= C""œLC1,=1C1,=1C[tC)38C?fC2鐟  C=UKLj C=UKL (CCRCéOCéO0CXp/ tCXp/ CXp/ YCڭڔ2Cڭڔ2]Cڭڔ2C$0C$0C ۴CjCCQjʰ ^C^+ 6C^+ 6CIPCClLVC NC&Q (PCD\pC+Cc -Cș9հ>& C;[t:C}p!l iC,qA$CCԖ8ʓ C(8HE IC^`S!C^`S C^`S Cۧ,ع+Cۧ,عCۧ,عCۧ,ع C\ U4CxܠXC¶XC=~qCU $CU C\z"C ]9 C ]9CQ CV"SCV"RCV"KCICDkCDkC8fj|tCWSZHD#x<D#x<KD$(jbRDw|'DN9[,DїDї D-*DyS6s(#D +~jD aM:D Dvw|D >QD De(D^ u eD=Hh/KDKDYDsH &DJzC iD&deeD&ʎD-I"RD0sWƊq sD1}^D5 >?0D9 @rN<D9'1 $D:@D:@D;Ձl6vDAR DDf:DEKU0 > DEKU0 jDG5T迤KDOԀDUtYf zDZFD]uBPJ ,D]uBPJ Da2cT $Da2cTDewYiDeYf;DfPs~3 DfPs~3C DfPs~3QDl~DmqW #DqTwDt*n  Dt*n DtjP7Dv{ o3 Dv{ o3vDwnT*f D{\k,6 D|z=2D|=ơ + D|+k DktDf Df D{j>D<D4xD)l+DopHDwxD/NuDGR0DGDG`D.1 ,D|D4DA;v-Dt%$# D 6AD?Ds DDtDj Dv2pvDOz|DSٛ D7xA \DC[ ?ޓD8ZD."D.D`E D. D ND Nt D N D4}zD4}z cDָkmD8 Dp*! Dq#|Dݵ$9NDIHfU DeȂ& DlYgD?b}YD͟:|$DgWvZDύ_s; D3ڰbDc!hDVs>D՜f2P DgZ(jJDڝTRYT>D܆ugqsD܆ugq D[ DF{,e DP-C aDYl D[Np]D$C+[2D$C+ D\ѦjE}> E}> E}>EI $EE >sE)՗QE)՗E)՗DEoE}gfE}gfUE: )+ :E: )+ \EⰟEy9 kEy9 (Ey9 Ey9 ESEU܏*cEU2EmE—RE_̡\bEܘfE 7QavE#%{jUE$!kE(N W a E, E,(MJE1GU -E1wau. > E1wau. E56roE6ϋrE7;F3>E8RRw$E=vIEA8*0 mEF$JsEGL#EL#"S_EO EO EQZ aEQZ EQZ tESCMETprr8 ET!E璥 $ET $EU eIEUT#߫[EW <EZƅfrxRE[Ũv E[ŨvE[Ũv ,E[ŨvE\{XBE\PKX E]/O4E`u`_0 iEkۉ6":EpI,k!Epq\Ep /8lPEtcflEts Ew[r aExXtEx' ExʻsE{eŦE|3~i E}1jE|Em[~E;^EwE[C?E[C?Eȭ+ Eȭ+E;lE!E<{- !EhEځn E"yx)E"yxE"yx E"yxEڲNtE"iE@j>> E@j>R EiʀfE/llEbEb EV  .E4m iEOY (Eхr$Z F=Fc,F"]r^F }SM FcFK~em F2NF0J|DFS.2fKFt4 F!A>1 F!A>1[F,KF.nF1CE2 ,F9F@OY+ (FB{W_OFD  FD  FGBx#FIiـFKI6[ qFK<FMm~[ FW` .FZA F\QvF`G\e5F`yƏ]FkFnkuFlGe"Fq?4 $Fsr# Fv50FFvRFw=Fx~;'Fz6V,F|&eF~e0;6F1K[sFDU ,Fv?G FJBs FlT FlTFDn4F}.VF5F f@~F f@~Fl#YF@f . F@f F_BFsF&flRF0x 4F园0 FXUF2%=| \F$66sFr4>HTR F[al_ lF/q&$F , FѧN{F,k8F@gF֎q-i %Fi:ĤFHkFy3eH1 FYP+vhFYP+ F,A # FXOO FA ]9 |FMB FF|7sF RF}i'F"UxF^o8r(Ftsb+Ftsb F: NF'#F'FuP_FXGC+5~aGKQGI+oO G[,G 2E ^G =Y[WsG$ c3(GeeajGnFGzkbKG/?P GY@}sG<& $GbS#n GbS#nGBl?Q6GgM.jNGgM.jG!H> G"l G# s3G&}9ez G)ǝ +bG.7 7GV( i G;8ƊG;8ƊYG=sѵiqG=TROtG=W9RDR G>"dG?ninG@!E& lGBS>@FGCgcGCm` !GF1e GN{R}GN{RRGQۛ}sfGQۛ}kGQ0#( | GS> GWc˴~GXe^\ GXe^\ (GZiyG^y G_y5Geki<-GiGpG9' GpG9' GpG9' Gp bGqǓ8M)GsZjcGx(I[ GX!G-0V:"GVIDGrIsϮ cG|"l>G; qGn1!G · G#8 G/˭ iGj (G jGu)+QGE G 8t- G>GI(UG[ G̑PGOG (rKG|5F[G|5FfG/w cG t_@aG t_@G+u@G4-ߧ G٣Gj\ G8 r eG6ZG6ZLGʸGʸjG{x GP(M٧#G ;aGs%GkrVG߾;KGk -Gk eGk>Gk Gk G nlG[U?% Gt aG_CG0`J G0`JsG0`JhGd;<GE{ cG$j<3G@]G\-n G G㯏^E lG㯏^EY G㯏^E G㯏^E eG㯏^E iG㯏^E G{Q|sGk_Y[$GȢJHNH^sx i H^sx H22`pH22`pH22`pH"mr4Hu}"."HKZhHW#^>H_;W H *rHޘkC>H%hFHTwH&7 /H'KY;H*IN #H2 @yXH2zpH7|]wH74${k eH=U)#= ]H>UwVZH>d#HAM2AmHFDEHF .HK|I];HOd)HP  HT#/+ cHW'h HZ'+Y&o HZ80HZ80 HZ(7 ^H[fPC gH`$`EbHaX$Ha&HaHbA` sHeU+:q aHfy[UNHl+>Hnn@:HrƁ[ $Ht'oG Ht'oGRHt'oGHt'oGHuH~p>"1HXY HI,_tH0- H[ HVGc,NHi%_)uIfH,W \HƝRHEpl! H @SN H5mPHAFhsH<4HZS h9HbVn #HbVn cH,dHq]g$ H<`QH^qpSH#M YeH#M KKH#M DEH#M HVRHOzlsHr $ Hw1;H|@->H|@- H|@- HܕA=HܕAHܕAHܕAQHgBkHLr HzWEH"RHx+K\Hy=NH:.q H,THlZH/J:v>H[AcEJ eHɔHɔH_&5# Hل= HHCHݵmHHBR H^, H^,H"p# H"p#HIH2g H/Б H꺜bUZHw-9H=YHAeHvWH-VqkH|H}hH2t¡ jH,gѭ *HҿbIi50 Ii50 $yIi50 ,ILCQILϙ I t9I u}Iˏv8 ZI " *IdD #I?^Iy)G*UI( I8'$nHDIi:tI#u I#u =I%•WI&[?4>I&.ǭBI+Nsn&I+P9I.fU.I/!k I/UorZNsI0%`I26 #I4yoU |I6q=6I9duI=Y5QIB^NIG]XzII@TWIIHEIMr } IMh|IQUaVlIVJX> IX@" lI[2| I\~GBIsI\~GBII]44sI]44>Ie`xRIiq~vtIiq~v Im\QIp rIy{lg oIy$OI|I@ iFIaH I9n懃ILIs3Is3I-n.IxVIxVI3L;YIB3:,LIh Pb I&=I-tYI-tIO*bIC I\Ӯd It` I0Z) I˒GI-X I)"cKI)"cI+،_I+،_ #I6lq! I6lq!-IkS"@pRI?tkIeIdAI IIzH_IWoN IHIH IH I+\IKxYIW I{IeJHI:N IX2.VN IgIgI`CI4U I͈4aI=3 I=3 $IAEI-JJ$J Rb 1 J Rb 1J S)yJʂJ.O Z J.O Z J, J ބ>8J&?Dm> J&?Dm J'˜E{J){ J)|9J+  gJ,{J1um+|vJ6ĬaJG JICS'IkJJ.A׬JL1 JN(ܜjJOkmIBJR2؀BUJ\ NJ\+k쉆8Ja;Jc4G@zUJd6,PJexȝ[Y>JflGJf* UJk_Jk_ Jk[ Jo|HJpuJuh?BJy87 Jz>Jzt2UJgJiA[JYJU0JuJ{ J?w0 ,J?w0  J?w0 J?w0 iJ?w0 CJ?w0 J=`k |J WJ<Ɖ*vJcߴR Jcߴ JhJS \'JSjJ}~mJ8#1 JXr^i JçOOJ TJkJ55JJ}"JtnFߪJd Jĕ0(_J?kX Jƶg_t6JƷтz { J^Jˋq7J|~ZJu`sJͳg'XNMLJ.[JZɥY JZɥYJm J("=JzL1X J>q~^m"J߫[J^*JW ,1JgCJ4 !tJnφb mJnφb JKdAjJ@J@ Jw?-JԖyJ& !J@aJzHJO?bmJC| #J?< iJ! vJqfE9JŭݽkJplIvKнK ]@0R[KKc)4i K{ZjKu"d K +YKfɃKP%[Kvr (KvrKvr KvrbKvr Kvr eKvr KvrKrM{-Kflc4KTQZK_>TDK#-'K bʿK%x>K%g򿋮K&}j%K']\+K'ʒA{ K'ʒA{tK(YYl_ , K*E:K,_ikK06$CCK06$CCSK06$CCK3<ݙ4 K8ab UK;̣.`|K@ bKA]B>KCDڏxKH,fŹKMq"+ lKMu hdaKO{V KPѾ_#( KQ#sKQ,2 KWZmTKY{(?K_r7K`Pܱ:K`DKdEn'CKd%!~Kj5`&C Kj5`&C Km 'HE KmgFKn&z>Kn&z>SKn&z>KoSRKqQ1w_KrlA< 3Ks*{5 Kt :LKzyI K{  qK| a K:G C9 +K?e>;K?e:K ~*h7K ~*iK ~*UK ~* KC<K&}(sKSfJpK3C\uKe{(Ke{(K`pKz>K,TkKCƕ]\SK/iO Kju ?|Kw \K K]oVKy6 KpKKmf4KŲ/+<KFMǽKy[>Kx/69K?K?K?K'j!K' K' KٓKbPKÁw:K!] h| aKhϩ6 K):mKeXK]Vc K8Z= K?okKI'!ZKѦF0KӃv 4K$zK(YROVK F K]|)7YKLNK戕_tK F K[$ \KdhejKH KH KgDGDKgDGK갉۶:K_3^ $ K_3^ K_3^ K_3^ K9jK- cKnU K??d Ky.hZKZ4LlL e\ aL ŝ L ŝ L T-^. ,L T-^.LȨQu Lkqm L[?I L4 L[DLYR LYR  LYR LYR L#Z^L/YD L/YD L/hYL3~V^ L3~V^DL4Z|V-&L7JK| eL:o ZFL;w!~TL;[%L>8X L>8XL>58zL>58 aLAq> LErID LG\<LMBfaSLMBfaZLP jPLP (LP LQpxY nLRQI 0L^ dL`TaLc6-vLc6-LhV Lh_0KLj3Lm*Loa- bLqSBLwp!?3Ly)JAlNLz@L}:NNL}OIGj.LzLdDL~{=L'?n:LpǫLlALsL&'\_ LKG]#QLp`n[Lie. $L;LjxLK LN}< iLN}< (LIzSL#?1; aLZ8D>Lݢ LUZ j LUZ jL`Q!1 LOLzk{N>L#&x5M] L(wR`gL;ZVLT\&LpoLjLjSL8c | sL8c |Le[L|m L1ufG>LӜ[4L}iKLֈi>L ^LCLCYLݱ&FHLWyp Lݭ7jLUrg]LUrg$L+YHaLZ%eL1HP› LA[oLtaLtLM)KNuMњIeMV!R MUM m #M E͂ "M \ vM_D$M4+QMp}TM-n)4M; ,:M; (MRvКM39)OMN# $M.Mҡ M lDMPCM"]{M$,C M)Pyd|M)>M0l M2 *NoM4o c MVQУMW0o ,MWt nMWtsM^p9wMbW߭Bn MedNMhv1EMiHSMiּMiugQs MiugQ|MiugQ Mj@"C Mm! Mqm)ЭMuMuֽp My~Ye: My~YetMyĉbM%!Mi MSnMlPR MlPMQfL$MÖM^ MJDžFM0sFQM% E# M@M ME-*UMT~BjMn/8#Mn/8M.MX uSM4HtMN!tPt N!tPtN$)ZN%Vӡ-2 N+"{֨-RN+"{֨-N+IDlN+IDlN-7NN/ ;N/ &eRN1-) r N9qUN:N`74p?Nx^_(NJqddY N.v:_NwMslYN<э N,G Ny3UNexdNtk:NN{[Ng| _NSG>kKNe NeNfON?Vz Nq\5Nq\5 NBNçjÈJNçjÈJN ic2Nh^"9-NmxaN$#{ =D NЛ֊B}NЛ֊B}Nԗk>NԗkNWg7\N[N-nـ N3#PNހOaf  N\> N/7}&N! N+=YN+= sN御`[pN御`[pdNf N?OvLN 1NX;:NYde#N NsbtNdr_:OWѸIO+NO Z@NjO hIO0}2 O?cOӖ8)ROw_`Ow_aOw_OFgaOmvG O0 %fOz^ڶbOfV O!-O#2R7uqO'o O+ƆktO-~甊 O1438|BO1438| O1$f O9i O;OB^3!QmCOF8'c:OFWYbOLw]`vOM+x3=OO_# ZOToB ,OV5DVOX Dб OX Dб OYdT,O\O_~O`ݛ Oh7֕>Oj/Ol*N㉱ $Ol*N㉱Ol*N㉱Ol|On-Y= OuOv Oz-~TOz-~O{JsO{1gRO{:)S jO{-9P O|U@OroOroOCO|}0yFO|}0yYO|}0yCO|}0yt O|}0yjOqCX*O0I7O1ZOj jObĻ2O5 "O 3JO~Ev O%o&O%o O%o iO3O9 ]Oc`TOתOYLLOBn`"U OaOKByDO3F̉OV0 @O %`FHNO }q O$j~>O$j~OVBu2&O*Ⱥ>KOr!? OeO>OLw[-vSOڈ) ! OܬѢ OČOY] 5OW/Sv O/n(O/nOyBjO! \O! \OÐ, ONnX$Oj +OSkOXP OXPO)O@O@SODir P[W+, Px' sP /MP Er)P Kjh!P -D P?UP?U $ P?UjPèhP>a P3'P&˅Dy -P{I$P{IRP{IKP{I#P{IUPS!P3IP bP<>P&b秃 P.C2XvP. UNP4[oڅ ( P4[oڅtP6<vP7 P9Z?RP:x5Rm P=mn0W> P@)}PB'TSPD=٬PE6̊PEzE PG7$PG@[ cPN ]PN9PQPO#Zt 9PQp PQp PQE=~tPTM^*RPU6nU PVDHYPZ?e SP\OԌU>LP\zAKO P\j\>hP\j\>tZP\j\>Y*P\j\> P\j\> P]z PauhuP PbstPb}$Pf99PiQv)r aPmC)ԭ Po-٠PpI "PwJB MPxcJPyh 1 Pyh >PzGFa P{Zmw eP zlX_Pw2SDPw2SDP?bbPm PGrP=P{ PGQPGQDP!lUdPʷPQkwDPQkwP|Piz PX-xU PB !HJ PIs\s P;!ѽĝk:P;!ѽĝPM<8VPM<8VdP=8e-[ PV?sP{gWPNeP풗 P(U%UPCPf볙jtPɬaP + P8˴DP_ƺ P_ƺP&ISP>JS/3Px)PnQ P*09KPĝ|P̉g\P̙ PϲKE \P< M$P¿DPkpqXzPƍx:P[ CP3X7 PHAP P<:5 ^P<:5 P<:5h P<:5  P<:5 P<:5P:^DPdʳb jP- mP&6 aPImAP""P-u  P@PvPdsP)iP} PN+"sPN+" a PN+"Pwj@sPwj@ P~kPFM NQ4HYQ skEsQ(zJ QQHKWtCQ.s#Q.>Q!A -Q6mWQD Qc*Qc Q&Q!}#Q"" \ Q#ASphK Q#p $ Q$7M^Q$7M^Q'1&N"Q.e죵dQ.e죵RQ/b= Q/{֑LQ/{֑?Q/{֑S5Q/{֑*Q/{֑Q1o>QCrG zQF*QG*c_ QHzDO QIN QJyE a QQD*T+D QR33vQRQS*!cQT39 a QUE3,S vQWfe&v QXfQZx3\ aQ\Sɪ ,Q\Sɪj Q\Sɪ $Qa`QansQansQe{^QhnGQm]t9Qm]tjQm]tQvjRi]Qxv%w[' Q{#C"gSZQ{H0 s Q| @Q}⨧aTC Q']QZXLQ/QXQX QIz0 tQ!h!N zQ񾔆Q. Q6T^QOQ;5JQ}(TvjQ\Mt*Qֻ MR Q( Q1LAQQ}QPFc ,Q{8!Qc3 , Qc3 $Q| QDI|jQ&g^Q-'!>Q³H1hQYhQu<^It QYQyBftQ̆iQΙo@Z SQΙo@Z 3QQ;ÕQ8ζQ {C4Q {CQҿ!|Qfբ4Qݬ0 AQ VQHQD FtQ_۰fQDxQDxQyFQyFQՖORQ棰 b*Q8zQ=;S Q=;LQ,dsQO<=õ>Qd1a lQ@;M' jQmi1 xQ hs R<׮ eRq<9+:Rq<9+ R=7*0eRXWdR١>R |e6^R .R~qp5RRyGtC RyGtRfŭy s Rs>R;z;R:r,R^.G KR֑έN Rn?Y< ,R۩0 eRִenRq jR&,s RNAi R"KM Rg<\&=Rg<\& eR_ (4R_ $R_R_9R%~_ Ri- ,RPOg \RPOg RR RnjfR2|I] R2甖N RQGZR2moR(^4 #R7e;' R՛[ R՛[ Rɇ % Rɳv R,/i Rq3`qRjV RϷSB# RФ0X)R ;vR+,5Rf$$ ;RRRRٮVDRRٮVD R۪mz sRܚs8RjR߁-yfR5VyR gR gRwy< ^R?K~R:&y|RYcQR誄61RuN] RuN]|RRzv~ iRGJsRGņR RrZwR1vS:-֩|S}GQ\S=P;QS StS 0 |S XAo Sd&]S A dSi+#`S"?Zȫu>SD iSf!qS"QkSY `~: SY `~ S\¤hJS ʉ' S#T\^S) h ojS,"Iq>S,r S1KGaS3l NS3"egYS949nU S= n#SCN:SCnCSE.b @SG~+USJz4aSMq>sSMq> SQVSRi j SR{DST?[SW/ÔQ]S[.@ $S]+ʷr> SacSacSdD ?aSd* PSg47SSm*.Sp"XkSu[Su!:tSy@S{+ Sa.'c S5&SBce mSk>KE $S҉tSW13So' KSjUS;68 SuCSuC \S]5 #S; SSKT'SXòEXSoH!Sd0E tS;_G5 S;_G5 S;_G5CSI&Tk*S(': SrX S < SK?S SFxaS,I" SŴE %tSc;gMLK Sc;gMLS) 3SiZcENSvKRS۳ ݹS8S8S-}8D[S StG StGSmsTS՟mS3fg)S רx 2S_SET($Tg]v^Tg]v^ Tg]v^ TnT ̎ -T "(כ T *zT Ц/jTTئT#zѝ٤T#zѝ٤LT$x=r (T%"XXπT%"XXπT'SKT+= T,T1I-HT2A`T3mJT<=9&T?}a(-+ ,TC\u gTD~?TD̄Q (TEF TGP TL<\XPjRTN\= TPtTPYTQ$w6TXq^uT_C0² TdA) \/TdA)>TgxL5 Th/GsRTh\|TkW<tTkB/TmgN Tr߲1zUTtgqTt jTt TtQ Tu_IpTwCTKTIh)>T#T$Zc#T$,Te TW3TN1oGTZ -To}Dm =ToEfAT?lT};YT1:T9c~T;GD Tt cTc<\~NTPBT"vXtT:P T'\ TTo9TToTTo Tn9' T]T] T;ӣ , T}Lc T?RgRTlS.<RTHM4 (T;k Tq 1T3:aTc;O , Tc;O HTc;O Tc;O ;Tc;O Tc;O $ Tc;OjTc;O iTc;O T& BjTɒ%KTo TǕT~E<ԋt T~E<ԋTm9YT'=N]T)ubTᷙ.*T?ܿQT)r 9T,V fT/ -T/ sTyv[ Tyv[ T\ aTyT X3Tz[Tui6 TN5ѷT# T#T#>TvM|T-&$TtzryRT6rqB UgpbUU{3 ,Udӈ(eU=6UpU 3KU ,U6^L UY͉$UY͉U8oE^U1jj|Usv|w Usv|wULο UJL7"U>UUR RUcf Uz:>U]i$v:U"#p {U"#p U#c$U'vƄmU" (U'ɇqo U(Sf U+ a<XU+ a<*U+ a<U+@}Gf U,fy&U-  U. ttU.ML:يU.!UU0^ U1 w U1^T} U7 k#QU<,V>N UUhj H\UiC; UjR iUl9Y*Uw+HcU>/AUrz?U HU`'U e Uyt/ Uj UNƹ&Ok kUB+UzUzUdlTv#UfpYU\=} yU4h `U4h tU < 9UP~YU6݅  UgC7: (UkN$U6+Ui 5UC:s9NUC:s9UtxU#&24U}Z7 UE~9KUE~9KU[U!&tU!&bUiUaUKȟfU˽~q aU˽~q>U˽~qs UiKhRU/KLU/KLNUHNUHNU.B׮͟DU^Uʨ Q)UQD)s aUlÏ< iUͅu UϤkS-GJU`Q L .U"z-RUֿ-sU'UUڬ,f#ß Uݑ? 1U!+i UIZU… mU'&ARU'&AU40U, +U~1Ø~fUWzU U67 UY! U`sLj jU&),sU&),>Ue-]Om8Ukcj 3UDð #U@|@qjU@|@q>UN$tV bVAV _Vȷ1|V2FV2FVO pV sL Vq] Vo>V E)JV E)dV>[& V꿦i]V"jdV"jdDV$^EZ2V%H{ğ#8RV%H{ğ#8V%H{ğ#8 V%UxV&rnrV*qKh3V*qKh3KV*7 xV+O:V+O: V,X; ΝV/CM !V0§V1JusN V8{X 3V9پLJY V<7*sV>>eL sV>>eLsV?[iTVD*b"VH{J=  ^VH{J= VL嵥-VOvyDVWF)[V\lH@V\\_ V^?1 V_VV`V^ V`V^ Ve`EVgHǹ VkQ Vl+B iVnuVnéVoXF1Vu2MVuكkj)VvW9yH5 mVy-:< $V~W D j4V+q 8\ V ckt V\rcR (V?̏ NVpqs0VpqVj& KV|> aV:!Vmg>VIPVIPYVS? VS?V?嵽aV?嵽L V<SV @?RV _.*YVI-VD)Vz9:VRWHb OV: h a#VL*Vъ9 V7UAx RVu%* V£7X VƗo VǮb VaVxV iV09;ȣV'#kbV'#kYVv2LVjDcj VjDcV^~$RW_HW\_Wݬ_@Wݬ_@WІ= (W:h:Wj>ֳp Wzc3W^Ih|WwA[W"j+LfW(,*rW,?qѬ7sW,?qѬ7>W0cdU W2|#W3X'yEW6ŮQ@sW7%?C W8Ur>5RW:^<~W@(KWAUl WA g WA>WB9wmWIJFķWKߦ+ʀWQꕕ9WVH _ WWF7 WWF7WZ’>WZ’ W]wlwT9W]ЇȆdW_ 9|tWf+HWgNYWWi0] G% Wi0] G%tWm~]Wt3' ,lWt3'jeWt3' LWt3' i Wt3' Wt)iWwKo2Wws<'  Ww(,ZWx&1"p 3W}Mƭ1sWXW|] &W5Ie W4'f W CWy"ax+W! sW! W! W! WR RWu;W]!]W]!DW^ KWȶWiFWm0SWm0WHB2 bWt WC W|J WViu WlYg@Wx% bn>W^(v W;G't $W;G't (W26>WjҙWjҙd WjҙWjҙRWmZKWnԁ *Wּ\WS~ĒWaN WaNj WaN iW 3DW 3_WՇɏWމ޲WtkW6PFvW6PF WER3iW&niWp*3 mW)ǦFW#fՇDaWQ> (WQ> WrIXWDo #Wvv Wv (W:ʽ/\XHmIS~6 tX<6bX<6bXiJ;%Xn (XZ" X3'4X ar a X ӽxX /vXpȀzXpȀzX#qXvDXy焁 X7xXg-X"d}{!X%Taaߌ>X&X)]\>X+Тl (X,B*8:X2̯sb cX4> X8G4dX8ָ~X>SZzX>SZzX@<3%X@ g,[XA=XA=XA=dXA=RXA10 XE`DgCFXHf6vXI^liJXIvXOkkg XQLp]XU|qXZ-Y,m>X[5:oQ X]tXb↪:#Xb"^ 0Xb"^ /Xb"^ -Xb"^ R XeYb(XeYb( ,XhgB> & XhgB>Xh͋mXk2 Xmkn5UXp&{ Xr ?,Z \Xs*("*׺XsY # Xvsf*% 9Xw͚;Xx 2Xzk+z0 X{=df .X~fXUY&x&Xa&)Xa& (Xa& X9;Z X51)2 XktXkX๋L X/gR 2X N cXlMm ]Xz c XNh sXVYXIFJYX^7\X zPXD3dX DB Xэ XK4&>X|ntGL XtXI'X#E}XP`r:Q XǿGO0XǿGOKXǿGOXǿGOXcb( ,Xcb( X)gvkX)g 'XX9;߁ X#;X}XXnXɗ½) eX0u>X̵&SaXHXR|"ZKXgLX4o7XGE 3XHd XtA`kXK< X+XTX5ՎM VXꑏtJ<jX(?X[?tXd9 \X,DEcjX) &X)tXR68 Y0SYtY Y" Y]aYQZZ wY j?YIUSY(: i#Y(: a#Y(: Y(: Ys]Yf9Y%t.Y%t.PY%t. Y%t. Y%lz Y%lztY%lz tY%S;4Y'UfURY(SVY(SVY)cC$ eY* kWS'vY* kWS' Y*GY*GY23>]jY4͑FpRY6hB$)Y7 {b: Y9DVi?YFg YYJz`YJ 0YMZ"j YMvk iYOtCR~jN YV>y9 Y[$Y]I' Y]I'j Y_}mYcXЪ #Yc2ڵkYkI\ Yq`/*Yt|&'pdiYu/ Yw%ȿsYwU)s Ywy.ÖY}C'/Y}C'/Y~ok^YO!$% YR>Y`B]] YvX)LY|Y|Yy* \Y9)EsYҧ>Y YyUY(M%Y(MY(M*Y!Q}bY$,YwY1/bYT)ݾVY9 Y>02YsZ- Y}! Y [*-Y?i@YHt mYZ˥mX YψBK YUҚ%YUҚ%Y¸]iYʲ-[KY~ YW ,Yϻ Y,Bd eYxjrYxjrYէk Yӗ % Y<&H2RYԝUYԝUYV,*adYNr YދD?Y^ 4Y^ 4YeGpYeGp Y: Y5#O. Y5#O.jYj/ "Yy^xEY^IlYtOY:Y: Y wY wdY w_%Y `Y3c:y Y+Y MUY# ZSVtZ ,Z%\?\N Z?Zwb>Z%H >ZnV Z\/ cZNIiZ$n8JZ"g H sZ(UZ(RZ(CZ(ޮ!WZ* 0T]Z* 0TZ**C& Z01nZ0a8>Z>#_R gZG,0' ZG,0' ZG,0' $ZHU܎ ZIx᪕ZJϝZJ  $ZJ  ZJ ZO" zZU")A hZV/ m 'ZZ" >Z]፰ZZ_貍 ZcDZf[yZ. Zh"? aZnU&$ Zo (ZoZo䲳:RZtސ2. ,Zv , Z,G (ZtsZtjZ8% ZP1ZP1ZiLv ZiLvZU a iZ$bnwv aZGE $ZGE ,Za%BRzZifZ7,CZD_jZ_] Z"~Z1tZ%/\y} <Zڮew ZK_ZuS1P Z? Z*sRZ*sNZ Z\agUZRZԲ;Ip mZ #U>Z|f \ZivR ZOZO (ZO ZPo,iZ3Zu >W"ZMQZZDt !PZjZIZ8pZ>XɰZsJ1Z;]C ZA8ZXޅ8Zu½,s XZu½,s Zu½,s>Z˶" Z,H9Zа Z`χZr|3HUZּ]MW ZQkZڱ> Zڱ> ZTEZ6!扜 ZƠXZaEZmY9"BZ華j %Z華j ZU][n*O i[6? [2H [%p-J|>[&.tQ i[(u [(u[,y& [,y& [,y&[,y& t[0|=I~[>ꣂb?SK[>ꣂb?A[>ꣂb?[>l A+a[>do1[>do1 [>do1 ,[>yJ [>yJ S[>yJ a[>yJ %[?Ib{ٔ c[@3x/ [GY+|[GY+s[L[O`gS[O2Um.>[P31`V [P31`V [P31`V[P31`Vj[Pv,H [Pv,HR[SbȽh[W [W̑c4 \[`-VU[aW&HN [b\v#:s[etH[grr[grr[hxH[k\ [v &+k[v0 ] [v0 ]j [{2Zh[|@D[}GM:[}t1[}TxY[~`N?s[28^L[4[4[9\>[lKNZ[Iek [aX[_a[ [k.* [rJg9[rJg9[B6v([H:(@j[M> [8:s[=O4 [JT['b$["> [y"D k[~3[mBk[@o,[Ac9OW[Ac9OWb[c5`[ i[T\\7 a [~Qx[$[*S[䍐[pE`K[̦([|o ױ[ѨW  [VO[_Xw-L[_Xw-'[_Xw-"[r> [rs[Þ[_ *C|[F̓ [i [딨@h[p#g E[ h [rw=9D[aqG [aqGt[aqGK[aqG [aqG [r ![r[rj [r [r ([F|C\ں \v7]\ zX\ Cv\ s\ c40 \ILK\Ӱ()\q(c)\9F &K\/R \%{Xk\r8K\r8K \!MgA\!Mg\&̑w@\(zx,\)Z*]{\2CiQV[\7E \7E\7Et\8 B)j\9:\p\9al $\9al \:8{G \;7ҥ\rquj\A iW+ \D|ɛ`\I䯹g\I䯹gx\I䯹gZ\Kݍ a \NIm8R\SO\V[\X@1\YGU+\ZRY\\܇\]3J #\]ٟE\^H* >`>\^_[ e \bS? !\cL_\fע (\gK4#I \i_3^\mf .\m<\rgs\s8³g \tfo\~d;jV\ڕk*t \1SXH~[\+6Y?\'05!\U:qS\@p\ A"d\zCus!\™ % \׹*L\\׹*\(C\v'\x3U\t|M \S9\ͷrP \W5 a\E>y !\E>yI\\FtO\êD\, \Ţ-\ƑBpEs\0|]ԋF\|lv\OPK\b\ \%.ПYH\Z6dS\޿D \ \\ӮRN\Ӯ/\Ӯ\Ӯ\▼[ \*) \: \\b0H\yX"bo \@^ >\o  t\#O߂\;E \M-]+3\9BwM\z  t\%>&\."w-h\E\;+j \;+j \;+j|\ { -];{D] ] Ϧ] W@ ]|?R ]YBek]eL%>]l"]E]]9} ]9}K]:-<U ]>\]>̉+ ]BS b]Bth\R]H~ ]H7-R ]I^%E]L m ]M)s]MF4]N<@6)]N<@6]QK۔]T)[]TNy c]VUD{J]Y,5[t|]YW* >]\[aY ]\[aY]_xjN n]_Խ ]cG[Pr -]co/]eY]fQP]o0"D6Q]wy[d6]{{;v]{U$]~ 3]{vN~#:]X{δoD ]_] 'C]B w ]P]$pS]hgC>]dJ]g]x\1]Cj]Ch]Cs]C  ]C ]c (]~ ]M]z.S ;]145S]>IVS]X=Q]7 Tp=v ]>1+ ]>1+ a]z7$]&bS]&b]DlGj ]$U0 ]$U0 ]$U0 ]v e]>{ ]B5],0 ],0],0]%:7C]{_y]m pP]:9s]Ҵ!SP](Y;|]p;wv] L!t]+eaŒ0]HJ]e0j]V< eB]V< eB]-(U]tN?JQ]tN?]6]dؙz -]")e]>q ]Be@H=]>e@H]>e@H]o}P3]רZu]@0nj^' *^E-Y^ IR5/^ IR5^ IR5 ^ {'_^ {'_^Wb^Hk^DH^DH^ W0b^"vtKo2 #^#L^(.C^,GN i^2X_ ^2X[^4_3Ĉ\^57^8 C +^<PFFC^<&֧ ^ i ^sʊt>^wozE ^wozE ^wozE^y^r`^ ^h<^hT ^4{z^r:X[^q a^F^K ^F^t^dK ^;q^GIFW^ѽ<|˗Z^V^ S^V *^զ ^[ d a^Ƅ* (^aK>tB^aK>s0^aK> ^ 85 #^!kСL^<j^s1ns^ܦ:߇^O;}—^+ ^y )' %^y )'^ŶV`( ^ŶV`(^Ƈ'˲^^ .^ȔK?sS^ɷ^e ^e ^e^iLP ^Nw{:^Nw{ ^tf c^Ӕ ^Ӕ ^{i^S>K^٭ ^^cj^w^ GOpc^ GOpcU^< 6^{j4qY^c_Ed_؞Z_Lt_ c _fi@< 5_ >._  f_ _  _ 9_L}㰛_ Dtc $_ %~_ |5P_ |Ϗ_ u_ 1DVl_KYfĔ _|h'm_|h'm_|h'm_p_ B>R_[@S_A2} ~_y`6(S_!]?QN_!a_$*_' Τ\C_/!N[_0pe j_2zڲ_2zڲ_2zڲ_2]7_3I*[ _3OU# s_411{ r_9$hT_>  _@5[S>_@5[S _@f$Y_AR$| _Dgj_Dg _Em#1 a_K'BG m_KzJ:i i_LbRS_LbR_RX1_RC_T1o+8 _U71_U71_WqR_X<j_Z˭C_c4_c4Q _e\fdK _e\fd_i _i ,_jte_q9tbs_q9tbh_q÷D _r:`g$_sR܆MvZ c_sA2_u.2_w>lh_| _}unm_ b _`_Z6xR_P _q* P_xw- _ u4_ƭ_  _TҳZ+_9(͠_ s\zk_~\+ _E_j_ _Oag_>N4y__aV+_̸5_;(TR_;(T_6j2Y_F _Qsv5_ɕQk#_ɕQV_ݞ$_ZUq[ _+~  _+~ _r':|_r':| $_r':| i_`Ajg_`Ajg_STe%_\+s_“o \_gɯN|___M_ɯ?T _@Rdn_Ѻ3Y_B4u_k9ˤ_]Y_,Mod ,_GlϢjR_7y _ٱB`k_ٱB`k_ki@N _ki@Nj_yL$$ _yL$F_.̬x _e2B_J94<_HSZ e _'r_EY Q_[x _Ba_\9/_g!_ _iZU c_{= _o{vyk_*]_X9 R_lA#o _L%lU a _L%lU _L%lU ,_s9'`z(g_ ` g ` =@ \`F_`ˇ`F_`ˇ`(&6`کa; #`ZP`.7k[ `"5X :`"gTK`'^t7`'^t7`'}:'`'2P|`'2P| `(6rq ^`(6rq `, #t`.㉧`. ˌ i t`5'`;me`<1 `>Ԑ`FRhD9y a `GDs `J١7' ,`J١7'`K Q`K K`K `K `O?zY)R`Uz u`YU/̸`YU/̸`^CS``\S5`cJt 3`cӇ8> J`hq+q-z`i$M `iPeNq`lTЪ`yE]K`yE]Q`[e[`?Wks`t[׭`g|[ `JvO`K>`Se/1 `u =`vU `& (`&`))M`]gXe \`:C ^>`d `lX͇{`i `ϬDD7R`vw0 ` G `:-|`y;{ \`MLKD`MLK[`Ov` Qý}v?` Qý} `~D`m/n- `վ7Q{`4Bo`?p`ǂJ k`۬Y `۬Y `Js`)`-`ML `B>+*`B>+`@U5`hQh)` ǭM>`;ney`۝ vw c`Y$`ޠ~r`\iX`KvFR`Gi`ߖ`` Z`~ni`鿲  `ﲾ0> `äae} c`o>` E`HvaHPz aQWWT<a = $a E[ ,aM%? (a2d ( a2dja2daQPaEáb8(a'7a 9a 疑& ga"gH`0 a&33BV # a(4 ]a(̖a( "a*Yk0>a*La-d,|a0obs a1-D ka6CnDa8^a8IH a8IH \a<"csy .a>aZG#aGi3!T -aJ˙aK@aM=*aQ; oaRNt3hcaSE .rja\8 Ca\8  a^=ata*сZCaxQaUag4K aIM  aN=jtaɋ#a^ 3aϱ}pha%,a% (a% a% eaVT# ac~Hb4am a(Va=;sk] a=;ska=;ska":S a":Saayw%aؽN a8, a8,aPKF aIPrvb&")<b'흸% ab,/v b,m5eM b/Lb0!rti b2XR,D :b2}2b5mxu;!b5mxu;!bbS+~jjbS+~j bUk~bYU UbZ`U Nbbw:<bbegJ- , bk[ oZLjbk[ oZL bk[ oZL ,bk[ oZL $blt./ ablt./j blt./tblt./sboFjPubrT[-b~YMsb~YM b-ȼbꈧbDz8pdbDz8pbcLubc^bc2bc] bcMx&\R bQ^ubb Sb~%:'bBƄSbi bwb6) 8bmÚ{b%CAb%mDO b3mlzbtIP ,btIP bk<|6t.bcj,E #bͺb2b babV:Dbc \[brK ob|5ibn 0 b uQZNbύpLbbf@!$bŵ^jhn cbTZhbԃ1 b=jb۹7F -bN>jbNbNzۯby  \by  bRkoD_b7b_PSb/h $b/h bYDbz bHD bHD b yo/bޯݞuCbh:b"` `&b"` `b:b oZc ףRcO~h_Z;cO~h_cO~h_c Cd"c Cdc CdcbȠIHc c1c Q>;@_~>c z'cBiOhcȷP"( \cȷP"(cf.cfcfc/cR: acR: c [c [ (c5ˊFcc>cjї­jNcjї­jcu&<cu&<Q c )̨E6 ,c )̨E6c )̨E6 (c#襯 -c$q>ы c$?xc(ɥ|qc. bHc1KHL-c1׾j'c2,',Nc2- Y`tc2iL c6C3sb %c7)j?(]c7)j?(c7)j?(c7)j?(c9iϒwz]c=KuƺcA"EcB=ycCS=scDUT>cH9"  cIꎴ)Wa6cO @0[acO_W=~ cW0w:C cW0w:CcZX-pc`pxc cd,҃/cdeYۉ8 c[c[ S-cʫ6{sc[0\cBpaIc{v)6cl s cKub ,c?scIcyXfR cd=Zc \cuѹ-*cݩ}~cԨj2U cԨj2c| q acaA<$c!:屃UcJhkc2Hcs[Bv ic|Qcťmfcťmf csxjc-6c%YcߗvcM4 cUxJVce] ce] $c[ #cV!ndcfK(csvzc fX cc+DIcgCtces;ro>cp cZclO0c\Qe (d) zlsd:%d5ޥjd5ޥ ad5ޥd5ޥsd5ޥtd âHtd ~.Dd ^5vd@ N~d@ N~dYnVjdI d0;d^>dPZSdPZSd1}d1}d#(32d#(32 $dAGrdfv//"dYC[?dYCDdzLi d'V_d d d&P3 ,d& XzId(8d++tWd+[rd,:!d,Lkm#d5J| $d6e-d87؏bd9Ed;|+_ ld?63Mv d?7_SdB}N-dDoB ,dDu7 dI:QdLr=7;dMJVJ/dMJVJR dMJVJdMJVJ]dMJVJ dMJVJ dMJVJdMJVJQdMJVJdMJVJdQ d dSKSx +dU@t.L$dU Wn#dXèsdZI0J (d]{g dc{W rdgaSpsRdkd& gdlu.;dnj~1 dpD.B dpD.B dqP}(1 \dx/~:ldSo)dqA db^ْ*dPP dxֲd!Ld;d!! d1!K \d ATZd#U dtO idtO dˎѯ>dSdc}^Bd/ NjX1cd\Jd\J (9d\J 6d\Jd@ 08d#6s d#6s sd[- d&Yd{n{d{n d>=3L dN4dN4tdƿ}?dJ t d&uԿ j dyEk d p8df$rd4B\ dͳ dYzTd;rd< dɇ?8>d7hd*7l[d]dBA dՕ-$Cdս8-aSd.\ da? "d;҆4 d@W?d@W?d&EWd&EW$d|~A$d. #d)d>d )MG ddbP[dbPd6*pdg d3m1d`?d[e9dJ eZ4 6eZ4 6 ,e &h e 5n˜SerƂu aerƂuterƂubeܤ ebħ eAFeAFe$W .eGlekG e $U|e!G? e"HTBYe"HTBe"(G$e$@o'&> e$@o'& e&Q߆d- -e(o"e*>%C ve+n*&:Z4e.lje.0*seie2 \$ ue6 se>7"tR eA4iheGu; $eH`\vveHQeI% eeMqJ]eN sAeP42a>eP42a eSTP- ,eT\ eT\ eT\eTdgeW=iReW=iR eWEqqeZean ec<ee8ӱ*Qjee8egRBegegeiRNj*eiRNjei蜏5~ejek$@${ ere|// e|J,e|J,e|J)gPk ehڣehڣeUw7"ecÔ e je-K0= e! e!e[[3MKe[[3MeiRNe"-o^+Re< eO]beʐ eLtLyxe? !e~i~ eӀ e|/*p e;zxseieieM6 seȓ9eɣ嵁rteV|ec/mVet%W 3eМ5& <ewM5s s ecR#e #e je-жWeiǨhe+OteCTe *eϻMZ6eϻMZ6 e2L e2LLe2Lebfej3ej3 ew2 eL`< df - `f40fr!fMJD f;B $fCtf/ f}m#ef7gf 𷔆1fTw}f]GC f4af9vDf9 f@(; kfHWb#F fPa fPa fჄFfbP f"|tnNf#p&"Yf) \$"f+ZBf+[j f.P"f0=cgf0=cgf1zPf5c&^u)f5c&^u f5 hf:q1Kif;yy[ fh f>h ef?G< Jjf?G< J fEw# gfEw#fEw#fFtCfH`'M fJ]#OfRZhn3 fV#V@qH]fXi]֜Jf\{NLf]P$G f^vUr?&f^fa0"-Nfc菱~ fdy>fe_Yfgq fi{[Cfm~ܙfq~_Ϲ'8 fr" 7 fufv9hDfwORRfwBCaLfzg< fzg< f~2?>f+]6y=Cf5C&;>fSQeNnfSnDyXf /ڔ $f /ڔfPf#-@ f{;$OSf)yaf҄RAfόՏF /fYW~.f+8N>f+8N> f+8N> fXdk_LfC衲 )fC衲vfIR $f_fUNЋ[Of f98b'K f98b'Rf$}23ff#kff#kfoY~dfɉן =fʊG fVB2K f|+Yf|+sfжtRf5( f4 f>\>f Jf_$֞& -fDʐ&Rfᯈf>X@f> nf\"]Cf\"f\"f\"f6xfSTTff"Lzg f_%&f vfӳ| fXuZf&7;/Bvf=2g $\ gW /gTh gVƥg.@ g Ԑ3Jg = Mg %Z ,g %Zg 'Bh gC.bg9g>6` , g>6` $g>6` g>wѐ ig>wѐjgc׻SgT:sgZlNgB _k g# }esg* Hg,g0K lg3+z71g4-oZ5g6](AbJg;(ոŧ>g; 3wv g;;)8Ng=BD1F ag>HP>gBfx?0gC/,5 @gC_gG4 gV cgK~LgM|!`5gP$t袸;gRhػjgTX{әgW^h%:jgZ|4ɉg^,!g`|1Xusg`|1Xuga\6.gavxRqQge@vMYgg ggE߇gh:Yghgi (goh4gsQ - gtʻ gz>PT[ gz>PT[gz  gE, gE, gE, gE, g9Keg #&g\^{ g[6wgֿ~c7 g0kagƭ7 eg XgTKm, gTKm,sgKdsgbe/ (gbe/ goJ g PQQ gYW} i g-g*+9hjg*+9htg} g} g{/g0j gl71hgl71h gY]gwgJ- ga9;Dgs`gqܥ>cgfM gj9iO{gsar g]T볅gdܫ*gLoen vgK>gٳhg agɒvn gʄ43 gof}KgBHUjgBHUjge^ ge^og.MgsЪg:CXg;N gRJ g^|gmk $gmk g@ZUWLgPМ&"g"WИjg6Pjg6P gDDRgDDKgʌ8g8W-ejh dpl' bh ؃`iA Uhh3֖N7h3֖Rh5ZӦ h5e2h6|0 h8:Ӥh( !h: BOx ih@":hAfoRhD,nhD(jhE91 z hE91 , hFe*CD ,hHPlkhK(PE2hNL` hP?ΦNhSsth[ h[PDh]Q)kyjh^Bȓ chdfW*thoxXx>hq76 hr?\, \ht, 7ht, 7ht, 7ht, 7ht^ö h~~h~gnC=h0cF:haRܓNhshshJqfRh>[hSYE"GhJ<aZ*hJ<a hJ<aah`Oɼ hN8hm4 h4Av h͂k]hSh=}h!nh!n9hƃKhƃh㖘?h]dhZғ"hVD+HhF1PQfhE8hE8|hE8hܻShN5hS'MhaRihaRhaRKhƣLĎhȆh u)KS h xS!h"`: hߴ3h4@>h~ڴ{h{ʜiؐh@ -h)h"Xl(h(i T\*i کA if) $if)iU'-ilѕ:0i|6 3ivWԲudi(I4(KiIJByw *iѿ ,Vi W/ i )nFe-i"UY) i#` * i*'<% i-sG ji.]bni.]bYHi0ׁeHi2h6&c #i6?2\i=IV,i?:Di?:i?:i?|R iAD+ޕiAD+ޕ[iBv]> iC{/AFiK7@ iMiM% " iM% |iTɷiYk iY}a#i_F Ri`Нl* ei`@wi`@wJicZ ifwB*2 ihO.ijZt iq0 ir: ivQwWi~{NH ip>ivSixC iBiBQsi`Zmi յ fi͡MT -iϵi_Xj i)/@ti)/@ iM{Y  iUj 8 i5VZ:> i?ji0 i0i¢ iQzaM>iqSi- a if $i4Ov iFW)"i& # ikt9b:i.щ -iP\:x +i6>N iD ,ivi:ASi!4 #i!4 ciS>ibdui貱ERR imji~eS :i^`i^aib} "iDZҜ iԞi׌ [i% iTAe:iѹv> iDiDi@fC@bi@fC@biϝ,i/;~ Q%i/;~ Q ,ic֍ i! q i(uÁ:iF;iU3is[yC0{i&Ȑ* iK„ +i?.I:DiA OiJܳi툨˗ i툨˗ziFibiۯiG iOfieOibp̖iHc2 i)iHc2>iHc2 iHc2 jt/J jϲ}jWw0jlE3d "j Bxj BxLj'eY$ ,Kjo;rd j'ƌ Qji j#X#'j)w|OYj)D^L%*j+e\ӽ@ |j,aZkvbj."mc|j3Ԋ#s j3Ԋ#Yj3р j4!½Uj5,> j7{.a5j8w[oj;x? j*ď;j>R1Rj?YjhsQjhsjM2j26lkjb-krjJ<#jJ<jJ<jW{AejGzc M $jGzc M:jWJW hjY0jY0j<1jmvjSO j VxjphrD#tjj I}Sj;w+jj߮>vj|tjSjjk*Lq ję+b aj|C=j|C!j|Cj|Cjš) V# j?5Yj5j. j. j=! jS׍ʣ1tjc*z jj)cW0 jfN c j>M$j'Ҡj-YF$ ,j-YF$ $j-YF$ j-YF$ j-YF$j4"jzMDj콖*sjCOjg j^oNjsS?h j ޱk_ He˂ a k_?9Wk_?9D k5:k讞bk讞 k rk i 9k Ε0ENko ?1kX#E@kYˈ#Lk7>kk cbY"k]k s{Sk!І5/ \k!ɠ3IXXk*tVAt\Kk+hG k+;l^}-Zk-Yjk0u#S>Ixk0u#S>Ixk3bI)&k3bI)&k3bI)&k4A*:dk6 k9-\n?k9 9k=4ikC@5|8 kDlA1kNk1 . kNM6 kP%Sav2kS60KkS60R kS60kS60kV3X{ !>kVUi $kVUi ikVUikVUi|kW*zRkcm} kf^v`]Rkf^v`]ki kmk\ koznd rkrULkrjY>kujX͇  kw[v kw[vkw$gcz>kzq3e)k{ԙ#gk{ԙ#g k~q*~!oLko ^k>a/ k kT; kT"kH nkjl kjl]kRk֫~EkE8k$ U k:k::k>8 ik>8 kg]GwqfYk˙d^kKkKkpqq(kRk=0?x km!k*sk/Ah} -k/Ah}kj}Rk!!kĮ'Pkgk8`Wka2rka2rk־]k{skCp!ktd: k״)`k =*k>@kkAEkGk` kGk`sk `; kږ0fk Ckλ|k `@^s kU&" kU&"jkU&"hkG| kkiڊYk'2Fo.kR_w olэ lk.YwX ldNP8O l>lP"l \l )`o al!eC3ZlWڷl36Dl'VlCpl; ,l9xF~lZIvlO(vl"'07l"'07l1Σsl):b2 #l+\cl+\cRl+ԞЭl,P rl,r^l,@!Sl0' 1l4 (Ԡ l6=9l:zxpl:zxpl?#+ l@0}G8ZlC[0lDAA (lGfqlN=L8[lTS[{1;lXD lY~ p[l]f;l]^, l]^, l]^, l]^, \laK7NOlc*ejldi">lg9C.I glgS@ vlgS@ vlgm alj >lqIJ KlqLK]lsc? lt2lw* $lx~>l}FRlz lz il7&w@l7&wj"l7&w l7&w l7&w el7&w l52l(o\$lNfdl ~ݦ[l+B͋lib5+v$lib5+ lib5+l1Q&d`lq elQpRl`o0 \lN6cp gl.ҡll-`l2M5k $lY2# Zslշmulշmulf>V. l8 luPܷ*l-Ql-QlqCdul5&Hl?leKl+@l[lc̎Qf>lNkTr3l5Kly,Gǚdlq xLl&cl&cDlըä* lq7 t'lsV~=M lOZlOZ lOZ ls>lSlyYdLlLel +lLelslLell76l؜sl(", il"#kl)eNl</l4Krl4Krl4KrSl8}dSYl@B7%l(d> l(dm6m/QrAm{"(>m81<\_m>/Gi&iLm?*m.mHp6 cmH-omImjiOe 9mjK+vmk,\3ml]$mn-xmnD*Mms]RELmwҳ4|mxhy$ my[pLmy;r"Rmy;r" m}ck6dm6N Am8/mFZmHId mkAkSmYj mnnQc> nnnQc> Snp#;DntPuzr\dnwam.;n}P\NĊ>n}P\NĊ \n9`t \qn9`tbn9`ttnk_@sn"XU Qnfs$dnt}/x snt*W nLnw k nm&=,nvg7htn)%[Nn9n  nV"#nC \nRin!*PG% 5nXië`+nXië`nXië`L nXië` nXië`Yn Snh"nI RRnb=~n̫y9n}o Snr2n <n < mn#U "n#Un["Ӑ enfXi1n gr2 n gr2 n/kDn󠣷d n>n^vsj:Sns o\vo&*0޾Uod,RoZHBL oo+4 o^+XRo!$3lo! o"O\l o"O\l \o%|o)1o. O ho0kX7 o1,զR, , o8ǀ "o<`ajo<`a o=NJ)Nho>s.@o>zQoLP"KoLP"QoMئE- oOt":\oO4oPȩIoP/oXWo]I|ߵo`qFWoez* of澢2Koh0QokM cokXoom"ct or뽗ot܋!U$ou43 ov|q c#ov|qox'BS ox'Box'Box'Bo/Ap: ogґkobBoP7jSon> oR?oc[R o/Fx o co,8oom'Ro\o\ omfo8. o8.o8.o8.soJaύ a o^l\to`9)=oRK>to E$odSoab eo=W$oԷ5ioԷ5:oԷ5RoԷ5S oԷ5oԷ5oT-oO5o(G oğ*p1K|o 9ox,9soʹĶVYo˛ocgo̵/oVH _MkoTc oTc o8MݣQoغ[S;o $^|oeb oeb o鉚/B o/d69o6odxXo yo yjoxw oo7oo'ocA|Wo//Շspry pry p̒\p̒\Up3A%pW3y@ p pn6 p ůZp ůZp _ xtpoupr pn bp䣵 p#x1 #psR p#6r pkdprp Q#p1]>p2lVp3gp6E <[p8#p;wN* p;> p?=. jp@ NpB9" pDO0G[pGV,:pGV,:pH ZZ pKS> #pOyxz pP̪ڦ\ $pXMW7kDpYdW pYdWp\Ӝ^u (p`Eu۫8Ypd#)*api} pj>Pnv -pkK1npkz^wJ (plE`plN/pmf pnc0L> pokaU pokaLpwdY/pz kmZ %pe#jRp~?. ep/fm=-p;Bpp.H4Fp1KzppvyvpC~ pZT'3pt p p\5oOp}pUT pUT p M]p M]ZOp M]L+p M]p M]Up M]p M]]p M]pluDDplRsp7X]pL) R pL) pu+|]pi5W@ =pą/o pĊch \ tpĴa pĴa pĴa pf RpƵS pƵSpQr4pfGIt pӰ۽s% p}p)=TCL3Kpצ ,pI pkTش pqT;p~WLQp~WLp~WLp~WLp 1$pV^Xp1*}G p1*}Gpo #p$O|4 pd`H)p pWj p kWLpEF,p?b $p?bp?bp-9q)q q]/-$q8->WIq<>q N cq 9fsLqIVpڶqOq!ys"q!ys q!ys ,q"''q"pq#&>q%Xa]q&|1I>q+,u-q+Y[f"q-;l q1[&6)Hq2e\0>Uq6v̧dq6v̧q8 (#q;~צq>kY qBJfB qE ޷uc ZqEYk! tqHWeAqK>Y]NqLT#zqLζp>qNLY% qO ~n3 qOIX3[qOnqO}QqO}K[qO}JqO}qO!6 ^qP< >S qTIloq[@>u1Qq\̊iC q\̊iC q\̊iCqdA2QqdA2NqeJ*- -qfGx qg:*[ qg:*[ qg:+Wql֡VNqnF Ig]Bqn[#qo#bYqpi#m qwP 8 qxxI԰qy-u5 Nqz}lq~X`JH q*q͐ 9 q[l{tq+3հqY' \qa(]Rq!*At aq'~ɧ&qmZqZJh qcr qˊ" qˊ"tqyZq9ʔۻ fqp&]D #q9nq9n ,q9njqg|HqJpO"V q3t\Eq@G?:q1Wzbq`q)HThq×A9q qtqi^9+ $#qi^9+ qƒJq6qXq\G[qqeq'f% qKQWq֟di#[q׳6E4 qeX qeX>q؏‘_yqވEqܳsvYeqrx qs"Eq\Pq$dC q#tSq\(|= qO=:VRqA]qg8vqSqYrw<̖ r1> r<&4r2HuOr 5Kb ar9?|rϒ;!>5 crϒ;!>5 #rg=/@F rx.lgMr?< $r[.r r /(ct]r /(cjr#1^ O/vr$'֪r$nc"r(?Αr+!p+ +r-P՜ r.+$ltr/4( r/Lr1pt jrr? &23rMYZwsBrMYZwrMYZw , rM߼ rVHbrXU#bՏrXU#bՏrY~LDr`$@] rc#C rr.IWշlrr.IWշlrr.IWշlrs^ypruh2 ruh2ru$ 6 r|k r|v'r~ uC rӐr>WF#rD5/ rD5/Rr}s # r } rxrxrxry}0try}0 ry}0 ry}0Y rՑ/r .+dr}BrAz rAz re'ܿH r0` SrWr%X ropropru ar5;irR2b rpOnV"rpOnVrpOnVry.e{crQKH brȈ2Fr;PZ#rɑKFX[rɑKFXDr63  r_= rϝ5&QXrkURn r\)rךt_(rׯ.yyr؆ͼSrن_}3i>rMLrzj =ruK{eCrhKB3>ri r*|rJ-"r j6CrFZqrJ ;$ rJ ;$rJ ;$Rr[K5 r[K5 s}9# +s ssF9,UwsLO%> sLO% sZc>s Φ+$f )s4] s7S "sGks^y sOr#_J nsssM7o s!2a"C$s"Fs+Rs(G^B>]s(G^B>]Rs1Nlss6"*O s:.AeUssbv_7Lsbv_7KsdO>| Ysi+k8>sjSSssto ts"ΟsBk(SssT[s{~(]s.x@ s~c\ws, sio< sP;qs:fO2sRszh.sۧyc $ sgϽG,ss^eds^e `smT sRoi s^$K sUG-DsUG- sUG-s^ cs17{ *s*4sqJOuj sqJOuss̮97shsdsdss̰es ~s߻|-scs1B!$cs^J"Fv$s^J"FvLs^J"Fvsq% s:~h{ssFMssO@7sW js&Los "*s c!ItE it2LFtαFt;ACttmCt >v饼t [| t St ^$>t~sY bthAЀthAЀt6 t i}:Ntt&aat.Iw t-V=xt1, nt1, ^ t1,> t:{]t!к!} $t"$ycv>t%dft'?`W't'yc= \t/\4t1$oG_)*t5/.I.t61c0 i t73}2t73}Yt<n/tAx$Aoe tFtttUXņy t_ i{ct_aX t`J̠0 thb5 Qti$ tjWÜ}tkj tk (tp./Ǔtq/ Qts@vZ:t{p |t~ # 1t~=to1ZKt~~Zdt n Mtr ǨtvANtaK@2trCCEtWstW ] tW ]Y tg>I tQHkt󤲿zMh t󤲿zM t󤲿zM tVH/;>tYGڮ~ tYGڮ~>tC & tV >tN4L> t6F6> tP) gt{iLSSt{iLt{iLtt]84t[޻JGqt.s܋p: tL[ㆢ[t  #tǺuZ$tݿ Ntۭ^]ta²tftԍ Ttz2 tۄ8,t)` $ tl 8YtߎV? tc c1t7x tۘT@ktQN twSx\ ,tkt2u[ t2u[tp4=t/\ URttS tltk9Et)$t)t)t)ttt@(S=0 tFt=9 \tsQ urU_ a u=MSu?S% :u )>&֟#u"6j%au%@eEKiu*FP c u!i 1u>} (u^u(W snu˧GD u~nu鐺 J4u鐺 J0u^tu^t uQ\ uR u— uizƯuizƯu"DŽ|u&^} ,u&*Su)*%N u.mU!u2/3u2/3su7r{4N%u7r{4 u:Vqu;)hq u;)hq =u<Zu>XWGu>(bolRuGL,PuI0W̙uIfM!uLfIe)ZuO}֢JuQ >uWyP%SuWyP% uZ- iA%!uZ- iA%uZ- iA%DuZ- iA%Ru\ɞeu\ɞeu]Prsu]Pr u^ ZX u_0!vaua ~iucnl*x uh_uhJK^ uj VQs uj VQ uk91csxurjusg"NuuGZE8>uuGZE8Ruv:Q ux=wGLu{WvDu}ARBuF%JYu?tM Nucq|6Ru3{z2duSodԭ $ uW,x;u+%{ u@+_;|uwuƒ!u*V?ݓ uWut榿s>uđ}{ueiB u*Z u'r u}V k u+&ZNu`` uE"UYL uE"UY] uE"UYZ uE"UYuE"UYUuÒ [uA3* u֫SuCuym 9uޫ&& cuSG u Vkafu7bzu'qq u(; ukr ,ukr ukr ukr (u]1u*cuXD9duXD9duAvR  ufa'Wufa'rufa'>ufa'ufa' ufa'u, uY uDw%dv%~J>vXtvXvz~hHYv ҧvA_ v wv ˂9UGv wkv F,v\+Iav/|`uv&m6,;Sv(i{e v, ƒ v,L v.k v/dD7d v/]Ltv0kzN0> v3WD٧v:Gv;=v;=v;=v< v>*{KU v>*{KU (v?5A!vv@xKvGe  vGe $vNiW.vR vUsЧ0vXo+svX KvZ!Kv^Ę v_Xisfvi/vj[pNpvj[pvkf~>vl~6kvn;ZyvnζA[ vnζA[vnU? voSltvolJnvr@ 1=svr9oudvsbQvx6j 7*vy2v{Eev{Eev{mRg v{mRgYv{mRgv} jvA_b vkFe #v/RZ v/Rd vv+jv4v$ vfh a vfh ,vfh vFXvGf[s v:ĉ vvFXu vFXuv3Y@ xv GvPэ-vvô)?jv&ھ= vy}s "v=Mu>v|!#vu(+ #v1h tvS06,v1Uz fvq=;vB2! vYJ&2vOjvV#v8&$vMvɦw3qAjw?.:f_ w?(!Bw?(!BwB9sRwHlSjwN7-G (wQz_&>wQ"٘o'wQ"٘o%wQ"٘owQ"٘owQ"٘owQ"٘owRh wSu wa,ܥywa,ܥywcs|K +wdFB`we\=iRwe\=iwfһDtwkf({wlSxQ|wm wn `Y wv/D;kww:ZOowzXm]wzXm]w{vǙw{vǙw~7pwQ$tw^lUwPε4w  iw swK_WjwRf w f" \w% w% iw% ,w% (weuyNw: w1`3w= FvwQ i wQ w)%_I4wKDwW|,Yrw'v,wʯwjFNw[QPw[QPj w[QPk w[QPw !Nw,R wf.~] wqLݣO owDwYwոmCRw[cGWswЙiCw_I ~Jw1ow3XKgw]\&Hw J@[w+׍zA w ! 2sw\b0w |Ծ ws7Q>w/Z2dWw/Z2dWZw/Z2dW]wɑHwG ~Nw*gz;wT||< w=-= ,w4ٶ w#1w^Yxb^b x ɂVGM x TfYx FH8e\ ,x BD@* x%U6R#xh, xxa lxflxlDF)xqNR{efxyPh=x +xz O>xz O>x{Cw#x{Vwx}7jx~ %x~ %xQE6NxQE6 x*f x*f ix<|9xm%L xm%LtxžsJx3` xeW3H xamxE xOk>x1;xӺFxNS[@yxecSx>xvxxvxQxvxdx쉝c&Lx`p;hx`p; ^x`<RR xD@MJ ,x>&d"Gx,4{Kx9S  lxuz[x-Y6s +xͧ}axͧ}xͧ}Zxͧ}Rjxͧ}xϣDlݏ|xQRmxQC x~ x4Fixšm0Kx^>xc7 ixxdZ.[ x1x}2.xS;x `Stx `Ss x `S x26xx/5* {x13TCR x[am (y1,yfUWNy/%yh\>y {{`>y(÷y86G:yYo^yvb.0) y5}y5} y!#jy#|Wty#5k !1y%`| - y&(_Dž (y&`{v"Ny(2R y*%d! y*%d!y-y-y.n}/By1DJ6S>y1DJ6S ay1Eay1Ea (y24'y3ٮ)ay;v5|yyTٸ|YVyU7yUv܀ yU0].>yXTxҵkyXTxҵtyYyZԧ\u`yZԧ\u 0yZԧ\u i.yZԧ\uY(yZԧ\u e!yZԧ\u y^$R" yf,}e0ymgQV#ynJyn+Y (]yoS= ypWwyrQ ytC!E>ytj`>jyvo@jy}Wusy~?Hz2y~簱y~簱oyVVy `yUWp% yjه, yqByr@sqyj۳b? iy3SNy R y q:y{ l y7 ѣAysϦ%ty`/Iy`/IyNaZyNaZ yNaZ cy(; y(;ytr[y0:d ycgyy!yyndM~ tyM y.Hy- yѻCx0:y\ m.by %#yG yK:SygbJyʛ'ꏟy#  yͱVIR-WQyͱVIR-WRyͱVIR-W yEyϱnh!yǰz ay*c]y<vyu‘MyB2yB2yZ jyQipy֧w]DyAV@yk9vyۉS typd Byn$yvjy)nF yPas. y|ʮ$-4#y$zKFzPtztz k4sz &T/.z`EUDa z}y={ #zV`zt<]Yzt<]bz(;m[!zlyhGzlaJzº z!Qfb=z!3S>z"L! ,z"L! $Zz"L! z"L!sz&(!Qz*_v&@ z1"vʻ[z1"vʻz3ώz4{N #z6_0z7Vzlkz<)l׶[z@zzA[=zDJi DzKU]zTI&RzUL;m7zYK᭧VNz_St4z` zfQdzh@%=tziɜDKzipBznj՟c zrXwKzsةןzsةןztzum&Uzwfɍzyc~w% z}TAvz}}oz~~Gz{(x sz)z=ePI z=ePIszR+ sz[i5 zAavz׺jqrz ! z !zzYzY jzYa2zYa2QzD9aBz߅/C!z}4,k z} }z} ^Pz): zƔ ,zƔ $zƔ ^DzƔ jzztz~v|tzai0-6zai0z@@/ azڲ "z,{28 z 8Nz 8Nzjτ\ hz_KrD=z_Krz_Krz}>|zE rzz! zeկ4G cz|Ndzx6kQzl*>zƎ CzƎ zF =(jzȡx( z_Brz.2[ z.2[z%*DzG}U7ztztD@z/cv z/cv iz,႞;zֳeH]zӻQ?P zXx z\T] z<z *QzqzC_ z|>z%"Czjz=z zhpP mzgZne{nE {&fK{&f {\!@{xgS-xu r{ g#v{ g# ({ Zv{ c{ qWð[{gx {w,{>9{> {$ {7?Kk{Ņ&b {Ņ&b{j^{b/ܖ{',% j{,Ĵ{,Ĵj{,Ĵ ${.@0{.@0!{.@0{.@0Q {2 2=Y {3""!{4̯dž;{6Ȳ{;yRM{;yRM{>75UC{A̱ #{BP0{tf4} #{y^ c{}UT!Y{9t#{c{ix˷ {ix˷R{] {֛f{Ag \ {\ {F9S5t{F9S5 {&P#` {&P#`v{*uL{_t=3{H{{ ({Qmz#SL {Qmz#S{Qmz#SS{Qmz#S{݄3_ {݄3_{i/, {i/ e{vNy{\{ {P{)kt {)kt{)ktj{&qpU {C?!#9 ,!{hHl ({4+x {daA{[{enD -{Anj{ ɱ_{AKWZN|gb) |۞ |ԡ| g| <"D d| ~,|/V|8YEqL|:l-|:l-|]Kp|y{<|y{< |WV $|Fl|;eGs|;eG|> |\]<|\]<|9/|9|([|-`ߞ9Z|-v* |/[lB h|5gA߿ (|5. |8ۗ.B|9T_*( |9T_*(d|;xh[2 |<߽^0I |@akPZ |AqEW|DR)6|EW" !|Fg| !|H |Hk 5 $|I |N*&ܫ|Pz<>v|W=d|WS/K|^jkɈ |a<&_\|cI!3|cI!3j|f,0|gLy |hޢ |mpXk |p C||p:rA|ptq |ptq |zOt|{R|y R|`Lj |~4v|G |b'Sf|yvn|PTyZ ,|{B#|{B# | |?Zf |F|tZcX|eF>S|I|]Br .| aI||Y|e4kB|sTj|sTR|Rixr|FS"L|Vd]j|*-6n|w|4f]R |.R|.|.8|.|. |_ժ |f7S^|f7S|f7SZ|.| `EC|aK*/ |aK*/9|‰Fu |ï`A~o|,# |,# |ĸa|"D/r|A |2|Z;Š|Y |rS|ډo- |ݏd1G ,|ݏd1G |ߚ|>k|<N|㠝N a|㠝N (|晼S c |F$|F$|,6 Y |\i(|\i|\i|Rj|O\j|O\$| G7s| !x]+|ry`:|Aq,|&n3@ |% | _|-|t|osQ4|os|os}fO}B}"Q}9@; }!}(z*b }(z*b (}(z*bj}(z*b $}.A}f, } +*X}DM[_L}A }U }Y}"+qޜ: }"(#ɮ*k}"(#ɮ*t}#; }# <R}$V})oЫ})uUYs })i})iY}*Zl a}+2TS}+]?uj}/׸V}0r^2}3v@ }7Arӭ }7١y}8mBS}9ʠ}<\ }=*V~ }=*V~ }=)e}A[޺}CZG!#}CZG!#}E`s}}F3Q; i}IA @4S}J+!s}O p}O pQ}WYPI1` ,}Y}O[}Y}O[}Z{ΌR}\gm }]u}jiD}k"׼ŵ0 " }nH15 }nH15 }n*t}ob}sRՎ|}sМKd}wOjR}xOں N }y[r= }{2aN`b}~Yt}ޒ] }ޒ]K} >8 } >8}S})7z1O|}>l}.=@}J}2}Xa}+c}Rxu>}4_ }d1C}d1C}7 Y}\0 }u- wK }0-Q}hkx } }P $} ,bd}@^P+ }p\F }>R (}Ei^j}!gt}}~hk R~hx~i qy| $ ~i qy| ~n+o:C~q/u!Y? ~q/u!Y? ~q/u!Y?~s7>ggI #~vW5[~w-7 ~LgS[~WlI~ ~E݊ ~E݊ ~E݊~xfd~Cq ~tsՊY~QmK~*<~*<]~*<~?؂~L~! b $~3G"~+T "~WM| ~9j~RPj~lO,L~H1ҏF~̺<~~)֙~ ~B] ~a$'vƽN~2|jj ~|~+& r~; k $~!O1贂v~OoR~o_~]%~Q/aa~<~;~">%~">% 6~hX~g@~g@d~^Z ~y,0~\udrR~,]s\~48Mt ~g[[~h!~L~; ~i'T~ŶrE~NAd>t ~ʧv~˚(I~PHLjJ=~VOdF ~r6=R~͊^~yӳ ~yӳ~j~wP ~wP ~wP>~3~ع\{~ ^<>~PeD ~~0y`~g ॾ;~ 1S=mp 5/n8xk\ :C JXsWF7p XaXfZbZG$Yh){$Yh){R )! s,[,YML-,[,YML,bf .[ܞ+4jY7W4jY76g cUA!zRBt+r"0DMOE Io .N0ë7S98BS98BDS98BQ S98B S98BTc{ hUyFYcZd> ZdjZd ^SQn #^SQn _ 7)s_駲2ea> % `b㪢x>b>cl.tfW6YSh+m&nְ mnְnְ nְnְkpcFtlpvxiq^ns&# s'&E% s'&E%tm};>yI;z_ m{tt|QЀ { Q H s*|  x U-7_+Chal toBQ oBQ loKs Ne(je( ٳ*U}R!f C)1# ˷ j/+u (J_ .N,kCA 4 }4"Ci>lrSi>lr)Ha9NWor c Z aƀbjK̼z)*> ̼z)*59Jm% Z hyҞڼ؝*aȉBzZBzZUBzZX(vECݷ_g @#gh/ho#]Ws #]WBn`GBn`G⬵|/R ҔoC^Բ cB idwZQ"ɯ+9 ,-KDj>0x2\?>JٳN>JٳGs L LhB|N )D Pl#TS VĨ/A _q Ya_=U|!bIDf_rgcjJA*lV5ݥpG`GqS7tvt .tvt .u (l vKwצ'os zh=]|3 }#d}^ {tڍXˉbC$qxbTd>.$FK>AjjZN4@{ 42齜>aO'gv5454$L y $HV5R;]#؋OP%P%P%ğ w>A ³V\G M9qֵQD-^մBĝR)?4jBcԡEƎ$4ij2. ttsF4x0707Жm. %T F D7 Ri;ׄzGZBBK=:cU3:ZU ," >F9h VwYӆ=? !K,=dk_>i= ;` ds7 ` Po a \S[ ȽC i ȽC  i K iJƑ~ %.X3~L>`>tԝqrW;Bjd_DBBjd_-RTR| # q\"o: 0KY$@D Q2a!A, !A,"gj#cj(LKd)[5:*H\p(s, -98L7dUY9AP9CLF;O'9Y ;O'9 ;w6RglR glȢ N "E?60zP%R$ GQKZMF>1H7[ 8JUtUDenr@Os@OsbGKm&_%J %J FbVWuXX kX ,:X X eX LX X XjX ixD cp#W>R+h8 u$j1dPe}3ZoEd e%x=ޞ%n.%%F[!c%F[! (1%F[! ,)%F[! &J./&Pe|C +;/C}r>/C}r s0 4]Y | cz0+~* 3 ~* 3&N r<&N r eJ'(mEϾz$ xRz$ x4)َkZq tOңf,<f,-,qP>S#RL gy)%0'9OVHxjzr'x [ fbq  L`:>3gMy\m x޼k' v0A v0A v0A #>6\W; S/M߂>B8y l໩{K T0> $ TO \<ʕ׮<u;)S u;)Y *wM39 ,s! , {/H ]1Q>踲ijNT A?. 6S o+[#QR%=Ȟ vYr3.O igyM2m[S<#f_!(% r!GNz"IrɹL&a '}MR(u,Ch/aiy n1a6~  <7T0=EQ+{Gx@ Gx@dS4#m ! Uz5A=:>WU{j cX,m3Y@ ^׳fva&& f <:āh)BBhju3jXͯ l;K vUav`Hvyi qyyS a ySyEdS{̿L|0IIK=o .|򉢔A|o#dHkK="؟E`&>y $kkgX4 \/YsՍ[; Js.R2ZMT (1{ i Ef rwJ^Bo^db1KuOڴel_%tZ1sq+>c>J:́"<7g a DR yL6'kYU)b:QK S{x ,7S{xs#֖5Kj x7j x|Ӵe&4Ӵe&4 $ n[DRm n[DRm  n[DRm (  ;b  ; lIVNyO> _3(t8ę5cf& a)s>/iiR=S=S=S3 ^  i*[lk)v^6:TZT2s6Ś+4kVkV@j a]?%_b  THK e -  еB co/&oSx  c -zMw|l1)LםY (!f,b(<ʣ._/^2?/q5e0 R6lpDxr 83ǭ:>$ \>:|>TL?^$>?^$ AbY EmQXK ^EmQXK|Ft7sFt7sGxtt$GYv@NJq^&|Jq^&|KM_+ ,Nڂ7ZRNڂ7ZQP|$T<8k% Zj U #%bzU eR  kY">mZ{ת%pa /pa /Nsw cs+vins! xyܬ ~4t #~mN -t*ꑞD[EY~w eM ˿w # \n dKE QZK!E덍R#Qλ R#Qλh2R4J^ٿu?k}t k} j: j: +( rKfQQ$6y>کz"e %  m{~Sˆ-Sˆ-s Sˆ- Sˆ- t=RDž#e*s@7y%; /#[CʉM( cF"q NS^K/@79OdTJ[z_ `7Yc c^dql \qѶ L {_* TF?(F?F?9mKmt^c%;jk>%;jk ZL1 (R s!'Y5s!'ts!'jXF1#]  pn d hOs S[P"mrD P Q"  ~p\ 0;)" " SY $䄳%`;c<-jP" 5ăV8ӈ :8p5P ;߇`t( s=yVZ@?@ C>M FA; +G EeHQw[I̮nI0 LD' KzM#6tTlIT8yc X$y9YSޏ YSޏ[C/l ^_Vؘ `# !R`8lc~AM i dE6rRh΃1@*vg\* vg\*y0$\s y0$\vz(&/}t c|'VZ\1 1yq6AT+H-|%0ib0iba0ib-0ibR0ibZD wj  ~j16~j1j&q Pz"jk c BF{KQVʭ_ ;\,R gZ== zuEhM hM+?cwPa]kDv$u ( E  EJ΁- eeػ+yk !/NIү4 T^{;G ^> $ ^> (0§0§ C^SC^SC^SC^SC^S&B =_Uvqby딧8wL ]s0 vbyb - wn jq)[F~rƤ 73 tc5)o CAj |  VFN -f $ h$&1nN %Dz_f \%L& yȿ'(ne:N)[ ? -6_tZ-6_ -6_sz-6_i-6_YX-6_ ,1}󙅒2#kt5@hn> 5@hn>5Mwjj&51- l9]rR:yӿ;_9m#<eF,[h =@>[BAW!y( Ey< HcLD䉗Mlf|MlfP,PdÏZ W߼t X ^[ b`eD /cqcq fRjgJ6]hp !\ s ] tU&`Y|80<"t|80<" } XlR~t , ) , \`<3oQ]KDTQRB!oU_G oU_Gsƅ ƅ> > `E T+]e2e2EDj[hyxo{ .s(: `4>G jgەŜBpx Y|%[ ̂ QІ> l$dI3֟,i28Jkśv2 vs"[=!G lT(S$-C>Zԋdk*{p mAss ڭ&!9i$'XXP2I]2 I]2;%Y iv(z01DeD(:]{< ' gQЗb сpM },r ,r #(ۃ DXՠ a DXՠ $I?MA=][bB o 1 }KM }; }% } I kmzkm 3HPOKTC ? sMi!h ($xy"&1Þ"++&\[U, 406"<"5 6"<"5s6"<"5:U؂f=B> =IDf<@ކZB3h2 D%^.HrMjO NP)N#t NP)N#hQukyS}U~Lt% X2P YA&2[ T[9?N_m$`_ZY`_ZYd~Ikd~Ikd~Ikg j^aj+Ѽ oPQ[{r ~QGjwx t lwݴ #GXyh'&@{=N @ӕ@ԏ1E>ʖ= w?ޔTQu $&XNkɞ;*p9sWA!>rA!> ,x/jk( ~8#o4õPi/U -iw Yw a/\p /\pD_ M X._=pL [9)@9;s? 3 sAR[sAR[ {R `ms^k%m\qE/ >IHկ4jjk2jjk m.n iю2Hs~L 2~0JR#BK dK K R% m c8;dt8;d $:m $#'|lAf hj \> EL/| (8nYta?vv 1 J1zt_*X3>_ , Ps V/44 8RזM\}"j&kĖ9q(  ͉4 ! *R )])GVt)m]t*v v+L[RGC+L[RG+L[RGd13 -:q4G \?WϙR@34@W@4Y$~_N@)`@)`DC +D&(JX`sz N41!.NRQzl҉!RaB1#vR֎ S` S`CS`S`y;VUTYY[V<Wrr' \YOɔYiAD`RaeeQIq9gն gYCh,NLh14j1էj1էjy6lm] 5u@ vAF Bx{2; \}ֱ);B>q',(5BSd#7Jk]ՍaQՍaK5fPTй + :98m6/Kkǟ5{Cz j\b J"(Ai n@rn@r 1j ;c ")SR' \_'7 \c-e{ bǗ ģ'{rۂH[%ѯTJ dC/LBb՟ehq Jک2 Y ,ےִ?c ۱qբ"ෆC=b ܐ n|\D p@2<ƼƄQ|@bY=oP"XT݄OnT&HE 5vH!gTvڰ9 RY!xj!uq%W: 3%W:>%W: i%`f3% "'A*@V]s0iHm3R0iHm32n=$6@ m8CU/V9q.F9AT=q AT=q BbHF{bMG؃4 G؃4 ,?G؃4G؃4jG؃4 G؃4H9y H9y>L]RP} gRx*.o SO2N UOZN\?mF1]Rjab,G>cW7߸sdE騂QdQ-#dQ-#dD hzMoH eqQJt&s&%ur%-Ij v&vr>w {w {w {@5jc ^|Ygj |Yg yd C69[ Z&&ĵ[6 'p.>P'p. 'p. 'p. Z~qt Z~qk;ÖY;ÖY;ÖY/ݣu /ݣu#X % i#X % ,ը5A谵N =} cA%0*8(9iR - 7 Y 7 kRhRRhր 9rVhwѭ-Y/ѭ-Ya-rTΩ-rTΩ'2g u>630h0 mù!@!ɬ.2 w!׉D#!sƆ 8$~`C +Ҟ3 c|3d*; , |3d*; /ԼgUb/> ԼgUb/sCQ CQ ;tf ؞al  g kĭ( !Q 4 Ѐ~s㿏30 "):Nzxi ,F^/[DA{3 A{ 1vd,/1vd,/1vd,/NQX |=S=L U5H3[t xS RWY {-Shm:B c Z Z Zv m GQ,FT EUt@^}ልa s!MS$ x]N)ͦ^g,+[Q#W),T8n \,tsB 0.{z , 3mQ7: 3mQ7>62tw048y=N8y=0=م%GYxIkfDA2Kýy:P5Ӿ R|G]R cTӔWmFX@CY\j Y\j^Y _%9<%qgV gV hIӠzjZIpltn 9 o!erZfr) ftΣ:b \u^ zD|oH>Ȉ1F#Ȉ1F$ rJ]}D 0| >BlWRB'ps Z: ioʅ!th ith SNth L th Qth g1Rg $~&<8  8+CY =~j m̥ &n] \8 j i*-7_! \Ȱm" -ʆ rarD%5Ac:՝_yԳhCS>ǒ eB B PMqM>ݴHdV7&w([Lmx`*{|k7菆E$Cg.dI׹[ l|3 %ɆILh' \S]w 0lBGmBGmD߿4_ ] ]N cRk -Xt>%j]|}KFDp w.e ,w.ew.e ^ w .Kߩz.Zb .Zbj2߃8j5x\s57,TY #:'$q; jɝv; jɝ WUJ 3AL]G$:ieGR>IN>E>J!RfMJ!RKnz\/4I QEpgTQD #R/?|SsS]Ӯ^~]xS]Ӯ^~T 84\^4 \^4^#W _b_ c= .WhWjDC kRm$DkRm$kRm$lӁEPQS lӁEPQLxYN Nz߱ہJ{O4t|gI}hh|gI}h~x6bSY6bSa34zW>a3v-XQcD.}$ D.}$ D.}$sZ.(YZ.(Y :/ӊ)sHh| R  > Q3z'j ^ M Ms B`2 jP lV>/ Ⱥ z4s6{Z{Ob& $ , ]ֹ9 ]ֹ9jQ}  i  > =@ HT{  r?C#!} %ex<жR(;1H; (im+Ԕ +Ԕ.'p:1|_v3׸7 6 >7i ߯N7kIuA$:3d;k]AyB AyB F+#wM> GO2$HhKѢ/o %N{"eS ~ǛaVhZC,:\-B bGOr` jaߋ jaߋkZӠjlsro{OMbho))'o))' poT\qUp̠ r@&xu>rń s28t=urTJzx(۪L|аHmt|аHm \|аHm a\|аHmb.v&~n  6vjlK K[hd"y:ȬV ȬV>ȬV 1ȬV = ,#0KoZ<&H lo+ K oB% *; E )Ǭ;"SH dLjWz>N9J# I c+z+z+zD/|OxN?almj9>p bįk^tv 75 SȮOMPJf[D[ rvժ u:C ޾e?)_޾e?)_ ( J;u \ u u kG' /Dw+o_F .!Q>L6܍ ct!q] ~TE 4S hB| 4agW; (Һlnzz\ 4} 3Jz /⇼ ,n  a_VeVb̼>U"8L4pEC0 c],{- g8j;"! Lc_~Y!hk!4_"W %jD %j'J%Ύct?0Or?0Or?0Or]F]w0 K_N GxVq [ \2]V,,dTo> ne)5Ge;O/ h_TotqZpSL{ ar~c1otr8zwБ ,wБ ,sxk7 )f-zz%vF5 ]e_f ڿSLI[/~C_5&  -k -kRɮZ fD(K6B؜ƹi m],ݳT !7v謫Nƈ;_/#C ! t  -Cĩ2 ĩ2ȃƵ6 [/8˚S5ɋ ,ѩm*˨Eۭ}j}j v}9=՘8=՘=՘fIbRڌ*t'sl !uQ[hRҹaX_80c"80cY5 e E EdCdCR dCD dCKl p]Rp]O1ZS=O1ZR # [jek' 9^Ӿ"" = S&Wve)*Bxu>*gE+!E$.fOq3H4qSI9@HP'R;x p׿jq%! q%!q[#q[[thju|Dv` "w2A |4o}%R h Ach> Ach i13">]TE8ߖP`>ǿ4aj=k6wj6w ih3k1 n$O۠Y; 7!oX>SJ+jF]K]V H<0RBW¿ > 7v 7v j7v jL{%}˟[m #La LaL} 0߫z0߫zT|7yt39% =Cvhۑlc9EN(.OˌבRps\1!-/>|:4Aae!>!զmP9|qX{<' 7Y[' 7 ' 7I )Xt] KtO4_$=zXB 3 M2> ?Ov.> ?Ov. C$+ - >B# c :F 0=  $ ; v.| v.| , km$x-v%LWB-?^ . x>4f@ 5@3)27N 7 2JHD<=C DWo#GFX Hn~>mYHn~>mkHn~>m (KrlWSP V2X餥+X餥+X餥+X餥+ ,X餥+ iXj [ÑK (cvb4 gRs& sjBr᳉Ksm>[x[3Ujy 2ݿ Fy 2ݿ ,y 2ݿjz] ] |3}΃ b~gh j[ @Lk <@Lk&irG dg> dg: dg avT_hh iv ^lIZ555555wq^4x(t  9k_zYmXJl|Jl|RJl| 6  6  ycZIR IQ a9N[ +xoH$#2 1010dw1,\(RQYF([ pY*F $eE $eEYAj0|a,o[-oNi@bhU ٣7S[ܱ| iE ` {o@_)8$ՄZ j 4a RPA!=ޅZ Le -6\>"G$ؒ G0 FF >%Yk.M\ :L 傗Py]/ ee(SFp rFpj0i]ttZ ܶ^-_K( OTZ,h~U6Y:.ك} / FMY0zFxa c3^뱋C/4?;G>C%>JFh Mכ >Nc \*P>QkQkR̦.kR̦.kR̦.kR̦.kXOe54[ XOe54Y;o SZ3u\殕\]_p9&"]_p9&]_p9&* ]" 3cq~wm&ݸ~n pPI˵tq6ܸ r, as¹agt=: %t M2WQ5o gYs JϜA>yrq<vTyrq< yrq< S't~οsFYfG$ ߽Y%VPT_U0c>k(Όݳ a7ɲ2pj bd鼴BTisF.ԼU a F.ԼU1O2 2 =d R=d n=d 4=d "ֹrJSB>`n 6B>`n (B>`nj>~_s^"VrjSH/8 Hs8z K wՏm  `$==fU 3>hsK C6c3V"E3/2 "E3/2j"Ԍ )#%\@iR%ݙW_(- *)S*|u *@-NpM-NpM/ހ/zc6>/zc6k0ȇ1Z 3>5Y>6aP08C8m+^ 8)W:<6Z ={T ^?)~?)?)?)A@ K"qϲ Qu8A.^S S Y\. YWM^=b8R0`UgDb6'] u#e#NP+ xfkf lz$ ={VaP{\F;q {_^K] {_^KU*"N2 nz3 $d Kݏ8U:2*#R~qx: ax@ $U>APC gгWS!+ sV*N"Z V*N"Z 1XSށZi0.>[  e[  vjgu vjg BhI FH9K pS+_/E[& ZK?:{K?:{Eg}Eg}gEg}REg}MEg} Qi-]-T? $Rw & L蠱M:?h`1q3R:">U 4/ K *ѐq%G<{-=. lM]h\}1![ T'BJ$^% (⋬wzbރzbރ 5 # > bJ h 6ȦtTj >|Ɩ;Ɩ;wg$[k GPZZ],X<{kc8~) &WnsbM`Y a ocȹS2 :L!x P]` : aOR%ӴV3("\,#*㰊D,7&y,-7i/1U5{6E.\h 6E.\h 6E.\h6E.\h7. #>Ɩ?8KcL#- ?8KcL#-?8KcL#-sBC` GOl JBa$JBLQAAC/ ,QtdO R41ѢRT- #TP8H ,bV/;cRs1scis(R9 adqӨ`dqӨ` fc bfuFfuiud jjm/QU n|ԿBSo;ao=f ~oe-]qX%3YtVKpK!u5Rvd wnp덹sy[~NES}&T -?E]HHlJ12+b?Au* ,7VWj7VWj;?&vynZ x9 0U  vIۗ7p\]7p\7p\,:jEYOYy 5=RKf0%VXY%VXsbAUՆpsSFC1Z1R3KFpŻJ!nA #N @KS Or! ѼvV.cړI 60 an;v E NFE NE N#E NE N E N<R֪ <R֪<R֪<R֪>v1r躉̡vy\Z;3.Ǜp}S$=h2ޥk}3S $~avUT5H:,Td#th%M ;Ƹ Ƹ g d  Xxk n1> \W J#g J#g vlIvlI ޡx ,)ޡx ޡxޡx >iz0  wm+*%}) &wM a)y% )y%j+iF,~ɟY,[d u.|>/B65 4> 4 >6U?8(w8(w 9d?< 9~O e9ؐ^[ ? T$ (H _h׎ d JU|U M3 SYUq Vo{E Vo{EWy[' ZIܾ6f#_d*{{>a~" } $bo9kbn)o'~jołqeA__cqɱqeb vǠvRy  z`3tz`3 }ٿ/>~7]ojUJ6>t3Z 88. 88. 88.h5lh5lPGc PGc `a W`aj=CKĽ[g$ F- U29[ z7ExDNxDRm? 1 u:Ab)(S mJKK mJK3sW:v ~:(~: (~: ~:tk` P] WHdmy j~n ȆymȆym#v4  µc! &x2 ( &x2  &x2>")k^0 +9 "W{yw Y~s\ ѫ=U : =`Yj#^/ (JC1_b>._b _b _b ( \(t( (p?b}`jp?b}` e5tph um U^q9VJ5C ] J5CG2SѥvAUR:RǕ=Y ˤЍ wKJ=R \ nV㫶DEx y y#NR&Wc++Fj) r+B\ n,t(K.P7 .!s &2UcL 2UcLL7t:B:m{,M:m{,M= %]=>=ON8>Q=ON8>C=ON8>K@'ѐ7D cGW`պL {޽35L*D5$MHgQMHg *OaE,6O΍NLBvT; (RU$  Y["aЖ -jYqYBKd\=ʚ- -\c=* `6Y/`6t `6 b Y J2 dP)dz ik-$ i[q|NGi[q|'i[q|Q kqqgƩ kݣ$z{Qn-͝Wp"=hp"= w9.rwM׾ nx ;Le gx ;Le $yp\. {NW^,h> e"8?x`$>ؗD kdEoRo;*$ >h9f&s ;&s &s P stB C}W;b o}u>o}ugBJBJ H&EP f $s|@ߺ^5r)FTOW{OI *h -)Q3WOR&VA&VARoOA>J )q%$ ٯ펶˚N)t v_l   \>ܚylܚyluMu,uu޳QBd=[)4EU> ]SO/M /IvFEv (vFEv Pk -o8/ ,(D8eZ|AT0_ScSx 6<9v8j +D mL- ζ腾 .fj U#S   ˡfv m i+ isi;Rz ]t3SHr. +Z=8(re'Y )kzK*z2y -5^V -.G2ьh32~)g4Oa4'v 5&veY5&ve 5&ve6n+GD6n+GDR 9hV (9hV t=x @ @B &pwHRDF/f \IF:ѰJz` DNx`tR5@ RNwmSW解 dU \Xegb- \L(r}^#d*Q^#d*g4s gѤ iTX &j!Yj t m:8"nO^  # rSw at, uo> v'<$$v'<$ a w/6񹧄>ylS zA:C=k7 k72i9T 7g%mT7GW eTܤ>> G%32G%32aш؃ ? OZϭ Zϭ a;Sd[ȕzz)W+yx < v&yK( CuM_sȑ Kv DBz >Td< O <S;;L# #TD   cYZSMYZZ| o g | o |~ٓrq<|Ut<|Un?iUR@n?iUps+R e AAe AAh\] )0?9☋"bF&g::¸Xq:ř$3(^)B0ޅ (M8N T[:zXl$lsk1_1rjlkt o^md7 $7s7 7c#Q%``%``nz ˒ z N+G!Ԍ *sL% *sSqE/RFqE/qE/qE/ qE/qE/;Ls 9a{Cs (J8R vGKh2*mCT -GA #,dД#,dД#H<$D2 3$ى u*~8.o$ ,/vmE|Y4pH2hx9mh>5|R;ޒ>k*@6 #@cR!KtBbjNHsHHEH-HHIXj^jէ4jk/#kke}l)k Mk Mk MqMs \rh;, yO+:ysz6 jz6z6 & vؘh"* /i|kK (kK jJQ6:ֽ_R2@w2@w$ _C!a3 LrLrLrxE/   Rvp "q"qnFR -ܫM]鮣eL"ʭ]/jΊ w# poA  (D M h~=B {j v t' ,Ɋ᜶ը-<lOlOi}&w w{&], %h>z tB[-o~Uݟivݱ+rd"ݱ+r6}N \`=Y [o(|ܫ(|ܫ(|ܫ]P]! ]{T{ {T{:q er|6XjrN K#EI WȾ q<< g 5=z c6z5P -=$LkC%`5 &]&])5ZI+oUN,4eq-ܬ3.Ԋe|}377E&:CG*"H? d)A6:BBSD;5(Dԓk Kј ,U)4UN8{W{>X\]o_HgL;4 aͥcemjcemseQlnșt>tI> #vQU | v>.Q jyR=u{Iߎ }XUJY0ܿC py>k$ʼwOGvRP^ͶͶͶͶͶr?{j j R"""" wsc_nj c i'&wUSB9FM wJYNT'pl0 vTC#*:OC1nj_R1nj_1nj_Q1nj_#1nj_7 c\; K! B3 ! B3tδG0Ϲ sc(Lĉf>c$ c$"c$>1 t!;9ziNU=-ξP$ |c v n;3 N$y^A$y^a $3&[Qn'1OZ)N , 4vK4]Вyj6e{ 7*Ny=1a >FZVTO s >FZVTO> TG ?B:>B V -JyGKM@z (LU ?A PWX $Y aZsm*KZ{ץ s[7wb [7wb [7wb ,_{7bm cbm # c=e.U. p#yN4 qW; qW;v^Uv@ (Ww$ s|[iv H={Nt! t!sgP@;v+%<+%|+% $ +% +% iNSqD& ,i=? ,i= I IIK{NQ X4")`c =_5b T0^aix 4 M _Y^ݢ?zYD?zY#?zY*?zY?zY?zYRHҫNHҫUAn  DT]O{ /> s3 ι;Mƍb| \Uϭ TQXuQ .nӃwQS͋ ,g+N'P' |6$& $6$&h6$&sd {,+X_3*t[3*s Yc<$ G?`tr61ZtEٰ55=,f[ #QpĒ_J  $!5FNlS $X0Spe_ $dү  $ Iώ$$$ Iώ$%'PҾG &V&@s9&@sk)o")o"D)pj. s0;1t_52Ш8` 4y#s 5j C<8<8==^N+=J. :>fAAZE.PAZE. AZE.BK E3( E3( E3(LHZO/vHy5MM'xONM; SXW۶>YjRZT8o[pc r.\FFV5C ^ E`vӧsU (bMѦ; ]H" ^^V ckf "\.1-. f jI>t$w akE/skE/ ,-7 -7 .G字)T*QIj2) lyKEBHb so {i|q^ ߻]}J#}z]"}z]bP|:c\h&)[D#pN, 9e"샮03샮03샮03ZeKi>ɔ#cg@q-b@MW , YPhH %zG W+ٳ+    $ -"0]ך qA ´<>f jS"O. v%,TR>Cvf CvD#la· '|C(yajIhj(O{..@ o /_R"4.Ԍp6Kg0R?M Y>?cZ s @1E @^[Y $ @^[Y (@^[YAxLB@WD`DF YH凊) H凊)DH|W' IC>KC_yWx5WxWxYXR`+ Lz bj,5b파މ>fe%khN.Ui+`_hnSq9Q (rQu+? vX71nAI}o>#}H}}SYjb/-%5>mH< UA;v! ղ2a +0|ٴ" Dq]zeY@ɯ @ɯDOI ,u h(;yV (;yV>(;yV >v^(80);>?|DPR[*#9`}֦ h= 9k = 9 iBS "iBSs:ђe e і𪦻Ȑ{!2PZC8>٥-X Q] ( eF칩Dhѡu =0kb ވ4*.෢JP[㶣X14lR ĘBB1^Mn3M #*D+Z*f7a ,Ә!2{>E!2{&4d$(?O (  (  (RSÐmY2SÐm  /  IR)>v0 v+w (+w \8-pmRO^OH@%2q>? K!oșZ3d*h $M4<ֺ6c*f-j=$sD~2<F0a=g $CF0a=g@F0a=gjF0a=g F0a=g aGW\(ϧ GW\(ϧH4H4 LQ#M._GkQW-KWo%(WXMzB XMzB>c.Pe9* Oe9* $grtr iK1x j8 j<*n@S[ n!}nrw22^tӆ9Zu-8>utnr^Nys^d@C' z]lfs{=t e{=t}>AK1b!?O a#+ۜ/*8f`k>u5[%{ҚAzl; )(Q%N3E.D\i>E.D\isE.D\i i` yyl}_C$l}_CN l}_C l}_Cl}_Cl}_C{wZ{wv bYAvځ<],ܷ AA  'd$JЬh  ^T !,c]bpwod$ ^@(E:O[z :O[z:O[z DsZPu9zY[L<j@" aʫ̠q[#GJaxL%e 7!6 n.4zF]%G+]%GfXjs\K+Xjs\ܢ2U ܢ2U u7$NoN ~ 7)-GH͵>rilv G{7Z  n` tSd[4Rd[4W\xR W\x r䪮q # m˳pu u+j QtH D^  |l49Tz11ME36!S3ed s!S3ed s)*,fKU],OQes -0 0kIU1c~Je a1V(d 30Y83XY851;TY;F7>J [JNoZJEU MVG,Rr%~>&UiUNB \UԈWW+;tWy3b .X1N!%.X1N!S\4&5y_z~w_z~w r_z~w  _z~w B_z~w %_z~w e_z~w ,_z~w i _z~wj`/@'vUb`  kKq +l٭RmD2pu\r> vq2{!7|ܮ3 }lg[~~Y ~~wC-;`qolD +H0m J/Kl !'!yD3 5D1nsʌe0:S #:uo#A F<2k]k>t֊S <Qd/~zb!R +$<5}{pc֍0< +,vRB \ąo?E!.l 0yPz0yPz0yPz[,9J[,9!)Td zsh׸z] ` (SϡNNRlXQdڛJR詋ޮ; N/dJ;}?xY!l9"sGE.Z Ӽ·-K !zS J ȸϰ 9  9  UI3E a.S( [@On @On : 4!Ts ,!Ts! j !uIUR"6pd $P'7$P'7$P'7L$P'7S$P'7$ %vY'% ,r9sy`/ R -/ü3$QYR/dJ /dJ7O(8& Q3 v S e`k[w% "[>v+>\e n\0 \0N]!^ lva1Bz~do44e@Zff_S f$h]:9s&h]:9kk#nbkI_nױMnױM rm2 ^tI 5;u R,u x,L0|\]b]|\]b}wR7 ~u7k1 N2 ؾX C#"Q 0S[uY[u$l#"Q$l#"0Xk a<0_<0_ <0_ ?n_ d ~w--~w~wS0( ukZ+"F>j}E Y^.O* ƍDЫf,O2H&$ YLvԊ YLvԊ|(3qmS \s*dj4s4>N i h.ҾFݕD ݕDjݕDbO)#XDCZw/\x8{iWyRlsB ;ܬ[ ]LS{]LLy]LQ ]L ]L]Lك{bۚuVnPY;6R6Gzr4 % 䏵y'䏵y^a8ź 5K&Ko|:0Ko|:j NXCmbNXCm9NXCmNXCm$ʒSRpZm%A`1 85D+1rX_ c>s (#ce#ceR  ̘'EFZB}>| / D-R] D-+  qIŮh<̨[x `$ \I^ cvwl|{eR4MS W"ܒQ"U$>F-')%| (f;>(Zt9)ܱOo>+ 2,^p 2v3" b3W=j}\S:a O<߆E>ٔY>ٔApuA}sCG i/Q& e^ H:S $V*:S>ZvB b\1.K ^p!j_3%,E a`Kĉ -f*E NkҌ Z kWܛln bd n bo' goP-]boěZoƓ{oƓ{pw8 lp>q Pٙ^wUHQw}pݮ>x J~f/(BSe͒Nl_& 1l_& jC exjZnR3S:178| (UJq }]u ~# > A{{ ίAίAkίA:Z% ]gJ8 \ۄl,MbMerO=terO=>erO=k?Ӱ6͓YEVӪj:;{~s x[Ѳ_Ю2ҷǙ uN| uN| !hG \fUBN R\2juR\2 =R\2 ,,R\2 R\2 (ܔ0L #jiRc8 x'<S @>* @j!Ƣu %Mg%Mg)~ )~[![!O&Q9"<ob%_ԠYϏ%Iک_*@> <Zd H+ # Af g>J  D.% h|A%|R)A%|RA%|R ۚÐ>!ۚÐvGOts \l^>&Ws̨R FH>@j YGN"j8Fi,x!F0!2& 4}Q1T 6c c63R% 7>8;{+r8;{+r9R> j:۬WJ>wZ?{ -Az1 Ae"S  Fܐ RRF*iF7S{TGI"szY>PeQ^ R'R *;T$b[\Tđ> WXWL\LaI<=)aFfZkM'LDkM'Lk!>N k&;k&; gmv]mvo47@4o47@o47@o47@o47@o" er;O u1z)y NyD!Rzh RKEx  !v 'n&5Q(yLDJFo4 JFo4 JFo4QJFo4DJ'I5 CI5 B3C`uL3C`uS3C`u6m 2lLJ .r2ir2i%0ʾk:!\7XR6sƝ+"s $9HE9H9Ha#ĜRZ8Z8 FŅ M/DcCѳ/2f1h41h4 \> -$ > -$> -$Er/& lүjډxRCC\/} cUt {k ` -=i'}) =i'}) SM>:•aj'sO%G O%G ,O%G O%Gj ΍T/wcLn;shKQbO^ K-j~֟:o f **L&g yn0\*Wz ] 6;T] # L (;LhL LjL CK!:T}Y#NE#NE#NE#q "+zv% x % x%  @%  s'% Y % &h(J2 J ((L3*3b>3q:5a6oЅC8$g 931B]=OKo9?p͟Y3)NE:'E: FiGhG4lH gKksJYsx| JuKnK + P"NS VXvg0 (!Xvg0 Y~686jYd׏ i\Wa]8g_ %j_$DNr_$DNr , eHٸ2fLg.F*`jgTke1Shbln8EBq@,q@,RqKwrۀ src@ 6uޜ͙txeTgy{ޖ[igS{jL݂>{jL݂ U{jL݂ N{jL݂j{jL݂ {jL݂ iR;_>Q gf %i G^DQR s DQR 1fcf e{ڠ>ڠ Y7²sj#Gk #Gk  slLn i(Jֆ4vk &k & #NK#NQ#Nd#N#N߯U?թqdS| yn !}̍` gs 54.s 54.54. eҋ_?0Y mo} էp#KeL Z891d>Ͽ }$߁TpZ5 A# ᇍm Dc{'\>fT `簮 4ji ([=)s[=) jW!<vFpQ) ,=xO=xOm 깥$_NAo,=YkQ9v,OIE#[ #nQ&5 \(A=)Bv)BvU,:C.4"1iz1~"XJ<8kwkh; s<"<=2@B 1WH J H Js N_do N_do ,UǓ@?} ZƏj`jlLZ exO exO f?Rh="gl~Ln5OLoo7>q9Z0fWr?r?{fJ! $|SQA l|uP j C$){Y[#g\ M Ab2 !S"Wo/% 5W]ZzEr .X3yz>(9~-i i% |V% |Vw[ !  {Ʀ WۘzUT>&gXiנ{Xs \񱌾k lz,d˕ BµPQ2&mF \X׬'Y +FU io'}BAT`R Q c/Ǭ< c~1)'#g SXaqƯZ D 9D))C:7{S:#=lOY9Qf~  s, s, a :<jp0 i R :f=gTVH9  %%=>kLq "#W$ it&o>ɥ&d {R&d {g&d {&d {Q&d {Y&vጭ'ۘ'KP\,v@@Y;0h b#}N1)"|2RA|H5ZrD;cKBt<4mf=j BU<, C%_C˪NpCV J >VJo>)MN5 OHOHSXJ~"U=)}7tU=)}7VXdYǔ + Yǔ +]g) l^P M ^i`4]D a:6LahUv #cNDaRcӝFP/h^jS k ѯl[pcXl[pcXp_J t~"t~"RuA؁> v*]z=/AtO -֤z$ ,  FG61;kQ`X;F¿ hJ~{> eh.}r%Wp*C͒ (~V  AS «QZ|B_l (Ӏ3$ Ӏ3RRz0P +\qz̆ꇰ@庖 cK/R'k*UohfⰥ$pR TKU`[ꐊ ⰑO"XOQ2 ^ "U 1?^ "U ^ "Ut,?ӡ2-ӡ2-T$㺸 +z؀bz؀tz؀k/A@UO %q @U j;1#s &Quo^YkuD h79 ad鏸d9rk(fN%w݌V Ђt ΓΓ mΓΓ:Γ0)t 51H^3 V ) &) T$.RM .RM mᝲf !Q&"z'#mܣ-)[d@8 %.Se! .K'mOr8Vϲ:pr \# ^># ^v?.#nC?ES̘ (?ES̘GCT7,rI Jsa  MsRMsOf2lQAH5_FQAH5_FU S&h VONWO\h[ [ c\G _ӍB_c`z`ňAjsbHbD dS;eY g4׮h5'h{vRi~T:&Rjָ/% <mr+ mt ,m[tzV9!t٨pDruuuPy|n0 $+?&v Om W8c^SI?t~-4 =46c :׵SdRB RB>ϯP \(A,;77S uWF)7voV,DѣV b#b80|RMb#b80|r*dQϧ MN R$[iͫ'q uͫ'q-O "LKai} oGÂĔy6UHÂĔy69ÂĔy6ÂĔy6ۈ: , [ aѹ ?eѹ ?"ѹ ?ѹ ?J*kX _X-snb-lޫ&t(A!0 J7@쏬#쏬쏬4(k>I` &)(Y*A1," Ҥ"x$N 7 72b)hsjSO uv3뵩7q>߄XM $3 %P;?&@Q +&@Q (~W .Q] ]1?X41;I[ 9 ,;Hŀ *<)AHv) 6AHv)jH*H*.R{IдksTd,YV6Pe lXz[ eZ!qʾdn>~"|e>_] f.4Tj0$sm@[a]oAW@I 9{~v ~z) ~FVSQMV4Wtէ$Frd.ozS}8^Ɛ K2/Tb 1>UӮkl]J^ aulq mYW )YW #'osL!$R%!ssQssDY.<gX agX>ݑoq̷fidI | rtZBUϳ Jօ zm # "po "pot "po i]BSڍ{O{O{O{)w_ $۵/T64; h|nzj%8-;| %8-; aL N B& $Fua $ Fua>F1yHLl7 eK q ME7yzP0}T_pO VE8f7X[J ZGu0Y^Q7 ,^Q7 $__ n $`=́_]`=́_`=́_ `=́_eF)/Xm&f8‘ n}۹RY p?rqrH)=Qs+!Cs+!KvDDIvDDIvDDIvDDIx1{q c3|"@b}:fR}  ~/0=`} jp;gSp;gD/ jOF \&%~DƒhK?ULY[ q9 Ɇ.YQL~=E>A&@0r*N&u= h jҬUUKne)jwIIojssqTuND!pAyF[Mkrn$kv 5: =rv| a h*l֙}2h#>ۯeƬ'< 7  < Ǡn5; R?Ʉ'bryVvU t5mb%j%fy j c<U(x tخ`j٠c@l٠c@fٵj is+"~ ---e]1mZ$>L:8OdX^9-5tEz \-D_Jnm`QF]@ Ȳ6"Q ά7AYVފZ!O՛浧ws XaQ  qSk tִ!S! j"^\| (dx )0k/*/mm/#0sA r1: i 1: 1: 9 jWz9 jW{:F=*F:̭%d4L3YF| ]M~ƃ_|i Fj_ԕLaVjb` $cd9 cMѵ1 cbqRdʡ"@\ sgug2tm> m>YmW Vog,koƩ- s%'=|td_|-w$L'w$L w$L $w$L yO5ړj yO5ړ , yO5ړyÏ ~ }|Cf= `}|Cf=}"/0 }# W&}# W&}# W&Z}# W&}# W&.4 3zy s RR&o * <`恜 iiwNzwNzKHcY  o/SqShj݂DMWDMWk<,a3Ɓ?y tW!nj#_ ( v,9f> g` `a3yÿ?ĐmwDb@,,%.n|bz_I; i&OgceР5mB]UE #ͪd>U7 s^#ZHiK좥N ) m bT )0 I[ag |;4 Z?Z?Z?NegpJ%>Uu: ~,JR|A m j L>K ŐY7^aOYve^aOYve^aOYvejj;:\  hj)l !g& !sSkr&=&mS'T(8 v'7G^- LR-ER>1VO  1VO 6瞷DjD8=[$9A)|K =wABz>=Mz=Mz =MzZ=Mz]?, B_aړFrT a I! +K̭K̭L0 L]ޙ7 MD&0Ot 9R_lR_l7R_l,R_l+R_lR_lT(;#T(;$U;Zuj,^ ]T˓_z_dOaQ4J b3D2b3D2btdZk B \d g9p|#jn|l#j p(. sRӟ=t}>uP8 vqȐzvᖏ[z [zTB SMZ SMZ ; MN~KW}NfL { ##Rt޾I F#H Q[D,$@Rϭ8.;X| NEK$tң Iv/.h'v Qv͙tQv͙K  [wtKva<7N9Lٍ>N9/ > U )-1!-QpGaAo:aAo 9aAo a~)v%t~1 eɱ !)OQZNY?QZNYRkyT߲ qUZ,>VR KVR VR VR V<'П V=T[Vyn[^vW>Wynů WG:ۘx Y# 9R Z* ` :eNHG_jgg.JYgE 0a ,j@ޕtkVHmZ$a, m0) # m0) ctn,tq:Tvn3Yzz{[Cks |nk=fphV@!$N;3Dp>2P} 2P}nӶ'\Uw"GI| r rƈ/МADTNWfB WfB (WfBj<<<SK-z"j\na(5?`N}.e $}.e }.eh }.e }.e}.esnnj"Xٴs#@N[ -.L? L 1 Of f³bwGxI (SSS>Es >ó x. Uɵ $ B ך$Iw8 秉n5"1j>ќCZ ew]ڦJʨxzz> W铡$TsAQQYϕ& V8i0'>c^Jb)*Cb*Cbt}dpY}dpYd6o Ik Ik ;P۶ ܍GGgk ,Ggk Ggk  /Y _@/ 4QTӃutU_BsKi:5#8"ޫsv$rjQ J$I̡R%}W4Q۾*4Q۾{4Q۾6eCw2 72]}=Z֫Y>MĎU@}kFb^H)MQ4~ MQ4~P\*R[Z;XD `)0]a`9ԧDc fa"M|u"᫜k ZuSIh& v<l \wun/U x ?79.x ?7 \| }N}IsFӺtt>)n)=6 n{kw M N-#Vww^RY<~Ȥ <~Ȥ &wN-9S? s韎L bh3D bh3 bh3}.A7 \}.A7j }.A7 ,6-k#6-ko-4 .f |L0t˳,a(.PJc.sijzJ>zJ \Rg_R)Rg_WFxSN A6 n;z ;zt;zs.gm| C S!s ((+B,LB,SV@L)N+ r # s`s1 $:ch# etRT sxg$\RPY R @;=;]]UlWvdDm8 dDm8ecSpBþTȏهP"%r7'..Y>Ϲܰظ J`}\4i\4i\4i\4i8:(wyJaɢ z r"gk _%; Y ƣ棭 (G #njRa!H UHG/YE`_C  m>'{ #T^L(LDE ( LDE \3H mYb% @  *c _Kӳ" cOF=N p(BM +mSmr r +C.$ceRcet%OML+@ɛp +zZP,rp[Zvj-> ->X4ڪI' 7p| 8SA :딂>`πIR>Rg'Ԯ?$Jj5?ܺLb$?ܺLJy 6rM7}VN-w5>Qw cSeqUYoUYo|W&*W2/# ^Y7Z ^]s@ # ^]s@ cfG'iT:,viT:,viT:,v j(|k[K9nrN oW, w&z(@w&z(@ w&z(@w&z(@ w&z(@dw&z(@wHdxZ% MtxZ% M (!T|!T|vìj ìj ͟W4{ ({.! 'cay Sf"% R) :P:s'TPS'TP]gZ$gZ$"*Z/OȄ e_2CzxbPN_sn5 r!,{* 讷D9.L ( Ga<%>^kQScCQAtr )j)t5 h!?BLmX (o9;k~ñtЊSA%f VYٞ ̅PYt̅PY ̿s]SH*D9LOlDBpl<,*Nx|n}u d ߷V0m=߷V0mSF\Zo|MRdo|Mko|MH["%jH["%H["%(afqqcGI8K "b? >^%YQU^Z,K 3DD?[EQ]}GG_s2!:܎AZ:܎AP:܎A.:܎A,:܎A#:܎AQ :܎A ;Dv)F0Sn.>@\"&Ͳ K"&Ͳ L/"&Ͳ "&Ͳ ]"&Ͳ  "&Ͳ Z +6h!:,@-J1ʻR#-s~Y/zho3 0=0= 0= 2 9,4}]98 J` :[΢t>j A =$uAr;o_l n A(u^ C-p5wG lK6g5AkNK6g5AkPI PI eTz/  V/fV Y®Ɣd_6rj_6r ,_6r gr'+mǘIa mo3: pŨpŨqz+Pr`ʒW s3;hsNMb \yBy~S|@ |= c Mrfo i9 7(&] 3>_80#s !=>pRM,*t!׀#% ۦ M?s9rQj ߍ4ߍ4`n3בJ: e%IH7g IE E jP}P} P} I3{q}zq}   1E# |}L1 2O f.`X,IAKmq &^Ƨ~h ~h Z 9j}P]Yٍ%Ot&taጉ%_HEɅ#r #rt5;e _M %]qR[&aTj,[&aT> [&aT iAsd[ V 7Y  7Y @[ p'PoD89bK 89b Qn?s!s?;?x u>DnK &*?|Hٙ! J39"eNb#9l_?#Pcu &mKmh&5J, , i_R, i_/٠ c/٠k3(bE7f I":T)$:uzҟ :uzҟ ,;Cj%{<&KgJ<ēo<ēo?oڇq iARR A`XB M`B(Rk - BP!(C:("F3ⅳ J"S#J"SM@:MGJmRkRkXO'B^ (_|va FI$(aI bs'! e4e4Dg&HLLIhtV] p?Vsw! oxXpyJۥyJۥpDq , K.Z;&͵#z9͵#z e}W o \ed'aed'a9Ȗ[ Lowca:,:>A)i wuCD uCD iL$466! 466! e466!j)ws%05Y9%F]硗Wva硗W –G5rkKP;d({ D  E6 \ ٸ8Y fʑ~@ ^3Rd!r>RDVckh>w%)o=`y+e blGdĺ%CitLZ (lJ>p<a P\ H ]D ^ H ov_s~ -ϟ2:yMJnuM_rtɺO} i]% p/ D$8 ($8 ( }(:c d- fmc-CB)m\ /tߍ:1>% 3qާv3qާ 4 o` 7xkr 7xkr7xkr: Oj;1J ;ÊD4 ;eZ%;eZ<>ί<>ί=  >B, (>jE?uUG3{z #Io <IҘ: $J-v;PA; ] PK \P*Q"ȻFR5 R5 T2o bU |X&1 Z^_I1[[^8eb=Db=DbvZdwme>,>f<% ihט^ hט^ (mcW\pV>Se pV>Seq6o;dtq6o;dYsS[uu, ZQv>sM챥vɡD mw('!N(yΘ¹ yΘ¹ {7[Y77dWmz."ܝ m~t??N j v`L v`L ȫ%$y j<¹މ|(u-̘}WKu9.sv˥^b 5U / |nƪιN݄ z* ix ,^,X҈AsQbnF r!nF rRnF rZ ak g;N(L<\DVҦ_mS@RORO@ O@:O@ O@H YJF8 8 r)~r)~RR!AkMlF* eM (Ut {k_C ]!<! 4e 4e 4 g *kvq0 q0q0sNSsN=hb.Kq"I!""K "R % =n!9vd \"?IM;'$Bj)ع_04| $1o4WD>6G׫`j6ΏMmB0%SHӹIb-| MCyNO> Ri*]]@` =a7*ة f^VdUfh;}~f* gZv6$kD>tgD>sH5kRx8sٲ?>@DvRx ZG UREp;B<t#[o1J _!TϮ1 UkLf?|ȱv#A"` Td?v>ǥNu䩃 %{K%{_D_D ] \f*>Cpx' ̤ 0),QW QW ,̭aeׁ ӈz7_QZ Qr3՚~Zۇ*T v4ݷF8, m= #i< צ+Qxr% $xv$x Q0 a2\$c̙@6 # VhM Y |יh2ueR8 @I.| f f  {[V  {[V  & c1+9x]>]j2 ͺ!L ?җz 2X2 إ"?#]"  mPv[$'& %[Ԋ>%^N&Ϟ &u&&d(w#L6K+A;.b~+D.b~+DQ/fA5& yQOL7 h a>? @.h%ўdBqKEWKoEkQ/sF`9E4>G 2@G 2@G 2@If6ӝJG$7 K2 9<QZ}QQZ}RQZ}]o<)_7F1l!x3lЎ mb) ^n"-Sqnt ry vu`&[ze|4A k |4A tݖ>v Y]Hs#Z> =7@~@[ *5>?R:\I_ h{[k"c $$]Sk %]; s ];6F ̸s3@cl|.? \4 #\l p@MPLih.U@ .U@ .U@|z:WNk8mOd $LňV i   2 / mtvSo εo{b~lS) f7Oh* - Լ@LJҸ&rJҸ&rC?O1?O-?O?O?Od ?O?O?O&zۻ-j'jێ!?aj1"v 1" eu`D) 쌢 s.hVsN4!3J9~~e9Q8?h s>Ds>Dʢ s X<*eCJT t D na l 4@}0 w=1 w=1[>U 0 C.:i)Y&bԚ "$Z) ,#sd #$IsoD%F` %Dq *  ,2۾]2&44$X]| 7 r r7H* 9t7H* 988@h; AT(`A\f&B 'EmѮjEmѮYF4oGD'b/D`I6CZ?NJGB gO_bRl RlSv* WڨJ$Z̻<6v [g*|1]y{ L `#u e((.pnT q˞o gr87jxr87u`mҎ xkۂxhdL3syr7ޠhyr7ޠR`yr7ޠyr7ޠyr7ޠ yr7ޠKyr7ޠLzfЍq o eȧejM#=Lz. kTT;   & Xԭ;w $BqI BqIWTTR +^AvS ?l cY7]ݫRg%tAP_xct< k{sd U/t#U/bU/ f6NJU$Rl t\M~t\M~ (^w 30202{H״:=6`a<0pzCΔ4T kp. [s /:猡{ ~ڜ)&)Vi5-C;H4v0KҺ|PgS̢|eAt|eAtL Kk,Ə a`JĈZ`JĈL "=: ZJZJ$WbG?\ \$UB{D}(:-O; `Ohs zP m_ "d_lLsFEQ +宱? ;%5ʪn R* ]JRh XAT5M[6 M[6>;x J̪>Wb&̪>W&̪>Wj̪>W ̪>W̪>WIߧJb!󜉔# 6k%gt%gs'e𤙨S)[Ϊ *]yC+]S~ (2=C_2r|YR4A/t5Lqxv 6og8=B. A|#! ARsbE; CM,¤1>M5yB P?Q P?QQG3/UU@sUԳLI(>Vj2eYW< -X _T);/` 4rn/t` 4rn/` `dZf/KkvoPHZq)>v4Nk yr/3.y ]Z| iw }D t` 3F d]{dCOQQixt/Dop*iSR34D\AYk:8)!R!g}RĶj %Ķj Ķj % #Q,(>r$ʬtGr$ʬ >\"^S 3^+v=nY p׾vDch"QgjoBy Ĕ~@ QzWb~ $89  0I -?#yXF - ԣLD8n{;׽~{ }|zo }|zo u t1.剌 1.剌 1.剌 1.剌1.剌̱rdԈ Z b1ô i1ô 1ô 1ô>q Z# = q Z# _,_| 0p-| >5R >5Rk>5R a>5R >5R Jl9RJl9 Jl9 #*84 sCD1CD1vnBwR4M\| c$ 5d{/Iő b^ Z<}DZt' ۅj 3 نھ #/RF2  e#dL=$_dh.Rdh.Kdh.$dh.#P>֔^ ~sRD ~sRD| ~sRDR ~sRD .>.j s]8Da H8U[ #xH %N1Ik 2'ʽ+lg*-Kk>/ Y 29PY6~(B:86ۈsR;vd @ aJ>@)%jCEKH/Bs HnKi^O~J 2VːxKXN[uo[ [wf \6],\N"cMR5d(g`2 #d(g`2 e d!'l2m⽥ )pE t-{k "t09V tVqk= yD:|&, Sd, k ?},Q &IתC}lh}ls}l }l ~> > Zi,_AHΥ&tZ.n%uM 5">]C4>]C4 rzz!YR9MaÎ[Y9xS9xMO'MMO'=MO' MO'MO'΢R̥ب[̥ب ]c0.ZJ>H_T H_Tנd נd $ؕC͉LרUmAᗼC9 "yTY qͦ{QDYGN*E_}M* w^ %2~ hR2~ hy9-t1 uVc ,Ek __b7=ݢt;nߋo(ߋo I[J%mv{H[#N6NjZ"F_"Y6 f"e^auǓb"e^auǓ "e^auǓ c#8ݡ:K&z7wg'J$ 'J$ *V/U,}aK.߇+,.߇+".߇+R.߇+K .߇+2K{4"Oga4ؗ6-INr #;Z\mi N8<?-3>EC8HG±s԰H|GzgIh"dM\8M\8sM\8jN0V O0@z>O\>PS5 PA RQ+LRsۡ'RsۡSɐcSTW'= iXjk4!X\J\#f!m$f.JBfE K7Zi(8:>lunZVvS;om FCjoDel~sf{z[F sX]tc9I3 c z*Xz*L}6h./*wl./*wl׸{:xCu [ @ 96 j1TŪŪr3R kKYP,BÛQSJr-Jr eU  EiA k`"{j퍽Vi e;: c 8zN fss2yu:Jv3r n]d $˄ ;&2,g5VI*-w[3K0p-k 3F6kV75SRf<| CmCV@#O9F. (GĦ iGD{GDzHP4~jdRJukgs NNjPPQkv h9 SSWXV\f V-D W8HŇ:Xޡ? Yð gZɍ|T ^(+.^ci 6`E ,cW}AGcW}AY cW}A cW}ARcW}Ad3,5 ,duPufKĺKfSg!gH0Ix{jT&GF6j.FNlH;Ͳ(L#lH;Ͳ("lH;Ͳ( lH;Ͳ( n<%xJ n^b0 ,ru<TtP̌yga (|g&u }(F}(FK~?KEǙv~)2EМJ7;.=RFRIRFS&RF Z{:W= )f|' 1 H_)[$Au# {6Fc?р>jh8LRh8Lw1OfRR6Ȗ̓g/_~sC;L%Ynvͅ+sͅ+{ͅ+ 2dgOw $iI =ڱ~ ,43Qʰv| *>NŜ;kyB a_ [( ,[( [( [( (nxn%Bj';T$ =N>JpHRs9_| `SM-/U|K:: j1 D\ ͽt|?OxgsXy/o} i]/o} iwG wG&P@ & a 'bƉR*6#R-, +/)m 8ݷ9K+ƅ>Z4? c\B_ߚtjGF. +GF. HJG -I噵'/I噵'I噵'RMu#P7 R9O"^ ,R9O"^U8+6H> V0 bgEd]uS.f큔 lrY}Sox?`oz$ޣdp lR wq'r-Dx,zS'x,zS{w m` {w mRv{Jۗ ON>~<::] u0QﺐH^خPX -U%U%:Kbd= ?3= ?t= ? RJfN!G {ok#8- #?zڥ mU Q) (< 鵆4)Q4e" kj {=g# S nM` j /jG ,d_)j \"P]R¹ˁjDJP! Ǎ$ *јX lDT6]QTen9|]19 _Xj>󉜀S$>󉜀,>󉜀>󉜀9eW'9eW'* 0r[r[K Pc>4 Kn~ xzD8 \!rRu +ErJ#ErJ$1  *S~D FBe FBLm`D _; ]oq S%}O  ǮI ,ǮI$dZ!$&q M* YzD>0-f27? , 3M"A5=*>7ҙ=8hQx. 8hQx.8hQx.8hQx.<''4] A3E鿌C:[DzesD:[$ 0D:[$ D:[$ 2E aH kG*gZj G*gZ cGcmؕ JFgW ^K :LoRqj"u>Y>]qKf& _|j_Rݚ bLwt |i!0 iP׳6No,tJwESkqx펿wLzO]sLzO] ( zO]kzO]t|1Sr #7ԅ썗" U9N, iD2k=SG2/ \yv jI` ,n8]nU}3 ?aY +=ɺn-ng`+~[+R auQ XT&d cO7kuq #IA'A`)ʡh *Ng eȎtX|s;5dv |Ssz9 z9 ⯼ űiW tɥ͟ɥ͟@~|lTCB1 \Js7 Q'󊝩hn>8I9'rEL UJ & \O(=d\B: N6 I|H u4J+Is J+I TR TP%0µ/]tz DwM ~\x S`@ Q6 \#b@E$q&R%ڸf #(Lj*8- >` (- >`0Sv1-.4{{4{{5o)rK 5o)rK 5 K6BlC7:];j_ e<XZ > |:v>"P4S?U %@|}6A1ONFG.c \H TENLUJ?t O07P Pʥk{ZTq B^U5Hd ^sS_ a`f" i`f" `f" \ `f" ab+ NeU/U[eU/U[Rfvňq1gH'w *i 5 kg*ho΋ o~Br\ޏtP$?VtU> ru%rbY l,j3wUCVeN [0 9stI ~ @I ~T]T8Ծt;PvRCdY # ަc9 F`tS1|R{rR{r>$yBD; ^apYkq K1_ Ku KuF- 3%vKx gxK" xK" '! 'm= 'm= ̱} vl8_"Z(pKqJ|桗6 *JhT(ip:?㎫e~ (d>1( F~oAw6Gv:3O r 3Os(Z79L9L9L}/c 0}/ck\@0۵ $ 0۵ ,0۵  F6b) N ! h$v%DŽ:{}1 r#q]TtNj }Wc 3D LkfR:"d WpF4 ,9j#Q̔ ($b=2K&cqYZ('93 *a82QLX,0K/8ng.D6W)Q c6w*n $7'G>;R'>%+X@ 7B'7CVsIrJy#Lz9MU;$lNOt/)WYw }YjsZMҰ a~@PCceE~ gr bjvkr o u@|wQd4 -z< #|"5Cv~b6p c~b6p FV|7Q`?9Vwn t7zPjm+O5.D O5.|D J)i 'tUt _:5OvP% Jjl5S}ES*0RjYM (wa} ' c*Ҫ/ _/ Z/ 5/  / H@ A6>A6  @ i `S]Pbe& ͷ I`kq.Y/!Զ\{-RA \E~/ׅ2kׇ0И9  % S % SC&c &c y7_ty7_ y7_Y y7_=hɉnZR ւ9 #71Mj1Mj+_;.9[Ut 9[U)} l,]Y^^Y\4P Y\4P ^m ; pRqHo#Qa pR^FƎ9 J+KK !b| Vwtn} "P;@Ȗ7  ZX NΞ g i  i ,d244NU] , U]"ĥW4f#L3 ~$&]S(8*B[**"t-nm- -.UMA e0]|2ĥ&S 6a`!=AG*٣=AG*٣? at? aY$Dc _L #Ove PS/_DQmZAsT ct? Uhɡׯ>]z2|]³i8ߺv^P]._R2Z _]`N`l`lRc`6tM.SgRsgՈiVǦAa j,;kɡ|>n2 %{ \pqiyIyest@.-U w29yAXͨ{?SǨ# |;rNiL}tF+N>iz!#jMm 1/i7 1/iR IFj~IFkDIFt3X`@>hp\^Ux<u q 8Z .I)N e\nY\nt; ;L !N cMyHK.Z>]| 81| c* ;ao!gczïG ,q@:&Glc#Q bܬKE'vJfh@e> +$p|ht8^M t8^M} n@s܊s܊s܊ N"x{Byx{Byx, ʁovM a B3o>f $֫ i=R -t-tjX-tY0-t ѐDi 0+Fj 'E4 d2IMR S a y FA TX" TX" TX" TX"ʽGji \yZ $$Sxs +$m%VxF %VR6[ b'Heq  'Heq 'zT-)cag!-E -=.Kj!k .2à /h<->4-/4-4-d5&gY5-J1Z8Sj9I ,:$dA;ƠhAB|ذ $ D?4 jED|d FEhID*C#O6P@l"0Q4U0QQ X7`X9/U<d[ؚ$OS^n b[ ^Uk_m?[s_I ^d!Ch" r"n fo MRo MDo M6o M)o Mr~> ar~>tf\Duh*vt|vt0pYEvt0p ,vt0p vt0pbvt0p wMq&}mN=xW3bd@/LJxkYV>TEPzbJ!Kފ<{^am{^amqغȢ_Dm"f$P$NiНY[@XU*=i&7YvlBkxge>mݚ@  G bd]<p[,O\N>UDRYP5 #ԓ/t ԓ/ ԓ/b\D]}|EX7 =v L'XW ׀A`P1J|~SaQD.m =QD.m iQD.mm 0 $+︽˂#︽˂︽˂j^5 j^5Rr - Rr !z #X#S>ћ? &=o |WkN$~ڷ"UfTz j ys5 5 ,5 5 * %!C PO홚 J׀du5|u5  OAmQ2OCTPC \&ɖU4e 8 " kC!~d^ ,+y)-j$/dW \ /lBS/lBS0=F 0=F0Lc\R m0,{K71W;r5`R<|D2+ ?3ˏ,W?=*cE-m,vE% Ib˪[>J?^QMew#qOD\iB>OD\iB OD\iB i2OD\iB P,4RӦTE j'UaiNEjV0lB \" p\\D4]iۇ5N`5s[`pJLnjLdV<'EdV<'Eg gicjle~p?o;bu>v׌l wA8"RwA8"wA8"wA8"UwpkFxA{J]x{}y;~iC ~ YA ŹQwSz:j*PlFj*Pl aH^ H^kN;k%(SKfw qVZ^<(ZEKRIuITܠl?ܠl A@wis }Z泮 %DjS Dja s~E  q2_ߍG ȷ/CAb8Ab8U9U9w$r Eb1E&EtǦXDcd6yɡDyʃJU9>&SiCROl%?=miׄ<ULl4g!G-.8k&v9Gjc|O7Ssđ?t;A)W #o#oRFSu JP pWdgF (JߣSJߣ3$7>R%plS%pl]1 1j:M3g0#J c&I `VX~ W} W}j ?r] [Ʋ $k!aZәә әjBI8Tc ([LEt]>W!iJ$XXI)u|8R,2b!Xjm9 (d&N) *+h"ˠ,$*ZB ,$*ZB9/O*/یB 1-[3;h4j5&zt8A-m :&B {>Xm!D@](;A*< Cx[Yr DSA c E(J EfةqF /© F /© ( F /©F /© iF /©|F /© G2u/ G2u/kHz.E= K͒LdhMڤ tNO9yOMJe tRV!b c RV!bXWk*Y}_ Y}_b_=*_=_=Yex ei.ÿ jT5>l=B_i al=B_i|ne1rF 7Kr avYy]CvoW7x*dI.x*dIx*dIy=Ky5SZ s{m=LX|.& - |CZhܯN|ݙ.}v8 .QDox n'$5Ei1 } av㤤 [dcØ.h 5(o'F+ afXw j>yޚA ]a ,K X^:X^>&]M>K[#dK lKk@X3] %4|.ZKh֨l Kh֨l"UۨPǡ/ ǩ_ γI%Xb ȟg~ͶiZ' ͶiZ' ΰ=qsĆְ9 +)v  !KvdUڂIGp\놟jA) jA) $ⶪoD㓎&Q eiC) g g Syj: eiplմSմls l`$Jv$##rv>ʬ)7ʬ) ʬ) $ʬ)ʬ) (,v)*,v) ,v) ,v)K ,v)?[%jd*en '[5a)j+  )j+jw)j+ ,)j+ )j+ ( * c>,* c * c i.2% .2% {/rV 0^ 3ΥwR6 7זBb8H)s=rG2 SH5# #Jm}JEa5ijJEa5i>JiYKK KOkln[Qsmd>T<Z8L [Ũ,Z\pPs!\pP\pPj \pP (\pP i`EiR]Oa1AaXIcܦ!lRdobNhl2LDmM!g&] #m}a t}p9\dtB lyI%>0t|yP@>F? F?s ֶ m}/ 4_ĺ3v2mWU R~D ~DsI^դDC dA$!~n rEBn:D =)d\ /=}IB 5* ,a 2eז;Z;r?4DZWEHծVb lj'{> JJ-Sدb::]nA) a y2|{@>a-K41L{ ,෵4mm.hlxuVDEi<R Ŵެ 20}~ ,ܐ5BNCS Jp ۰ \meW$*Vd"Mᮘ :- E aP7:! _4 >_4 l_4  Y a Lni kI  =0  yϠ(- $HH$P #|ttX]zC SDSD "SD (iVx (mxC4ڱm #gQq*LG0 S #w]ie9&W2 )d*Q )d*,n .ͩCzh̐+D0 >̐+D0 >̐+D0 m?\6?\6 ,?Wڥ@5xCYROHwٗ5Hwٗ5K^.>S|7uU4# aU4# ZnaǙ=f9L ,obl$q ҥ q[oԝj q[oԝ $ q[oԝ asvssvs svsv_ iZwC#Z{4{4|^r '&ubU@vdM5)>PjUV= (n7| 3aiDpB~$R͐(9թ3c,2>[l2\+jPYM2$/]U_ +stW%RtW%I ,0TkC \. # U.O%N=/e*k 7=׺Ba6`>)zK #B> j뭅E #sV!#q+\ԧi LL y 6˺ŝ)Ug#-~*PjMyp=UU׏ 2ۉmz}ؕ #bOR8#-c,, L mDw  C! >_uGT vh_݂h_݂-t<ššš]&p#xkz|{D -$3t$3t%W(gk)Dd+Nl`D.fS5}Y6IVu8Hԝ> :@@Z V@fRAxFل9GZR.ONHF ' I.ZJ/G5MJR2K4 @t $ SU1vGD V%RM WWĝI X>-*QD]ň aIG@&n\aF>dcod>Kʎ+vfUἰf*vj.r j.r m*q>q5 . ,q5 .rS1Sv/ R|"yǝ9}U}votkpush ush.1kcEZ j\h .c+[YXcɽ . ! %i0 <jR?Y>jSjad[!kNSfȘ_!qjPgцRi3~`{ *mt|K\RfZBw_ܵ7_ZƓ@ƓƓS~68p)JUYgh aѝ[S%ѝ[g0 i%2d z_Q@iC&22oi/1i/1c ,\jT)˓Bs |˓Bsg3@1,@1,QKjD ʉR< 15V> z r4 "5#wn &xN' t 'ܛtK)% #*}|-H-HQ.='/zU~KI 3.j6n 4φ4φ4φ5o8 a:7J$ ?~Fd@X^Ew0CG0,:H36UHj>Kr]->K ZM+YMwJN>QzmT7#T- %T}Tu!]ғn ^Unݎ ,^UnݎjaWYcF♘tcF♘cF♘ij Bc iޱB|x9)0(&7x9)0(-xQd}?; b‚qm' ‚qm' \ ‚qm' ‚qm'„c…No \†k&†k&QŠ!N3ߤs‹ 7TŒ%*Œ%*R]ᜪw i]ᜪw]ᜪw ‘h?z’ 6•rcr4 – F—w6~š 4]>›N ›NZ =)^ lŸ jM¡}u |¤v2d§#Kf§#Kf§#Kf§ «$}0IK e«/v S²M4µ*PQ¶'GQ·Ο8h[¹p &ºRdºRd¿ɠ#o>d9{h^dj -_TK&ڛ03SMx9r 9rjSSPgrВ gTC'ОYS聸 Cp^j}J jlП#] H8dkFLna FG  "wWs&NV + 31BR2XμN 8;K 9䠮`[F;iu9 DآJ|u] Em9d6 m G;]ZI8sPL.PL.S6(>KT^HT^HV0NWGX< AW/IKd YǥyYǥy ,.Yǥy Y7 Z:cap a ` c}V>e#ԕ (e#ԕ e#ԕ  inaoWu\}ozPS qcsvg er:\Z6s~Pb't> z5c{)ּS<{)ּ%{)ּL }ۖXhN Ú`ﶨ>IÚ`ﶨ ÛAq Ü@d_bßLLyâ? "â? æ)ۑ ,?æ)ۑê{( #ë=KZ íKHHBíԮ~˨ï]2ïFڿ ïFڿ \ðF8ezñzڍöfק-bYöfק-bö.E Lö.E ÷~Ɏ  x! ӡ&c3>ᕹ >wPڀYJ9̞# U># U # U # U 1Is - 5t8) n`&0 VvV X3,Nƞl/ (g(YH{9= 9= \ʬ4 ,j M[ vt78] "%[T8 !T     QI >K@%|Fakc:s(z(zElZKn mD mD>nEnNx>qY& 6s{js!6t ZNv{io|3ākH ĂET iĂ ]S7Uă6wąEY 0 ĈMnxdtĈMnxd cĉzĉzRĉNeWđē*0 cĔ֬Ĕ֬ĔnĘK;tKę9luĞ uĞ uĞ+OĢ#>ģdG& ,ĤaŶgĦlO|}Ĩ4p ĭ" \įxKj ijyB(QijFv7> ĵK% eķwĻ]CĻ$3 ļcI_Hsľ GBb~3vqÓu=>Km?+c %L ,c %L@o ѸݞN+Ѹݞ L!cW1S9W1S9W1S9ԋ]eh ~mLu \6q[9*f #15Pb}= #$ 12t0> o.o.2*SGR' Ct6on0}j9~{Ȩƞ{9w 9l( !) ,7 B  RA,Y ]E a8#{% $ "/q"/q"/qA7L]A 9  8]68]6$xA:,gj=>=* R "b<:"b<:"̾޴''tKJ^P,ՈvFD,ՈvF ,ՈvF,ՈvF-]-A1[wb3xk7:$cjW80׼bNa 8JO~~Y Vkɍ y VY0XO[5 #[I3Q_7F _`N Jza彰5sd de6T 6e6T f4 -k )'l6Nm⇴bkoO}qFTqת8Ct+oq|}ewvsJ~A//&]~A//&~Zn*}FŁm Xeň>Seqň>Seq ʼnJFg Ő־v[ŗѧwDśVE&ŝ~wՙŝZmډDŞrŤ }$ť,Oph ūu-Y ūěip ů( NOŰ(?Ÿhl>Ÿhl Ÿhl ź=$-{_ Ż ž35, aaJ삍 (5P̠Fwj<<R #`#T70HqV&}~0}~03dz/xcs/xc g[=nnZnZ nZ I~  ^s.ѹŌ .:.: 01).}e0reSv #͆z<͆z y< -bٕsL7YKL7YQL7YL7Yie\Z sq/^a>LuLu\nc } Y_Rdj/h=`57C ~aKn+ #\!L1ilD ն cd\:W9Kt{+[W aky>\&^8$HU!&$LB؂ "' ^Ѯ)39;UCŹ> Ov[^)v?vAR A[5AC[DKvJ ?OJ ?OQL8 i QL8V+|Ob cLޭT}1dc2Hy mج8Q mج8Q n4]$;_ni&-%q7RBtM\ uKs}kfU~| ƅ9 Ɗ)s%@jƋ"YƋM᳅ aƎՉƗf7ƚ4(_Isƛwx1>Ɯ'Ɯ'Ɯ'Ɲga yƟC ƨF9 iƩGzYƭ?e ƭ: ekƱNӍ7ƱNӍ7ƱNӍ7mƱNӍ7QƳ(SƵɚm$ƹmR0ƹmƹmƿE4MMG a ca #rGiX# yO[j*y\[/ˮr@ nq X͓#' :[Dvh 'vh vhW_ׇpY 6ͶH.Ll/։Yvk։Y D [ O5 [AV[ˌyXGas Gas  s4% l9T 5 5T`?JDJDs6ItQTKZf9`>lQ}$*̗!9>?DJ >J 9 XFow SJǙF:d  0{!t2Z92ZKH #2e[9 -2_ JWrH@C{ϵkt *᪾t! C #nT#k-J *}5, 0IY2Ǧ BUADeFs[E=Pa GmJ¶kG-c A>I(gt+NJeljȬL nja͒nj{=>anj{=>Znj{=>dnj{=>nj{=>LǎQtǐ7Hjǐڙ ǗG# eǞv{$Ts$Ǟv{$Ts!Ǟv{$TsSǞv{$TsQǞv{$TsǦ6 Ǩ &$OǪԕJ ǻ; Y ǻ; YǼ8.L Ǽ8.L Ǽ8.LtǼ8.L $ʾ=ۅaolH ʙLc2 ʵvmCkJ Cѹ3 in ї$)׮R@ÄNE 9ԟ{! dR@v' ƢU' ƢURr nbN,  g9'=x4isK(ZxSQ`DQ`$rW:Y  D9f otq4T>6H͟z*Sf ,IY`Ot*bge( 4:սJ4:սJ   VcUGa VcUG"(n+}"'a /h 2n] 2|H73 =Pa@ =Pa@>LL? ȁNz?{Q`C:ƒ PF1Of0b;6(Of0b;6 iQ9NULRV W 3p[W\]' YUwo>^N;_g_jT `; a`;a:Ibj& B d<(h #hE lvۈ+lvۈ+o{iOMGPvN7Y|wq:ue| yBZ9C8ȈȜ+T"KȚ!\ ț E9j + ȝ"M Ȟm}Ƞ ݰy ȠIȠIȠ[7.#KȡICx ȡICx Ȣx(>Ȣ5Q4X s Ȣ5Q4Xjȣ@ Ȥ2lj#Ȥ2lȤ2l (Ȥ2lȤYzc̯hZdZ $ϋA s b awN K q \ WSC  WSC| WSC+Hw9 j'' V?[~ BΘAS!ȴP #GJ: s%se')kb)l'XA -a}w_ -_.;*;1=VN2z:A>H2z:A>7l' 9dDGy9dDGy < G ɡ5ɤ@P .ɥY aɧ.ɨR5v ɨl@ (ɪ9ZNs ɰA`GɱZpRG,ɺm56wbɾsτɿ-2d} _k$ YL!RWsYL!RWYL!RW a|ՎCQ@?$#RB%٦ ޖk5C=R Ҋ/Ҋ/t*ӊƍ,ր5rpKWفRJ#YLGz D*@A SmR蠿]M蠿U5%>R ( (X 1^Y ,Bl0 Bl0oğ ;WP+|\j+|\ iK  t u=|G O2[D S+N ^# YOb!)N-#b!)N b!)N k)> jg/\l\! v #p14Y&qpl(6Y0T8'48%=뵣=KbpE =KbpE >S8/vJ  aLl%L{ĩ L{ĩYP/vPJrn>RCn2% UoM_\MVS.[RNVS.[`X0_Cbg9d*5) f y㙌 |h 3I4v"nLȵKTnyp>no>K (o〉T$p6a9rd4G ,rd4G rd4G rd4G t /bYw% x]D^Z{/Wp c}|qS}|q}|qL~| Y~R#ʇ9vvA cʊ!zJEQ lʋjLʎk aʓ[Y ʕ(_k>ʗ]Vm ʘebCʘebIʝL $ʝL ʝL iʝLʝL ʠ[ʡA 袘ʪkY!Q $FʬY8'ʬ\Bʱw%ʴF<& ʺR^ ʽ^A ʾnqʾnq|@s/IYEiz$s$צ$,5-A7Ϫ7 #:|VhѺJPY~f  i*P0mM*P0mM>*P0mM հp[հp̚^ך *lP:]9̼_yR7jla۱_z_-DoPU+F?j0^(PsE<#2JR SfYuN1}! J-  0 N #")?ti pySRqEJ$nӶby<n:. |gPqjgPq gPq_T@ }| 5}| i}|> }|   euKQ 0 j |2 ^ؠǛ%k9%VbtqZAK *x f'@ Yfs"@"I7 'Jv~z 'bb)Q,UzTQ,u9.ű /2@ 00\J0bw}'X31fQ441v4R 涧b5;L| 5;L|s6;C :ůJ:ůJEmŖkGJ\[ JVL\ O<*7O<*7>O<*7= O<*7O QPPQ=8R9n9^e?Vmrgt^gNhQjLl@c+ soBYjp¥p¥p¥pMĪ%Bq'م.qqÐqlarrr(r}giĒ u+$y>u+$y uOvaF yk~?u>yNjyNzBf|Qy8|F~-}J~-}J e  ˀc1d ˀc1dRˀoA˂G [ -ˇ.*C ˇ.*CˌzZsˌ\U- ˌhRvˎ e)Ijˏ]V ːu9=vːFl/Xt˖d|`'a˟f˫$tk˫r˫Ľ͋[0˭M7 aˮr˯{? ˯{? \˵16<L˵16< ˵16<S˵'S`˶D\ ˷aK˻" ˼&KsR> ˽@~ )k ·$ľ T1N2FV1?hV1? Ȱ? Ȱ? ˏR:٘;Xo'mޟDB |le1KydKyKyZ H\/$? MK.A_a9JMZ3Ct Ihz+=>v z+=>vhn (JP pT/xg j -Ġ1> qY;Ti (|+m뉻36= QKZ vX8 9.Z $$B: $mBojúf3(U e=&k@U@} O'S+O'S3u!~J[#:G% +`܏s[.\ .\ i /(~: 2t w4WN2i!)= 3,4e5$ﱔ 7 | $L> (B}/"Yqk^= t.}j@.9R@.9 ܨtLZY$ NYB۲?K (`IY`I 0ԪV[ OmyUv A]q -`\:; 1$KuHK| @ RIa#hReO$2j%C/o>/Uj&/U i0'B{T 5賿ؼ6V뜎sCʻ>EmXtAEmXt , EmXt F(F/ #HOHp>Jg JgDOm> P xP xSS?VU #V@D, Wtѣw Xk0BZC%Q.ZD> -ZD>Y[z/uL\$f|]S ,_2 `R C v`&NCe=]J c e)&8`gjgx q=  r8C$s,ǨZOs,ǨZOYx+B=2> y '2ݠ!zNX9N ̀ʹs$ͷPBiKͷPBiQ͸)m ͺLCͻQ(KjͿen: c: #<&5= ;f5= ;fY5= ;f (MŗMŗ|΢7uR 9-}I9-}Iظ ظ ܏Nq ݁T?Dо9Lo-\|<>_d3" m" cH[| ?F܎ck\ kl: #`xͮ+ }1p&ޯ 1qG++uꮖ>X aꮖ>X ꮖ>X ꮖ>Xt >M >M c pMfYb6^# Eu‚ uV V ʯ(NdFSɊ xdN X;F O_K J!x% Y,rs&J] &ސ'.K ,.۞.۞K2]uŴ:2cAnOA]RtRA'+CuO|C&N EDEDQEDFUu]FPs]rPݩ0NQ\*G cZѠN[ezF s[ezF]B6k]BlT<_Ca,-bEAcv#3f G f Gh#j5'j5'Lj5'jw_ w lk~dcLk \mTiZp1wstCUw^io"wzrŹe} |+f +|vE:'+NxPT}t΀ZT i΁Qr ΄s$B. ·YY0·YY0Έ1RS΍9jΐ aΐ ΐp`ΑJ>mΑ嚽1t Α嚽1 (Β*G= sΓ&4K Ηcvm  uΘ6bf Κ"PΛ{ )Eh΢vZΤd ΥB[YcRjΫE6N >ήe:jNήe:2ήe:γc=7 jδߢlOε5j; =ζ8Dq>ιCUιCUκ&n|N μ'ο2 Lçi =힌 ]I=힌 =힌 UĦz 5# $ŝ4fƨ rR| R|YZLBrv ,:Ƿxѕ eѕ%BJ du , ?wh6ډ7GwVyډ7GwVyC'-<[-eA޻zmkҏ r2Nr 3 $D IV IV IVIV-e̫`;,")5eo5^4v8Vd8@n0qYY;e)it>Y[> [>Cg %?< >CB \FjH?$우jKҾ${Z[M$:eOʗ9] O(<YEPxoyJR( g SE* SE* sY\ NZɲr [8 &\⢐% ^!w*;^!w* \_arACarAQh\wNbj9 ,kH~% (lK im69B,nm=UKQnm=UKnm=UKDy@[|''} [| }_}WfS]3'֐φTbRφTbύvG ϓW |Ϙ)lϛoU Ϣ'5ɐϢ,OJ ϥ]b $ϩhJ/ $ϮXF ϲycDϷ0n asϹDd}EBϾ JG!t Ͼ JG!bϿ@3yoh cϿQ ϿQ H˰0H˰0,t P4h9+z=ƈ ]>KЂ@ (e^3d=udJ8f m=udJ8f =udJ8f رyۿ ( Vr q 켆.A켆. x! Ku$k{Ru$k{EQ A s.\j{<ȶ@j;r9vTJ ,g3H'J]>rQ܌!>w-w$ 7878787878ۉp> wz˶) wz˶ -" # Hv̒Il>ҍ"G„ uR+#"G |#b7>$"d ,FE~ =0IwK0W5sI30u0}k1*a2j~]4`[6 (6 (8{*8{* ; >3|] ?$zJ?:C7 (AT @dBZD>` D>`Eߥ3WNFSp FUAJ"pLʧB| cSIK gSMP  #U9hV`|oHW> V`|oHW (Xi=b[aT܉ - c eKtk@۟m3d # n8\:oerpoerpjoerpoerp (w$?M>xoU{ {'>Su {/Z} }6'{\a &{\a {\a i{\a ,σYЃ* ЃdЅu->@Ѕu-Ѕ,ъ?sЅ,ъ?Ѝi  ВU Д7 ZИڪ5]НA>Н_(( С3*YЦѩ1aQЦѩ1aCЪI LЪ.<Z!Ъ.<ЬQЮ^#W7 "Я<Я<|а@@>sаPmG+>бb { еCzkж иC2TN й N1SKU[J=R IUR IUU63ڎ\=sk s5 LIZ"p ̴R瀠= SDLj}sk,ڢՕ^*SK is 0' \؝H˳4PO2ܩ䄋L:ގ; ɇ ,}Eo)?ce׽Ws9.5! $j]a '|aj '|a a '|a|[jYU L-deX|M bd%ZWRlSgE5  /rB q--Z=`ݸB">X.i%#&-#$~'P<h'P< ")Xb*,t+*E:+]x .% 0Od86p% ; Z' ?@ l?M6y?M6y?Nj/?vE3SGFW1UGWmH>J gel JӟPZ_ƄvoQ1yhPQW^vK݄ ZQ hWb.Wb. Xv>|YP\[颺tH)s tH)>v۝vr&Xs yU3A {GZ})~jh р"Rtх>Fm4 цڥ>ь[X $э gstю^?~Rюd. gѐٝ:2ђNw (ђNw ђNw єLe9ї Fїl! t їl! їl! (їl! јr2D њOܱDџ>i ѩ0wuyuiѩ0wuyuiRѪr}3ѫEP>YKѬTzѴ6UjѵA{Ѷq]Ѹ`q2 ѺqkѽhVQѽhVDѾ TzaGDѾ.r ]GR SAQ?Cm Jg Cj Jg CF[Fdu'< |)Obv v.4g3еX7'tg e7~a 47~a 7~a|n~065S;ql ׵ ^aԈ1 ݘBa \z@;e/i #Ty%LTy%YGM[ lSuSlSu`.t`. (&,ѰBiv m%4\| Q@j裗2; N_ +P_f>N8saN8>%ʾS :?L0[V #Y7ł!ǿ 4AK"> vVne vVne "b/ $ "b/ L& \OG٪.C`Ms]9H~_pP-I*ٔ ,+!WQv,'p 1lV 2q371"sN7'7't7'Y7u`03:\O , ?~ y JN܁ NyYP DPZHnV{LWQM aY D'dY*2s[ZA ]`c ͌. 5l>1  o=|q5TtH[yL2 ҄7/EҋqI^ҋ{<! ҋ{<ҌƀÝ ҍ0.&P$Ҏ- D!ҏ?XU#ҐgOҐ/ ғ&;sҖ# ҖJxj(Nҙ!qSNҠCw?ҡ 7"Ң23Nң:ٶҥ+s Mү{/g+Ҳʦ#vҲW=rҳX lҵa|C aҸ  ҺMһ  һ  x3:<2) Pnl}6tӛ0 S&-4?-/ Nr8q 3;_yq :65` 8&tT bڽ.;5Gn]-+]-b'2 i@mɠ mɠb3A,@wy!zt^/feVd7 c5@ k 'س c@נ9dy1, g:  ? s# t DR[ݏ |&c`vBg. 'VF RY ؝jD ؝ ؝  ؝ e#Swۭ#Ti%J8Ċf \-&݈p91o%+2-2) 5\}7e:t90! 9`dUq:rI?w9ӈ?w9ӈDBVPl4 bCY CHE:E: E݀r0*GW"EkGpk #I4O1 I,ŻjK~Lz eNPjI YOYܡ.&e Z @ 1^Κ$ _1(cDɔ icDTrThkpKNQZs$&uy x(z r m{4NUt{4NUR{< t{uԓӀhq SӃbv4\9ӅCҢOӉDӋmx v ӌDl!j ӎ.k7  ӐQӐQӐQbӑ+T>ӑ?I(ӒaPw sӖt@.vDӣXdӨ#mM)ө.!: өY{ nөY{> ө-KӪxmyj ӪQ ӯj%ӱ~ Ӵ>L15x ӵTN?p'ӵ9d>ӸߴQ \*ӼjI |e{S{S!Pu!kŬ`N>kƧ 2FuvƧ 2Fu 'ks 'k t'k iw j;Pϴػ:( .'_9."pjG!V (~s] j~$`/|r6"tS 6"toz̅N jR!SS#= c$c*dQ (n=X{04NQ 3J$ dޕZ +t5e=B>$n瓅+HmӞe  PpJ邫V >#qФ2[#qФ2&if;'kG,(Zoks*~ *~ -3W v3W v5`T6[8{cj8(ypY9`GF[9`GF[<~62>SbPA=b 6NB:Ϥ`Bk +(BA sABA \BA>BA 1H),PN/LἁzA 0Uj|U ֢h + V;ަ1\]6-2 ]㢀O_(9`U6.`U6bs4 abs4sbs4j dvhGFLqiLZk Skq 㺕dkq 㺕l)tmr"l0 YsYo toCtov.|AyW ye%&z([ϝ %z([ϝ>Ѩ{Ոa|ՍCxՐCbJՓ.0{ a՘5̨;Iՙs $ՙs ,ՙs ՙs բUUx\բǐ%Jգѭ դoթ2+\ կMIհ[ ?յYھ;Hkն[z@ ջ]s ջ]>ջ]ռ2y տR; տR;SAI>9Xv ’q&¯ 8߄ X0 |bJ 4?VKǯFXOǯFXOm$ N+KbuOz.8ϋGs 8e?sՏi ֞` %x;K| o  oY[m_k}>)dGed c(zYd3{_+>,bc}RYeN]oGCK0;gTRYj7 &\a}B o(( ::N{)  ͼ ͼ ͼU~.yj6[h Bg=`jBƬ &И# +-U$&%   Dwz  o!iVo!iVo"W"]y ~$O/L&TF1&TFS*]A6ɑ0} {1oĬ4Iv 5Ы<6ծFpT2>7u r8Y߿N{8:. 8:. =cj ?#f}PL ?#f}P ?#f}PDeNEKE:) E:)tG|J0<J0<tU3Gx8a U;dWX2{ R\-ER`B!da^>ddqBKP i "kRPЈmpm2@x q<D qu xx/ zր& .ց=4 փ9͠ 6օn1~Z\$և! V) ևRȣ ֌nv֏ߡq ֒^j֓~HR֖/7 ֙"N֛H{ Q֞--5֥+,'C"֥+,'CK֥#a֮K<< IR֯5 S3 0֯x֯xRֱ@q.ֱ@q.ֳ?%} ִ0asX ֻ@]dSvֿl4?ֿfۉjN9@ lZyUv|9/J|9/J7n {91p -{91p 2nYdٲ}*/& xھ*|:4L+zގE} ct)|yqtYל Ipy lF V64@)kEaDՎAjI/u (WX8 [z O6=#z3HI <SaNW RPwK\5}CM+:Ue ثku?:H `uyMbZX9stQ *",][T%"xL%#,YzU>#8#$#Vm(u R(u )C/3gN 1QhM :)濖:LAKcBсB`P셰DDH? uEh|MQ'NҘ2PbA R#kwDZR#kwDa RZ RtêiXc,DZby]u11^]4$K^natS bk((Rbk((Rbf b`GldYyVUSf$ tiq5ON0k 9R+k 9n>%soKbC!soKbQsoKb soKbugS0-Bvg wh0>׀ C׍Z#׍Z׎R*0L3׎R*0׏Qwhs ׏Qwhs ד/{ssדn4 זV<_חmל %S לatף ' ף 'tת"]׫bp ~bY׫A׫A׳e.y׵4W}D׶-{'Hh׸.oTW׺^-2w׽ 'cTYz~ mgLC mgLCt %}sR Б잧` eNxNh@0 $ofO>J  Q>޵rg_R|om ve˞ - ~=c {n.sd5Q 6w 6w. H>'Y\ s %[7}b s+ -r *}yJo-!>o-! g%0h;?j0h;? 0h;? CQ/ &:mwMC5'$X]? i ]? tBФ Yڳ #V s #V ; ιjD +qD9 N r{ x d id C-w,L$ $  x3ú >机< ".K'gfs 'gf 'gf)L P*)M%*)M*)MQ*)MY+ʋĮ++Q'++Q'5퉲5;H ;BG v";BG < Еpd?QG:-Af1uYCuEN,'.3|Ns| mQUKN R`L >3SOS͐; S?U˩VvYHأfZg# d!if!$zp:trs_>s6'Kv cZ sxֶ~^Sr؃9Sݬ ؇17,vGw؉x=7 5N ؊dh ،7p-،7p-S،7p-؏`múvؗ*zodؘt{@ ؚ̪h )ؤ8 tب^ Mثs қUث&c.شYxa\شYxشYxض~AU}W ػ&F j\a ' nà{] Eþ) _ ˖oS OOR1O oˑB W;fӤ$WK&z k[t< Zֻ(s 퉴_h7 \n  29 i29 GHGHGHvGHRGHUGHGHGHo:KQ ;+jǗS5- ΫW} &OV F6#d5#3m)Y#3m) W#3m) %c O's (ߤ/ g(ߤ/ /2 #0=!}s3PdA3$4*{#4{FHI4{ 6ENL ^7Yp0 -9kr:Z>qzlN>[s>[j@ -H|jSfnq&S Us[==]mOt ]r?jaK7wЅ ar#|q" ds3df8>Nhx6  kz>URlck \lH.mR= mjVtn ~rg+}RvjVw_@W iy F` zϪV{" 3zك*{Gًy/ 1ٍTD'ݹّkױ H>ٕm ٖ&/3 ٝS0oV ٟ4&4 j٠^~ ٢]Rr}L٥ ud ٨8C w٩j2U٬ɵMٯPٯP ٯP eٯ5 1ٱܪ aٴ&Z.ٵ~  ٵ_,o bټ#uټB #پZPvپZPپZPپZPٿ/h0xUEٿ|An .v 6; -}Ѷ  E*!F 㰢3k9+`όqĤ^ $ϵ'z  үP$iүPR Ӓ3 aR|lU  _)ޢRt_8< 8< (tU m!R , /Y gv QsN8@w;^U5;^UNB1~m9:VKo/&:Hkr: =S & =S &{qn  g  gY gt g  l]% 1WNw5+: UKc(Lj/yDsN"M| ؜RQ;DfT.ՆK T.ՆKtIz4-rQ i"h$ ,""h$ "h$l_@M!Pt.y"Zre$d#I &<7G(HEH` ,Q 5 ,}W-D/L-D/$-D/.dڎ/./w3LS1p~ 6~Vu i9c-=shy= %= %Aw-h DAJDAJF GɻFHrɀ K[AqqZZ-, s[Ɲ\d^KmL \d^Km] P;] P;`B|aa/Tyb[ +b[ ew5^j \hEn$@WjL lBrlBr oGr' ]w|ctkwú`w;tz'yFj{g]c|+"|8ځy =fڅ~،څd! sډ Px6#ڍD ڑ4=Rڑ@ZtfKړfF tړD9` ڕ0}TڡPK`\ڣUS&jڧ\ήکsN lڬl\Yڬi ڬ?mڮگN7/ڵVj!ڹ\ˠKھjwR0v ^Y=Ǥa Dd= )V +m:*mT=3cP 93cP ,3cP 3cP3cP 3cPNTp Ј`#X: Wp0=[Ӆ2 @7vi6Ԩ:ع:R$U9ٚ 39ўR2Y\@6!L***v~y( ( X n~n~ n~h\9/(6' g 2(~&sO>UsO>c6 ꕀbInK3*JK= s ] #ۿOd n.ojn'jn' #j~!jhEA $,R$2W(|'&`C a'&`C (ϩ ,!] .p`ۃL R.p`ۃL .p`ۃL D .p`ۃL Q.p`ۃL .ɨQ 91MX? b1MX? t5pCbw j5pCbw h;0 ;qVxU;qVx]C S C SE ,FfQWAQWA_RPV|rbUw^ (Uw^jGUw^ nUw^ ,_VȻw( VIjZyŸR[܈J9=F \Td4 ^"\_# bn A e+ھ jrWCÜ ryzPryzPuB]? {YD* ۇ"( (یHyیHyv ے$Ⱥے$Ⱥۓt ۔a6x ۖI3" ۗ*?>ۛؑ+ۜmEc ۟O۩Lae2ۿi{hɋ3\L;̊) +̑כ+stb[+hu Vn1. >n1. a+{40 ۳ܻ7Kp>>ܻ7Kp> iܥ2'xA68B'xA68G@uRK     2ޏK젓s젓sL젓s젓sZ,d~ܝx ^V`-S>, @yݡj ౄ &gf) $9Vo]ӊ3 8[~ aY@<8 a1oR%ݼ| $S]N 0j5'K uA>*f e *f CECbh:kv < {2 - #Of7# c#F5U S &\J_ (]9)lhB )&&+&> +A# ,T|(,T|]",T|,T|. 5R20>n l4= cL;#37 eASƄpApGv L^|EL^|ERLc+ rVrΤ$VBѓSaVBѓSVBѓSXݵ[n\\^wC"]iH e_g*휶;}iWl ( Wls2bmO(  ]& ` `22jwPjwPj RwPj ,HwPjwPj wPjjwPj (ub7 p͐nk|lg 2чf;C QJK   (wؘOiT:T OiT:T 7=DE K c}ѳ !#x j3?S*kDgam s,#=t&r}kv4(x7A5>z7wz7w1OK݀p ER݀08݁g" $݂ѧ݃ʼnp6 ݃ʼnp6݈'=3݋Wz]݋#M݋)= 3݌ZrX ݎՇݎ)=ܥ0OhݔzƻRݗ޻ h ݙ>ݝksF[ݞsBR" ݞsBRjݟ%&ݟ% ݠjEݡn%ȻkݲEG ݵ'ƜHjݵ'ƜH ݹ5 nݼ^DHKJݼ^DHݼ^DHݽT̾ ݽA銣'ݽA銣'RvK¸Nd yi 1yi>ƴG^-#& h eBշ".7շ".7շ".7 v;;7|Z۸ҵ;)5۸ҵ;)۸ҵ;)`n $Bߋr8d. ?<pHqw L!K` ~}ׅl[;_qX ,Ϗ_ Đ_]<>7! AO}X5>E2gaPZs#E2gaPZ E2gaPZE2gaPZ G\ KPrG/MM*1F MA+m8 PK T )51U}@zId뙇1> d뙇1 \d뙇1jf hmRދ:m)p&!nI(c nI(cto) -q.ʺ_uNML|uaҨvVzwLނN]|ނܧ'+ N ބFbc_Uވ nފd[ތ32uKތ32uޏf>R ޏf>Rޑ9YDEޒArޒSܪ=ޔC7g[ޔCMr ޔCMrkޔCMrYޔCMrtޔoo[dޕMd ޖ~fU ޗgMbޘ>ޘZu.U ޚp=vޚy6$ޜ2݆"7ޜ0RQ ,ޟɥ ޠB ޢ4ۭt"ޢ4ۭ ( ޢ4ۭjޤxY;#ާ;ީ8"ު܁  ެXE=޲0Pӂj޲0Pӂ ,޳ o<t޶W`@ -޶G8f޹-I޺bSX7 U޺DhS ^޻)zHy޽@޾H|N _HH { jR%‰;T~ c >p Q Q $"Q Qs8e!Q נ|lj iס٣Rס٣>׸{ʹ jj+\X]m>!#h2s ܖ9Z.xZ.xQo/| SM.>"iTj<. Z j2!?BJ 7e  7e" (}<| yy yy z:`]/3`]/3|K">L _|ҵ |ݖU$q)?i# ~g> E5{ QoB8] t#R)OB{ +*d-J{` -b6<D-b6<.0@di j6Lj$0| 6Lj$0| 6Lj$0|s=u%$=u%>)=aށt?"l@?kD7uD7uE%"ն F̻cF`jIX iL9  N +Ll zNsxm@@ aOM]&XWHE.jXfYYn>Z3$ \C:& ,\mR\ b $dV4{h'ʤJhI Z]%t𤾑Nu5 w+Oa9L $xe4!S>yzgpQ|8̟R߀/%ČJ߃׷at ,߅=w$6K'߅=w$6߆%bPDt߆i!m/߆Ǐߋv ÙߋVұ ߓ2 ߓBa>jߕJUEߗw%ߗRVI30|ߗX ߝONhX (ߠtdr ߤׁ<;Vߩo98߮Qw ߮V ߮V ,߯^ a߰F_ ߳ Q߷5V߸c7ߺ8 H[dߺdP&SߺdP&Sߺϩ/+)} s%+)} |*t}@ÆET` ~fs VB/!R2L hϫ6;3 &vrD w獬!Aڄg$NS.^w5?e ?e K`o H(-7)J92&^ # '( N '( i 1>m4πBF 拚"|7o7oQ0 "B>% $ U&Dj N= 9oѧm4$-!cl-!cl-!cl "W$H9m ]R'(|NWs).*-܅0%+\+:qUK+:qU2R:v7}2l |7v8%7v88Z:s;c= >hWP!>hWP@`bwb@>BLEc9BDoٓGFW6.Lz #NIeRH + P@,B -P򃦮 QWJZ[ lQ+ |T/C [K趪K\]!4t__.)` Cja۩ cQy c`5+sdjDoe@pK.>mA|ӐSq}-q3#>r[k1~iboL0 ތ%2@&R99RCY"k bG rw a]*aU G[9ӂ 6ytyrr[G&&@ sME/1K%eܒ%eܒNTK TSਿB)\nN:௰a_ \ఴ,O!]pC#x l a ෞGBYmO sZ^pAvOkY" ӘgS Әg\ hdusYm+9 SdkZ ,՞>o͢۹: ٠`;>{L \G o7 #5^c{ Ia)  4aâj{SC4$R ¦NdN" XU+ɸ3MSQްS0RDp R\reUҙ+Qj3:)! c "r@z "r@z -(-VE'0{ML0a 2mӭD3ћK59 lve:V8CnIwj JڂwtK{Էф LUMÅhS MÅhLQ.=SQ_Fp ,RUE{+UWǚ+UWǚ+>V8eWTW׮+ ]Pgj `}uo`]I.c[\k $k,Y"lvO elI~Ln "J>sN~ t7F (w "e|. * w "e|. $w "e|.sw?_| zR)O:HQH=Sۼ^1懯y1懯yRf cᐏ vRmjntt NƦ# D L-9xzvRtW= jᰄV=u` xZ Ẳ?A#7 jF i jF $rI2[i ̘ɲjQFr k-#@ LқR q?- -c [ ݵTy݉X_tv݉X_t)Lo ,Īq kȆZ*o^8Yl 导lPP |F\  ! B#2 쓯Rc9W?0/D7g>7g>%@h& 8"vS"%r^nj ^nj ] ySXk 2\ j7 P)$d  J WD$*%Ra>'oب!mb/Jmb/_'mb/ ZIU^k΋p(!N?b "$G(;9+Ii{S,dh,BQ>a a2,h933; 33; 3¸~zt3¸~z 3¸~z4X5S83s6܍+D8n, ;U`<4=G,%T >}+( ,D RܶEY_SGY )HRN ) ( HRN )Iɟѻ Iɟѻ $LB,:{MmKVwR&}pVBR2VqJXȏt!( g1Xȏt!( XTk \YhhZwJQ ZwJQj[|冉 \7՗:_% a5﹎8a5﹎a5﹎Q a5﹎aMd(pNi baD btXBb9]؜h7:k @WlIga rK ˙wr3T+;y2ӡ#9 ( y2ӡ#9| y2ӡ#9hy2ӡ#9s{i{ A {HK{HKB $-&ach ,r⌎#H U; c␮d␵NvKsGƺ }╋/*~ޕ3m6 "G>>$ mʡ7vFfPNS❜#8 cQaA 4St⪎h;N ^䆰 @SPK⹝L0>⹝L0~n Yac. cƁ aRA $zgzd:TLfj`KWz3<HtS+6dZDOc%et@qI #Y˧ QB sQB SNw>_n#  ,Y  K?<{ K?< >j8R )c& ļy:j ļy:v YDpYSs@,$CtjCt>"P>"PsѲ #nSͬxR`]={o E/t ) m!e\~ #r|y#r|ye&#źd(bbh^0 *}|; +WݿL/.z/ ?= 2p/w i4Ir]Q6WP7E4c35  7E4c35 7%oV8Sr(>9|aR9w;/)v{;M4jC=[QP >h>3u+@3?gb@q3AFY>Bnyo # GȓLjJ R;@Ѭ -SY]T(c>UuX2 + XZ9M{AZD: ]a Z]ʑ&dVaңR cMh#N:t ev׊ ev׊ fWj lkU:tkښƒOo׫vu}Na9 .y~"}}IY a》bUV] {  S s S s㎻e S!㎻e ,L lh%ի Gh%ի 㘖I { 0'12j2M& *੿ 1 d|gq‡meme ,me $me{n5-?w!. u:ُ㱓}K )63 ʉRm XRKpu[^cxa)j 㷲NR =az"#eۆ 㿍QYV㿍QYV㿍QYVǛ, 'RXf_ AgNsb/D'!X p)%R$OQ $OQ݌4O g\*n34fC% fC% (㿧é$%oi *c[s/_ҕ NvHIf΄ c [Jww2 zAS?) \ l ͬf  8ML$q " [~M \|%,|vga=RYP i4K nRR RZOfcƂ!_ Ƃ!_ (&s.8T{'`S~*!Beh*CA>-K -K R-vT4|p(4Nǵ4"&u> .4"&u> %6ŨC6ŨC 7#%;}Բ $=+ >npê ?D#`gSAQh 9K $DǔaCCTC b Mw~JsbuEcD+ ^ ecY_r4fT+5$g% i*YOjT$n]zpT1sr}E6w,[ .xUŜ }f 䃙T5٪jY 䅆j >. %i). %i5J͚h dJ;K ;K䐸-Y cGk#M]䙊,%S48dj dKuE ": #HΗkL$"䭅.C 䮆/ (,s9R (,s9I~ 佖wOF PG C6G"P |LYvW^sX 3g58V\_DkN>Qη ,οh[>Dў PHd ^"g mï& Ӿ @!Ez \i % \i eYH B  $ Czxsә6F} 8x2&7 ,oIWl7J -P Jb7=>}q T;vxT;vxd T;vxdAp dApYdAp  2)ûB ?V q 1yb1ybQD U:N**(JG ۄJ^jh9h $u+ VVpkaL mҡͮ ]M A"KT#%2 #,aͨ #,aͨR#Ym!>$B2#K$B2#V&c}', ,SO$C,s0s.{R-Iv1-Hl2 53n;B3.zE7־L U8OɓQ?#P_CO/ǁCO/ǁKVyKVyOY8 QjJ)CQXSYR0T m9 XQeZMG[ ]'u>M "]~Mx)]~Mxdd7J{g,NFhGRO `lB 4 [lubNlRЛ ,wLH=yMv/zF ~(~c ~3n?Z~3n?Z~[?8 MT傡F償[f~kRZ$ -K}O|=L ;ߖW&GhD*GhGhQZ%k Z%k _zfBrbµ µ &g>3D e#s/@?埇LL= 埨j 埨 l?yw-BQ宓id" A&CbSճcK WN庇 x/ >x';K-5EK -8jA{4 D4^i aގ ޙ&/|tP}-tP}-0[ pxkص.*ZhHR\󺙱7Æ?! #Æ?!===IDRA ,hb! s l[#- b< j ˿ e"<*/NR*<*/NQ2%2% A:]  3? 3?m辕Sm辕RLm辕K-k/> @O.x %59'y" +mqY+87 #-d ڙ #-_0/ؼ|y1ewS6Y8[-9ޖSd:NlI9:!W; 0Q;*=$Q l=wO]E LNSEmP{me5eeQW+YQW+ gRŋԿLW^pXT iXɖD XɖDXɖD]@i (][Varsh^Q- Sh^Q- "iYaPlGdYjlGdY mUWkr0WktFI3 $uϢ>|wN<it^]  H m>挨$t#)8C$Ǟ'HQN <h Su?v)u? z曲7鉴޻z[XϋnȪ ( We: Ql Õ} !# MX]; s汓lo>決а ǩ,us ~d ??#99:kZ?>3m#OtzЖ'ЗnbŠ 8wCg$ٷqAEٷqAEUvl|-_w){l,JNe7 J~CA CAb]>cV|~ B;#'n $:pN6+L 6+L 6+LK 9- cTV cTVDcTVcTVr5UjGt^!tOK ˿L9 | 9 | wvtN!^ #+4C#+4C#+4C$PNYBv &v"L/)ZX`--J .(TA0W=΃0ilKj 7i_ ;l d9A6QAqB7 E IOyNvJv*OWm)SWm)LWYW WYWD]*^!j_ǀq`@10ۥc6[>be"h)#E c.kT $m/ S m/ Q m/ Rm/ Km/ tf7u#wo9EHDy( {%t ~9i.E~M!燧cI)燧cI) e燧cI) Ņ`&FŅ`] h9瓫})JN3K瞘Ϝ`L瞘Ϝ` cw 4Pwd:gj祺Ү ҮLҮSW/őxvW/őx $簹ZU紨rݬBȁܵKp %? a%?(%? i%?d1Ejd1E9Vf>9Vf -랒 !2?ḭOdVͲb~%-VX $њ}9YKՔt lyR$/aU>ƁK'h 1ɋU;> K,x0 i핣Ƚ $mnmQSH SH (+xrC@{ yOB| g yOB|YQx 2 ĝ  pҨv pҨ pҨ=W bBP (pY51RkZ[j-C UvY5v|tK!;H<#xX#xX &{n (\\A> *eլ D*eլ _*eլ Q,.U 06{3iUs3rQi 5Z 47t\wt4 pm D c])L ggfEi 9i kF al}nAYjru~.4ejr_ nr_ ^tߗS4x.wx„yíYt}kd c肠`HWЊ io D+LIf \Fg (\Fgt\\Fg莆o hZ [H5v[H5v˓ctK'V[7 B!\ 7\i" {}rp4q> 襭CQj覮}Q覮}0 訟/ɡH>c< sdBRc\j 豋L>$B8tg Jր7 $躎(ds U軑@C0軑@C0輗QPbkIJ('x|ϧEŵrhȏܹܪ̘o - UOĉ}K]M{;tw nB ߟr >ߟr \ 8j7 SJT a*! _=_= i --`\ob> `\obsq_ ')- _|3x Šw +#o t 'nU@ Vy8B eZV#E]"o%dD=d=<\ jh))}!SkjmczoÚ8srs_Ksrs_f2srs_t[H t}GQUuÍ uÍ w}B z̲fYz̲f{1 b {(-XA{(-X ,F{(-X A{(-X*{(-X $({(-X"v pz pz oMlh 鎻k9 ,kf -6ݬAj6ݬAZ^6ݬA26ݬAa6ݬA6ݬA閝S@I c\/h 8雑/MfĢ3Gɱ 韋lxPY餅`餅`YFD(p魑= #魠mؖX`'魠mؖX` 魠mؖX`]魠mؖX`oM+kw3<\\`R@cd \ 4  4 *[BT zI2ڋs4pS4pX1 ɪ(Ƣa ,/HymPlԸ t Ը VN6}S T0;dǣ? !o%\RԨČŰ9yΈ$!yΈbA A[UHHB Aoh?J [" "v|> "v| -I|8crt }FTg Tg K"$}#'2ːj*jĜ h02c>02c>02c>102c>02c>R 02c>0 m2abam5r\>< @YGTiJäEKB{WLF. dQNˇ QNˇCRw T(+WZ3Z CWZ3Z 9WZ3Z i$WZ3Z a WZ3Z WZ3Z ,X0Ё _;Jjlc r~ 1w$u҉1wx: # x: cyd34$yRx/|i)l|i) |i) |i)~"7R J~kꃱ(L>)fDx@S_iʍsme@J- ܼ ܼ kǢŹmH (+[ꑙ{[.  gꔿ1ڎyjjZ:Ss^t`LG $ 겂R=:j*U(U(g7 !AE$l{C9 __p (__p ꄆ-i[QV%>lY)O~ (Ӌ`j{mq Itq IYKT^~ ߲cT C>N1s >N1 ^井i ag Í wA' բ;BRB֔g{ ̖" soJtHr%[ RLXb3At"0dP*Sİ0>H gBnO Cbs uLj uL i =Gu e_ &D DGj9϶^zc zcr !*ԥ` ιZ["=ݓ$QRJ>$QRJ (fU (fU (fU .{0Gb 0d 20 s1 " j2,os3:( 8Djz!1 8b8J<T;d\d ; 됰 vca{뙲xdߖi@Iԏl 렏LJaW;=.5vz묵5%n Y v g뵋X"} $뵳8 iYvN%g \X e™[a"L$ϋǰ9 mN R ^}jx}Rp(np(ntcxnH3 gNl|֨iׂU5w ܠleܠle %|F ފ$5 ފ$5[gseY (LJ*& $ȸYX (aZ_RLD/ %DVm3$_R$/ \PH;"Uv J"m8Qʌ1/sM,!>0o{0o 0oD ֑z~e 26]of9$E{_K9$E{_9$E{_S9'ϋ<_@5>*K s?:[@(N@OEz@OEz eB+kCjID/) FrR{Jg2sJϻΩ JϻΩ JϻΩ ,P~KOsQ@8Y sR | $Rj.nS qo7$T=}T=}X5 o $ZNZN], ebmo cMc/Of  XfI0 hvXLkl&lq,)Z t6]!1u$zm7 av2c̛w.C+FRw.C+F{O_s9}ZN̲-xjDAiVkUw⣧=Jt"z V}UԷ 옙ЄJV$$ Fw $쭇O<# $ET?w9|Y&P`%켅 'B^W>T x#Cx# [^C ;[^C>󐣣 #v mHqdFow)\0CkS͑mCcH_ #cH_ 62J(Rx OR7OR7V>ճ \V? c%@-6>߰f @"e=ӵ9w|^7 i7lI $_:=&OSe9n \DBd DBd X:ۉjӷD lj{2~ lj{2~J+E m emj1'R .tՂiMg6,H#:OV c d@ I4S nd 30RLr:O[  [  [N)R$s |CE;8S !  OQXh OQXh ('jl)p( +B_ $5*bq i5>U$5>UR 5>U95(Cq݇x $ C1Vj I%usJZ,MC$' O,L^)Q]P:UX~t>lY.T#paX bM_enAr[e gX8DhSkw@% kt~ӘlŅ1pBbv6~<w Ox+HPtzܽ zܽ!zܽtzܽzܽ ( zܽ izܽj.f#!Z>`c ;Ӌu NʼnJ[ux],^ƃ\.>펾)j(%? ?\d`=KFH"- :NFb6C6`> ,6`>:[ #흜~ \[ R:lR(K&}:s K&}: I:,I:,jn WFt/M1tt/M1k߲z߲zK `_( ( y3ݭK IK IK Iϯ_ VKrZ\^h 3o >ǠM=aM`<кa"[пC.g[i ^YB@B@J |Dw^[0|~$K@xK@x t9޶~klD 8 ㈊}< a㈊}< ㎙Kzv{ۆ5Z禘A r3ι(/ e4Y% fo> vO|߄#iR9@p> B]z+SH az  az s Q&8 9N.d ` 9N.d R/:| !B_ϭ ;Y 2[n ^%uj(##,Yd+R5<[-kV7;%-5< /=d i 0(~ѩʦ>4֪Qzt4֪Qzb4֪Qz R> X䤈?>f Ut?>f U?V@@d%s*@³9 F2RמI:4MٙxR܈cU?U[Vt~Y|Y(Я)Z&8_%UHsEaװb)$6S>d*PLawfR4FfR4fR4 fR4 fR4g~"$hmc hmc hͷLsiD*ieT{k& ojy_r=-)@3|BSzWEzWCR`p5Si[f {[ Rxs;5~>O (+u[ hth hh hKpЭK@jJ 3> i~m )>_д\>Yv}X{d'dgR '^ hbSidf>lP #KMl[Bs} #£yȃ**nQȃ**nɅ *z 1*z> *zj,6*74˖"x:s!W( GYE-k`NbUn CK>wdo`s_.k1W1W ,#qv *&.vR*&.vS*&.v+ RQSY0\Ѝ8E~ ߘpOK~M 䁇@Դz z>I I  #z^5 y  3L\cs 3L\c 3L\c  3L\c !Z+rX ^ !Z+rX>"|}1$ {>%%Ф($D ($D, zhk /F40 ye!b 0 ye!bs!0 ye!b i0#X, "1u5 923j 6R^+v-9 Bkj:ooR;7T=Bu>%;v>*?nז ?r{pDeSfH $*SfH SfH SfH ,SfH Uj5 yU=T{WaXBH}q\:& g^:l[K _>Pǫ cCTURda+ c d jf~R(d jf~hJamNj%Un$WNpo(R'oFc|zf, r_9 #%nh1 (GcRQ5BY̨ks OKwW=SNJf; A  ْ- >D} >D} ,6 BRX22;AOqlumчABsk;k;Rk;FO 0.au %(X_#z!I"fdO>$R>%V/3i)^J[)~<,0e,0e-s/0{}"  BXh!C# Hʲzf Ihm= L*ZS}L*ZLȦNQS1R ?LjCTx sX*$X*ZB5 mZ<=mbeyi2;ictic|j㍾ 1kZl kF`cYrR.msI|p xvO -5<%3%<%3<%3a ?&1ds/z cR] mh𪱽R =3} ,=3}s%4%YYΚ{ezK٥\H>\H\v_b R\v_b \v_b \v_b Q^7L  W,4D PXRJ'~ KEВT*`wamb ^ 4J pmJ(-V؁M ʂ.PU$ Yuͧ2j*Җ_#l:Җ_#l:(\Uo9/@R `cƎ4 2@Nㄚ)S ㄚ)d_l> Bg3'sN 3?ָ{ ?ָ{Q 1k" cqY" k4 f^ MxVZOĠ'@ R90^ TV!L'aU.51UbU.51LW#[L W\vW/!jW/! gYAAҔp YO@DY|+[tB[t9]6 \ڝZ>\ڝZ \m ^Z-0^VX\_9@e`cb,(>`cb,(ebJ}'BN3e[>iZ2hm e@m}t nw1[ o?Pvj9;x+ >.x+ sy_@[ [|[s[ [ q}L_.2h<-jhG< w>ml$w>ml$Y 2dmWș 7E :4 N_jl( Ho"B9͉b&e qipj)Kt v ݂  ݂ Ƽ  =W I9VC "l$rP'z:*[ E -6TlA."4[/VDS:#) &#<5B>Lx >Lxs2AIQ%$BO_BdctGWHnO{ƁQTkrQ.%,% Rb=pRPRPUdKV2 [vd= a#3cC uR ism МMiJiA bD(6ZtXԮS"^!jf jfSm^IF O|& m\",pRTGo7晴1]S t[;qDTv@=M X0OfC| to e"Yo3 g\fQR&KkvD:G8 zҘ zҘ zҘQ ̻.}b ̻.} ̻.} ̻.} ̻.}R Tq: Tq SAes2~"4Xv a-9*d cd #qYĹ?撲.. [P2bջRbջwRd YfD e!b*sj $7z +tq s, w2EV 8NJ p: n͍y?{Xc?{XE%WsղEβ?DSHy[mg \Vˋ=M. +Yf%yC a Yf%yC hYDa .YDa 3[5#ܤgk^S'_.dÕ]b_.dÕ]t_.dÕ]:`\2`S#b&ժJG)f<:,? ai] jiy a l]n P0jq,sl' s{JC s܊," z Y {X {Lz cPyՙ h󇍦~/  nX):F%i8ó00>Fh>ޗّ../[./[|b*Kob*Ko}r[YyhvHPae -Cx2BxYN#59C[IbK >B&8 ߏ8o/kAõx)wMhHbnRHbn.-.`!7]1 Z -i[iS˼**;;+ aY~ cӋ;y,Ӌ;yj Y$XSK$s0jX j")?,=..VCdiujKg>䧿M{^6!$&HK6* Ǻ]G+5Qu 6JuHp >| ՗ -A✄< A✄<XQ2A0. "j_ZYp #JTR'7{S(|IJU (|IJ (^ )ch^ j)|o43*  ~*^ A% )/ݏ-1Q #2 2y\rs3j•5a.bQ978oP9J4< cBOECn D1?l  E#=zC3Eb1 F<( In`P IEf;Kia3Kia3OKia3 Kia3R XXR0Lfb R0Lf R0Lf R0LfYV-#0 WMB*B \+u'Ya]m˸ g\2qO2L@rXC thz|'{c=wi 갥l/C􄮇􅢦 \ yE̊DmX;%c :7mJ[)[1 \-S\ dB1MNp]{~Qb O"Q!D (*"(3T | œL)Ȳi #XTm !XTm $XTm ,XTm s -GE * V q]92q] q] =q] q] Y eR+G}(@ɡ Û/B*v ,S8<~&ڪ C #wqNJwqNJPJolODںPDںP (V3V !g  6AKӳvUqk WjYeI $vg>eN ?ZYL E.2 ,ܔx>k G 㰚znQk蚇C*П1jS {-ަ2Z2Z :;NQFiE)κa֢z%N cEns`R7q51bo?}0 aQ>c(8D ,9Rx n f̀] `r f!p ")ozK"3/B|"%P* *%W [(/r/a-Yq]-Yq]9-QqCN6548pl/98[{ d9ؽ>naQ{DC[TYC{A=E-`FGi| MH@,5 $J]FYK!/< K3XOq* R#wy+sbR#wy+s R#wy+s Rwe) /Rwe) Sd;ZUnan=Unan=XAq@* Xzc; %_C}ܨ i_C}ܨ `$ǔbHePNe=q>E>gY9v6ck{Vq k{VqkF:vlR1lR ,lR $lR nѥubp;x s  QMij h3 1s 1Y >`uj43 u9Lyʂi4Y P5e#`mk&,s?(E1K )ff9*ȉ*ȉS,`ꅴj,`ꅴ>0!1 1Y!3I 5N<963*:63*:7aiD68[|>:ގ=;U *>TxЎ=A؃4Bg^q C60C8C60C60C60EagJet%Lˆ%-YvLˆ%-Y M!bP@M!bP@ M!bP@PX*T;=PX*T;=,T@* ,Xl)DSXl)DZXǿSXRsZZidðl\d,w\d,w\d,w\d,w]*>C _A $k `_YEd0~ey_ ^ey_ >f|?ol+ e jmq'.nVVo]z jr2tr2tu}?QvFXIJ z "]b|l[uO*!t}d+f1DjݳNOcL>P?~U3n53n5#1 g AqaVDlRDlRiH\%EwK,A /L0K :rN7s+@|t iósX[UiDH8}/+,mR3TI #S!O% a}ME  C z6Q]ͅ,W mwLkɚ(jY8}y *]  ϗP i+ ϗP ( ϗPs'.hOc. ai[za Wi#tڦde  ݫ9 }hS:UlgGPNT( 귭.[ aSOK7(>!))."g ut)g utR &-0<] tL߭У c߭У-)> NE+Vč>C[6ftb(yBz-rv -rv‚.wuft t # 4d?= 4d?=j 4d?= / 4d?= i*a փ cQm;c  :1'L-Nlb/D>+M5L D [ 􅺤 gҨ dE $Jl&|%{O &mkR'U 'Ut'(븹 *Eu(-q 1# 2v4^ۅ}lh5Ec =gל=gל?O1 ?O1RAFܜeaHcWSKK02B SبV՟-?3Y%>5Y]-}A j [^e0k\!!' e+ Ro'ceAZ>p]jmp^h ,p2~#swSy>us*v"ȯY x<*;yCֵyCֵ|1t| TZ|+6t`7 |+6t`7|+6t`7d~qm1 "- o$ o [[ [ 3|-X3|-XKPQڐ^GPڐ^GR7.:M!_CR;!i =˅W V|  {gf>F1t䐍 ^ OZ ~u4n>V ։y_g njˏ=³{5_ #$߸Qk UWo (>$ӪMv[ӻa>IfMSF+,{)ʊDn$~=SW"kw ~ksRK K$![O seGFI;n<0H HHQ3_&>/tOFN> >SZXҍ Jz[ Ths[M>` (M>` 0q  ߗSL x3Z?thd 4* |4* :q[` auMk\k$ Hl[Y>q+q+R,iji 14S=Z 4՗+Y6;76;76oWwz>;A$wj;A$w dR-'gC[fgً dhJh/:i1N|)mU. o^-q.!1-r~UCw?E xq=pݤxu|4 ^ ~Kc-@ ֿFY*/qd'c=8$^ =8$^].ȋsLݯ `kSء $rqE~ +s hj.sDX=k (_fʛbiAN˥k- k-jSB"]1SB" SB" 3 XVVX>鿨 %>Nq@F *,j 3V'ƹڋd aڋd _FY2qjBDSk( Ɖ8r -ǀ_ΌkX% iȶFvȶF o@  o@,>[zy`asu,%2u,%2u,%2$4"{QIA}}K)7bQt9Rbֈfn`Olܺs؍F% bI eA11! ތc@&pT̓"þ \ ck:VU>Fڞe W96tW96 W96 ]˯U_e "@V4$K9vP 9vP X"FPuKFPuY K' ;s^tf)Ò7 sJh tQgQ #rR$>4$>4$>4*"zk5 ,cXgs0*ec0,$m0A-:2^$jSvK;d ZbSZ*Fe j[]s]WC9]u-cWwfBE cWwfBX cWwfBjc"H8"d\uFZrRJ wavɶwy^/4zܫ{Ht[|rϤ|v|RN \>}뱌8C 6wɕJ$(ue:걓tlʉm *ϥ 9^f$wԒ!J9MD B # o o \Q 2 dQ 2 nH b,. )-#%L/uD#A$]*c#R8xSR8x R8x$77ΐ6䥯a#pR{RļrSw7GJb>b{"""  i i i  i Y i ZиD?x]Ydk da32 a~8b#J}`sl9cH`v[-yg@֯ Թ<* sEqB b+  EVJ f;_] ( ش"^U !mpv, mpv,mpv,]mpv,/_/T (hv"Shv"ZS aS&<XK tf!B~ 1  z5 = =%&_%I%ZD%S (FP p(FP p(9?^j +f ,+f 0;OkZu \46vi 4 ; ֠)=uA # sB YC+F[D͡BFI~UGEIU GXG H_WL HQC ,I+9T۫>I+9T۫ 'I+9T۫ I+9T۫ I+9T۫ Ki-8> Ki-8 KNӊKOs#%rrOצ^|R6U3-pVEUم_JParaHF @7Rd[B3j]n?os-Soh<Koh<QtE tLxXimRDyv?|:>y y y7dNTRy͹Ew ͹Ew ! ͹Ew ^O!=*[U?s?x_AxUP1_P1_5+5d;2 JC#^JC#^j;Y" ^m4 (oq05 Z / 6R / 6R =̃ŨW/NWde9U He}JXR$X *94py (Ķ!``Udp Ɵ"wR,n=R0ϰѦ/J\ J\ mN>К]>К] S45:众Lٻ jW, { ,E1s] is WM S& sMV".jk X% e w=ܦ;Ͳ@ bi7yЦ!@ 4d53td53bI,- ͖R.͖ Pk~|Pk~ $xv EQ}  U^t sWi&ȡ 7_v 6bwϯp:( c2}~g  kC\g/(7Y>!tA8"/ 1!! !t!fh{^%5> )MmCS+ vu-Wl -klV-klVL1Dr7x79d<: Eh eM"WbXѿ@Hv8YWCt ]ߵ~Ê!_U7.`nKci5; f2Y{vm ~]8q5ށES s@R@ jt$BuUDEm cw37j yA KygD.(y/_|G 1fA{,sc{ c{ cߤ( ɤuSjs}*BK? tH%k H%k RwL wL wL_FȴEjvnp uzA*h^.|$cEwZ $!&"#'jPUq $2UD@(Էu=(Էu=(Էu=R(Էu=Kʎ'z+$`EwWwWc0-΂0`<#hM/hM/ZhM/Q׊qҐe= e/Ґe=v-ܫC dك"la``9.?DCq  $)-~KJguk)KJgutyt[ +V3> l~ > HݣvƔz o " ctf p RY_O Ob uѨ8$uѨ8ok"QvFvF uǹ > S8EO{+t à(/a(wEhЗ}%pvN (nt':9(vdE -,E~,t!}/Ct0R 06~R3*;Xi{ ^O?m^M@Z! AYUOQAyrBZ+D4 FeO5]G1); Jl !Kt.KTLBov8 LR C LH*vM MW2158M%ÎYN gq& TK3\DRTC䣐Ut38~ iV萱 V萱XY| Y٬(_o^r `NLkd栶csea;}s ea;} ij?Bjݒ\AtoW<vp '[cYuaЉ8,ubq%>ubq%>vx{A|z_w>{:}F,:Mh>G'ԛBbKřo} ak/l_k/l_JZmO'|  (C6\gv>|OW!lme|aѼ[jѼ[OѼ[ҕ2 jM+Fi"Bv!>Mmq| $prcf>}U6 1}]?t vB.:B.:lve v KRg0m bmV2K|i>>2h * a'S Ŝ-~N>|ʹ ӱ:y -Ίyo4=pn `('vիb i] 1[=7_Hdӟ>.}.2ߠ֎eLߠ֎eRߠ֎e ߠ֎eZߠ֎eWM9h09 R 09 *Er6n) r6n)r6n)Q,S-2&>eJΰjr% jr%DR=k yM+ a6'<b!$Yb!$Y ,b!$Y ax~R((-]jgk fnr E|& Ano. _ƣ _ƣ .; V; !t%ML (%g+!8s2fxŗ 5Ò}Z8\ =>"Հ]mC=>"Հ]m>@YJ  m>7 R ?8Ei]Bʱ[ !EL7\EL7\! F] IH.Q NYd O]~QF* f"QF*9 QQ6R ?8R(B\mmS,SVĊt cX7Yb^Yb^]9&Rdǐjdl<vc%E$ wo|&eTI |u骻Uv ~bG:ϙW IvO ,Ҡ}nrI3fsg `F{'0Ru) %#LjfdLiR)"pү \AwךaZ( $ )z 6?;( (Xþ1djJhJ> aQV:N +AY^KjǝCI[԰Kp>y1q&D);ϲqtXک1Lۚ䬉~LܾVɩ:w (ݐyĬYBWLO1UO1UEYE 1GE E a`H0 -_"g$ζA7s N,v Yn! Yn!Z.xJxJjA3sR6  j$h j9\ s4?Ҟ /2Qf eQf Qf ?5ѲkV= sDtc( aDtc(sL;hL;j-ASj'^Lދr UsQRC\OC\C\R$i(ƻK(ƻ*,1vJ>*pK,`v 4ݨ5'T^>6I 7-°[<ʭS_C$BԁkH KƎqEMhdN-|lQZQmk Qmk Qmk Qmk U< V$Z\^ 8'H$\^ 8'H$|\^ 8'H$]+:j_L50d^Sfzpiw fzpiw fL"!^YfankogP gj"( $l ( l mjnmqHv{x#x́T>yzAx{L~|Xfg8Rfg8>3G9f_eݖ'08Ҕ>@" NHCbe7Q )nURn]/F:VV{rVUUP  B% {\o= #/ TբB]j] x[9Re*D e3N z[6)q1qsWarEQIT?EGs]: KgSгyʲ '`;b''`;t'`;"csէ CqB\'0!jع6E6 eO@ꄍ ꄍ ]渱N.cBDs  QDvCS)]FCS)]jCS)] iCS)]XAsWQl.S )KRE곾,Z/2Н gGgGQuZ~ +BVP \ aJ  ad/gV ]1Pk2pE Ez}J@ /Wy8 /Wy8ހ! -xW;"!w%˳ #v%#$VA<%Zt%kڎ *ϫ4E+PA,snj.M,K.M,R.ʁ vTɬVZj$8\! [Y0xx\r\rQ]xoDb? mdTQkf]6lt icx/ i$} j?&ӓlʋdkNmK1]N-mb{+mb{p}S p}Ss.<rsǗ {M{} qsv8>椃l>椃l 椃l .`fAnkj[+ t9߯lAM!  ! H3A $κ5 s'Yѻbc͙ K: F* 9 V[+vJ" %B2D H Wzz /#X t8 ilNx 9 < %H"> %H" s ʭf c0vF;f #ذ^! d:01r$<a2 |_kD[ lH@䦃ğqSF/F/ PxDuS{?Xګ۫RL #ُJ [%1Uš_ sn M8R{^yp B%{%ذ| Y^Wfruit-2.1.dfsg-1.orig/copying.txt0000600000175000017500000004365510402400155016313 0ustar oliveroliver GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc. 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Library General Public License instead.) You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things. To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you". Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. 1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 9. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. 10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) 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 2 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, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Also add information on how to contact you by electronic and paper mail. If the program is interactive, make it output a short notice like this when it starts in an interactive mode: Gnomovision version 69, Copyright (C) year name of author Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, the commands you use may be called something other than `show w' and `show c'; they could even be mouse-clicks or menu items--whatever suits your program. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' (which makes passes at compilers) written by James Hacker. , 1 April 1989 Ty Coon, President of Vice This General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Library General Public License instead of this License. fruit-2.1.dfsg-1.orig/technical_10.txt0000600000175000017500000001305610402400155017065 0ustar oliveroliver *** WARNING *** This file described the older Fruit 1.0 The evaluation function has been mostly rewritten since. The rest is still mostly accurate. Fabien, a very lazy man. --- Fruit overview -------------- Fruit was designed to help with the study of game-tree search algorithms, when applied to chess. It is now released as a chess engine, which is a somewhat different category of programs. Therefore the source code contains entire files and also functions that are either not used by the engine, or could be replaced with a much simpler (although somewhat less efficient) equivalent. As a chess engine, Fruit combines a "robust" search algorithm with a "minimalist" evaluation function. The latter is not a design choice, and will hopefully change in the future. The following description is only a very incomplete description. Please consult the source code for an absolute definition. The search algorithm was designed to accommodate with heavy forward-pruning eccentricities (such as search inconsistencies). Note that in Fruit 1.0 only null-move pruning is used as a forward-pruning mechanism. Board data structure -------------------- Fruit uses the 16x12 board. Although this structure is not very popular, it can be seen as simply combining 10x12 (mailbox) with 16x8 (0x88). 0x88 was picked in Fruit because of the small memory requirements of vector calculations (much smaller tables). It is possible that Fruit uses bitboards for pawns in the future. Search algorithm ---------------- The main search algorithm is a classical PVS with iterative deepening. Search enhancements such as a transposition table and null-move pruning are also used (see below). A few details in the PVS implementation are not-so-standard and are there to supposedly enhance the stability of the search (like reducing the consequences of search inconsistencies). For example the re-search window after a scout fail high of score "value" (with value > alpha) is [alpha,beta], not [value,beta]. As another example, I only allow null move when the static evaluation fails high (i.e. eval() >= beta). Whether these features improve the strength of the engine is an open question. Transposition table ------------------- Fruit uses 4 probes and replaces the shallowest entry. Time stamping is used so that entries from previous searches are considered available for overwriting. Enhanced Transposition Cutoff (ETC) is also used 4 plies (and more) away from the horizon. Null move --------- Fruit uses R=3 recursive null move, even in the endgame. In Fruit, a precondition to using null move is that the static eval fails high. One of the consequences of this is that no two null moves can be played in a row (this is because the evaluation is symmetrical). This is a usual condition but notice that in Fruit the null-move condition is "pure" (independent of move paths). The fail-high condition was selected for other reasons however. Also, a verification search is launched in the endgame. Move ordering ------------- The move ordering is rather basic: - transposition-table move - captures sorted by MVV/LVA - promotions - killer moves (two per level, no counters) - history moves (piece-type/to-square table, with "aging"). Evaluation function ------------------- The evaluation function is pretty minimal and only includes: - material (only sum of the usual 1/3/3/5/9 values) - piece-on-square table (that can probably be improved a lot) - static pawn-structure evaluation (independent of pieces), stored in a hash table - a few boolean features supposed to represent some sort of piece activity, such as a penalty for bishops and rooks "blocked" by a pawn of the same colour in the "forward" direction. Note that some vital features such as king safety are completely missing. I cannot recommend such an approach in a serious program. There are two (bad) reasons why the evaluation is so "simple": 1) Fruit was designed to experiment with search algorithms (not just for chess) 2) I just can't be bothered with trying to design a "good" evaluation function, as this would be an extremely boring occupation for me. Speed ----- Fruit is not fast (in nodes per second) given the little it is calculating. I actually plan on undoing more "optimisations" in order to make the code shorter and more flexible. I will care about raw speed when (if at all) Fruit's design is more or less "fixed". Notes for programmers --------------------- Some people find that Fruit is surprisingly "strong" given the above (dull) description. The same persons are probably going to scrutinise the source code looking for "magic tricks"; I wish them good luck. If they find any, those are likely to be "bugs" that I have overlooked or "features" I have forgotten to remove (please let me know). The main search function is full_search() in search_full.cpp I suggest instead that one ponders on what other "average amateur" engines might be doing wrong ... Maybe trying too many heuristics (they might be conflicting or choosing weights for them is too difficult) or code that is too complex, maybe features that look important but are actually performing no useful function ... Sorry I do not know, and I don't think we will find the answer in Fruit ... Disclaimer ---------- Lastly, please take what I am saying with a grain of salt. I hope that the reader is not completely lacking any sense of humour and I certainly did not intend to be insulting to anyone. fruit-2.1.dfsg-1.orig/readme.txt0000600000175000017500000005142310402400155016070 0ustar oliveroliver Legal details ------------- Fruit 2.1 Copyright 2004-2005 Fabien Letouzey. 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 2 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, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA See the file "copying.txt" for details. General ------- Today is 2005/06/17. This is Fruit 2.1 (Peach). Fruit is a UCI-only chess engine. This distribution comes up with Windows, Linux and Mac OS X executable files as well as an opening book and platform-independent source code. Sorry that the word "Fruit" looks like "Fritz" (it certainly sounds different in English). This is obviously unintentional (or is it not, yes? I don't know anymore)! PS: How would "Deep Fruit" sound? :) Official distribution URL ------------------------- The official distribution web site is Leo Dijksman's WBEC Ridderkerk: http://wbec-ridderkerk.nl/ This is where you should be looking for Fruit updates in the future. Version ------- "2.1, what's with the version number? I invested $1M on 2.5 at the stock market and now who's gonna bring my money back???" Not me! Version numbers have nothing to do with chess strength, but with the quantity of code change and the position of the program in long-term plans. I decided to enter the Massy tournament (2005/06/12) only two weeks beforehand, and I had to quickly decide for the version that would play. There were only 3 main changes as compared with Fruit 2.0, because I had also been working on other programming projects. After the tournament, "Fruit Massy" was tested and it appeared obvious that some strength had been gained. Fruit 2.1 is a "hurry release" of the tournament version. It took a few more days to fix an interface problem (hash-table size under Arena) and add opening-book code (compatible with PolyGlot). OK so in short I switched from 2.0 to 2.1 because there were few changes and I don't especially have plans for a 3.0, sorry for that. For a description of the main additions, see the History section. Files ----- The archive contains executable files for Windows, Linux and Mac OS X, as well as source code and a small opening book. The file "technical_10.txt" only concerns the - obsolete - version 1.0 of Fruit (because I am too lazy to edit it right now AND also was when releasing Fruit 2.0 AND also ...). The search part of it is still valid for Fruit 2.1 (except for the addition of history pruning). However the evaluation function has almost been completely re-written. Again, see the History section for a succinct description. Compiling --------- The distribution comes up with Windows, Linux and Mac OS X binaries. Compiling is therefore not necessary on those systems unless you want to make a change in the program. In any case this section describes the compiling procedure, it is safe to skip it. Fruit was developed on Linux using g++ (the GNU C++ compiler). The source code has also been successfully compiled on Windows using both MSVC and Intel C++ compilers. I do not know about FreeBSD/OpenBSD/NetBSD or other POSIX-compliant operating systems, but I don't expect many problems. If you had problems getting Fruit compiled on your system, but somehow managed it in the end, please let me know what changes were necessary (see the contact section for details). I have now included my Makefile for Unix systems. It is a bit weird (it uses GNU extensions), I hope it works on your OS (let me know if it doesn't). Associate the "-march" option with the appropriate value on your system, and type "make" in the "src" directory. If you find better optimisation options for g++ please let me know. XBoard / Winboard ----------------- Fruit is a UCI-only engine. This is unlikely to change in the future. Fruit and other UCI engines can be used with XBoard or WinBoard (or other xboard-compatible interfaces) with the help of PolyGlot (UCI-to-xboard adapter). You can download PolyGlot at http://wbec-ridderkerk.nl/ Opening book ------------ *** NEW *** Starting with version 2.1, Fruit handles an opening book, tada! (<- Windows 3.x sound for those old enough to remember). I cloned the code from my own software (assuming it was legal) "PolyGlot", sorry myself (it's OK /Ed). And some say that open-source is not useful! Now, I hear it already. Tournament directors will want me to designate an official book that they should use. To keep download overhead low, I decided to include only a small book in the main archive: it's called "book_small.bin". It is in fact the same as "fruit.bin" in the PolyGlot 1.3 release. However, I would prefer that Fruit has access to a larger book during tournaments. At the time I am writing this line, "book_corbit.bin" is planned to be made available on WBEC. You can build your own book from a PGN file by using PolyGlot on the command line. PolyGlot is available for download at http://wbec-ridderkerk.nl/ Tablebases ---------- Fruit does not use the so-called Nalimov tablebases, sorry for that. This is unlikely to change in the future. The reasons for my decision are: - the source code by Eugene Nalimov is not "free of use" (although you don't have to pay for it) - the design of the code does not work well with Fruit's "small memory footprint" requirement (for example the executable file would be at least twice as large with the TB code). It must be said though that I have great respect for Eugene's contribution to the computer-chess community. As for Fruit I plan on using selected "bitbases" in the (very far) future. For now some draws are recognised by the evaluation function, and - despite the errors - this somewhat reduces the penalty for not using tablebases. UCI options ----------- You are advised to skip this section unless you are completely crazy about computer chess. Here I give you another chance to skip the section, as you should not be reading this ... Well you have downloaded Fruit in the first place so I suppose I can't do anything for you anyway ... I give up! - "NullMove Pruning" (Always/Fail High/Never, default: Fail High) "Always" actually means the usual conditions (not in check, etc ...). "Fail High" adds the condition that the static evaluation fails high. Never use "Never" (ever)! OK you can use "Never" to test a Zugzwang problem, but ask your Momma first! I expect that this option has little effect (assuming the first two choices only). I only added it because most engines do not use the fail-high condition. - "NullMove Reduction" (1-3 plies, default: 3) 3 is rather aggressive, especially in the endgame. It seems better than always using 2 though. I have not experimented with adaptive solutions. - "Verification Search" (Always/Endgame/Never, default: Endgame) This tries to solve some Zugzwang-related problems. I expect it to hardly have any effect in games. The default value should be sufficient for most-common Zugzwang situations. - "Verification Reduction" (1-6 plies, default: 5) 5 guarantees that the cost of verification search is negligible in most cases. Of course it means Zugzwang problems need a lot of depth to get solved, if ever! With such a reduction, verification search is similar to Vincent Diepeveen's "double null move". - "History Pruning" (true/false, default: true) A bit dodgy, but fun to experiment with. I added it in Fruit 2.0, and I still haven't found the time to test it seriously ... It should help in blitz, but it's possible it actually hurts play in longer games(!!!). One day, I should check this. One day ... - "History Threshold" (percentage, default: 60%) This is the thing, as it affects the search tree! Lower values are safer, and higher values more aggressive. THIS VALUE HAS NOT BEEN TUNED! There is a good chance Fruit's strength can be improved by changing this option. - "Futility Pruning" (true/false, default: false) Very common but controversial. Makes the engine a tiny bit better at tactics but slightly weaker positionally. It might be beneficial by a very small amount, but has not been tested in conjunction with history pruning yet. - "Futility Margin" (centipawns, default: 100) This value is somewhat aggressive. It could lead to problems in the endgame. Larger values prune less but will lead to fewer positional errors. - "Delta Pruning" (true/false, default: false) Similar to futility pruning. Probably safer because it is used mainly during the middlegame. Has not been tested with history pruning either. - "Delta Margin" (centipawns, default: 50) Same behaviour as futility margin. This one is probably safe. - "Quiescence Check Plies" (0-2 plies, default: 1) Fruit tries safe (SEE >= 0) checks at the first plies of the quiescence search. 0 means no checks at all (as in most older engines). 1 is the same as previous versions of Fruit. 2 is probably not worth the extra cost. It could be interesting when solving mate problems though. - evaluation options (percentage, default: 100%) These options are evaluation-feature multipliers. You can modify Fruit's playing style to an extent or make Fruit weaker for instance by setting "Material" to a low value. "Material" is obvious. It also includes the bishop-pair bonus. "Piece Activity": piece placement and mobility. "King Safety": mixed features related to the king during early phases "Pawn Structure": all pawn-only features (not passed pawns). "Passed Pawns": ... can you guess? I think "Pawn Structure" is not an important parameter. Who knows what you can obtain by playing with others? History ------- 2004/03/17 Fruit 1.0, first stable release ------------------------------------------ Fruit was written in early 2003, then hibernated for many months. I suddenly decided to remove some dust from it and release it after seeing the great WBEC web site by Leo Dijksman! Note that Fruit is nowhere near ready to compete there because of the lack of xboard support and opening book. Note from the future: these limitations seem not to be a problem anymore. Fruit 1.0 is as close to the original program as possible, with the main exception of added UCI-handling code (Fruit was using a private protocol before). It is a very incomplete program, released "as is", before I start heavily modifying the code (for good or bad). You can find a succinct description of some algorithms that Fruit uses in the file "technical_10.txt" (don't expect much). 2004/06/04 Fruit 1.5, halfway through the code cleanup ------------------------------------------------------ In chronological order: - added mobility in evaluation (makes Fruit play more actively) - added drawish-material heuristics (makes Fruit look a bit less stupid in some dead-draw endgames) - tweaked the piece/square tables (especially for knights) - added time management (play easy moves more quickly, take more time when unsure) - enabled the single-reply extension (to partly compensate for the lack of king safety) - some speed up (but bear in mind mobility is a costly feature, when implemented in a straightforward way as I did) 2004/12/24 Fruit 2.0, the new departure --------------------------------------- The main characteristic of Fruit 2.0 is the "completion" of the evaluation function (addition of previously-missing major features). In chronological order: - separated passed-pawn evaluation from the pawn hash table, interaction with pieces can now be taken into account - added a pawn-shelter penalty; with king placement this forms some sort of a simplistic king-safety feature - added incremental move generation (Fruit was starting to be too slow for my taste) - added futility and delta pruning (not tested in conjunction with history pruning and hence not activated by default) - improved move ordering (bad captures are now postponed) - added history pruning (not tested seriously at the time I write this yet enabled by default, I must be really dumb) - cleaned up a large amount of code (IMO anyway), this should allow easier development in the future 2005/06/17 Fruit 2.1, the unexpected ------------------------------------ Unexpected because participation in the Massy tournament had not been planned. What you see is a picture of Fruit right in the middle of development. There may even be bugs (but this is a rumour)! I have completed the eval "even more", not that it's ever complete anyway. I have to admit that I had always been too lazy to include king attacks in previous versions. However, some programs had fun trashing Fruit 2.0 mercilessly in 20 moves, no doubt in order to make me angry. Now they should need at least 25 moves, don't bother me again! - added rook-on-open file bonus; thanks to Vincent Diepeveen for reminding me to add this. Some games look less pathetic now. - added pawn storms; they don't increase strength but they are so ridiculous that I was unable to deactivate them afterwards! - added PV-node extensions (this is from Toga), e.g. extending recaptures only at PV nodes. Not sure if these extensions help; if they do, we all need to recognise Thomas Gaksch's contribution to the community! - added (small) king-attack bonus, the last *huge* hole in the eval; now only large holes remain, "be prepared" says he (to himself)! - added history-pruning re-search; does not help in my blitz tests, but might at longer time control; it's also safer in theory, everybody else is using it and I was feeling lonely not doing like them. OK, Tord told me that it helped in his programs ... - added opening book (compatible with PolyGlot 1.3 ".bin" files) - fixed hash-size UCI option, it should now be easy to configure using all interfaces (there used to be problems with Arena, entirely by my fault) Breakpoint ---------- Why a breakpoint now? For the first time of its life, after the recent addition of king attacks, Fruit has all major (but admittedly few others) evaluation components. Don't get me wrong: they all need a lot of refinement, but the code layout is there. When Fruit 1.0 was released, some programmers told their surprise that the program was playing OK-ish (not that I agreed) despite having virtually no eval. They might have wondered whether their larger code was really useful. Since then, I have mostly added classical evaluation features. I believe that Fruit has gained overall 150 to 200 Elo points by evaluation alone. Here I just want to explain that the minimalism of Fruit 1.0 was never a goal, but the consequence of the "as is" state of the distribution. In the end, the moral is safe: eval is good for you! Also "don't jump at conclusions" seems appropriate. Future? ------- Because of this "hurry release", I haven't had the time to continue cleaning up the code. This is the main reason why the version number is only 2.1 I hope to provide a cleaner alternative, perhaps tuned a little, in a few months. Maybe it is time to consider adding features like MultiPV. Although I believe I could keep on increasing strength by adding more and more eval terms, I have little interest in doing so. I would not learn anything in the process, unless I develop new tuning/testing techniques. Ideally I would like to spend more time in alternative software, like my own GUI perhaps (specific to engine testing/matches). Nonetheless, a lot can be done like tuning existing code or building an adapted opening book. Therefore, don't hesitate to contact me if you are interested in giving a hand. Computer testing time is especially welcome, but be warned that I am quite demanding. "I can include test versions in my Fritz-GUI swiss tournament." -> forget it, as well as my email address please, thanks a lot! Lastly, don't take it too seriously. I am tired and always under big pressure before a release, because I want everything to go smoothly. Who knows what I will think in a month? Bug fixes --------- Contrary to Fruit 2.0, Fruit 2.1 checks the legality of the hash-table move before playing it. This could make Fruit 2.0 crash in rare occasion (like once every 10000 games). This means that if Fruit 2.1 crashes, the bug is somewhere else. Fruit 2.1 will now tolerate a hash-table resize after initialisation. This seems especially important for use with Arena. Unfortunately, it also raises the notorious 1MB problem of some "bug"-full interface ... Known bugs ---------- Fruit always claims that CPU is 100% used. This is apparently a problem in the standard C libraries on Windows. Mailbomb me if fixing this would save lives (especially children)! I prefer waiting for late users to throw away Windows 95/98/ME before adding an NT/2000/XP/... solution. Thanks ------ Big thanks go to: - Joachim Rang and Robert W. Allgeuer for spending so much time testing different versions/settings of Fruit and getting actively involved in the project in general. I don't know why they got interested in Fruit but the current version would definitely NOT exist without them. - Bryan Hofmann for compiling Fruit (and other engines) for Windows - Aaron Gordon for the Linux binary and long-term friendship; he's the one who showed me CCC years ago! - George Sobala for the Mac OS X executable - Leo Dijksman for hosting the Fruit distribution (and also the PolyGlot adapter) on his web site (see Links) and all the rest: tournament, testing, documentation, etc, ... For those who have not noticed (e.g. people still using a TRS-80), Leo is EXTREMELY serious in what he is doing. A reference in behaviour! - Ernest Bonnem for making it possible for Fruit to play in the Massy 2005 tournament - Tord Romstad for being my virtual twin brother; who knows if we can materialise in the same place some day? - You, for having patiently waited for this release and still being reading this file (don't worry, it's nearly finished) As usual there are dozens missing, it is simply impossible to include everybody. Links ----- - engine lists, and much more: Leo Dijksman's WBEC Ridderkerk: http://wbec-ridderkerk.nl/ Alex Schmidt's UCIengines.de: http://www.uciengines.de/ - free chess GUIs: Tim Mann's Chess Pages: http://www.tim-mann.org/xboard.html Arena: http://www.playwitharena.com/ - computer-chess fora: The Computer Chess Club (CCC): http://www.talkchess.com/ Volker Pittlik's Winboard Forum: http://wbforum.volker-pittlik.name/ - mostly programmer stuff (if you have several lives to spend): Dann Corbit's FTP: ftp://cap.connx.com (do *not* use passive mode) Sorry for the dozens I simply had to leave away (but you know them if you went that far) ... Contact me ---------- You can contact me at fabien_letouzey@hotmail.com For a long time, I have been waiting in vain for the "Fruit Fan Club" T-shirts and donations of source-code improvements of several hundreds Elo points I had been asking for. About the latter I have to say that it is not very smart to delay much further: the more you wait and the more difficult it will be, but I suppose that it had not yet been challenging enough ... Anyway, I have decided to launch a new initiative. What's more boring than reading one's own code at 3am tracking down a bug that might not even exist, know what I mean? I have the solution: let's fix each others bugs! The new operation is called "Fix my Bugs and I Fix Yours!" (patent pending). It works as follows: 1) You fix one of my bugs (excluding null move) before 2005/09/01 00:00 UTC (the acronym that does not mean anything in either English or French, so that both parties are equally disappointed). 2) I select the most artistic bug fix after the date limit. A jury will be nominated if necessary. 3) I fix a bug of your choice in your program (excluding "it plays bad moves"), it's that simple! This is not irony: contrary to popular belief, there really are bugs in Fruit. Even search bugs. I just couldn't be bothered with fixing them so far. Sorry that I can't give you more hints, for now I am using them to find clones effortlessly. See you in September!!! The end ------- Thanks for listening, and have fun with Fruit! Fabien Letouzey, 2005/06/17.