$SP,"wpawn",1$ $SP,"wcastle",2$ $SP,"wknight",3$ $SP,"wbishop",4$ $SP,"wqueen",5$ $SP,"wking",6$ $SP,"bpawn",7$ $SP,"bcastle",8$ $SP,"bknight",9$ $SP,"bbishop",10$ $SP,"bqueen",11$ $SP,"bking",12$ //These are weights for scoring positions. #define SHIFT_PIECE_SCORE 4 #define SHIFT_POSSIBLE_MOVES 0 #define P_PAWN 0 #define P_ROOK 1 #define P_KNIGHT 2 #define P_BISHOP 3 #define P_QUEEN 4 #define P_KING 5 U8 *imgs[12]={$IB,"<1>",1$,$IB,"<7>",7$,$IB,"<2>",2$,$IB,"<8>",8$,$IB,"<3>",3$,$IB,"<9>",9$,$IB,"<4>",4$,$IB,"<10>",10$,$IB,"<5>",5$,$IB,"<11>",11$,$IB,"<6>",6$,$IB,"<12>",12$}; I64 piece_scores[6]={ 1<pieces,*cur_p=&p[piece_num]; I64 result=0,i,j,k,x,y,xx=cur_p->x,yy=cur_p->y; I8 brd[BD_SIDE*BD_SIDE*sizeof(I8)]; BrdFill(brd,p); nobound_switch (state->pieces[piece_num].type) { case P_PAWN: if (!state->cur_player) { if (BrdPeek(brd,xx+1,yy)==T_CLR) { mvs[result].x=xx+1; mvs[result].y=yy; result++; if (xx==1 && BrdPeek(brd,xx+2,yy)==T_CLR) { mvs[result].x=xx+2; mvs[result].y=yy; result++; } } if (BrdPeek(brd,xx+1,yy-1)==T_PLAYER1 || state->potential_en_passant_victim.x==xx && state->potential_en_passant_victim.y==yy-1) { mvs[result].x=xx+1; mvs[result].y=yy-1; result++; } if (BrdPeek(brd,xx+1,yy+1)==T_PLAYER1 || state->potential_en_passant_victim.x==xx && state->potential_en_passant_victim.y==yy+1) { mvs[result].x=xx+1; mvs[result].y=yy+1; result++; } } else { if (BrdPeek(brd,xx-1,yy)==T_CLR) { mvs[result].x=xx-1; mvs[result].y=yy; result++; if (xx==6 && BrdPeek(brd,xx-2,yy)==T_CLR) { mvs[result].x=xx-2; mvs[result].y=yy; result++; } } if (!BrdPeek(brd,xx-1,yy-1) || state->potential_en_passant_victim.x==xx && state->potential_en_passant_victim.y==yy-1) { mvs[result].x=xx-1; mvs[result].y=yy-1; result++; } if (!BrdPeek(brd,xx-1,yy+1) || state->potential_en_passant_victim.x==xx && state->potential_en_passant_victim.y==yy+1) { mvs[result].x=xx-1; mvs[result].y=yy+1; result++; } } break; case P_ROOK: for (j=0;j<4;j++) { x=xx; y=yy; for (i=1;i<8;i++) { x+=gr_x_offsets2[j]; y+=gr_y_offsets2[j]; k=BrdPeek(brd,x,y); if (k==T_CLR || k==cur_p->player^1) { mvs[result].x=x; mvs[result].y=y; result++; if (k!=T_CLR) break; } else break; } } break; case P_KNIGHT: for (j=0;j<8;j++) { x=xx+knight_x_offsets[j]; y=yy+knight_y_offsets[j]; k=BrdPeek(brd,x,y); if (k==T_CLR || k==cur_p->player^1) { mvs[result].x=x; mvs[result].y=y; result++; } } break; case P_BISHOP: for (j=0;j<4;j++) { x=xx; y=yy; for (i=1;i<8;i++) { x+=bishop_x_offsets3[j]; y+=bishop_y_offsets3[j]; k=BrdPeek(brd,x,y); if (k==T_CLR || k==cur_p->player^1) { mvs[result].x=x; mvs[result].y=y; result++; if (k!=T_CLR) break; } else break; } } break; case P_QUEEN: for (j=0;j<8;j++) { x=xx; y=yy; for (i=1;i<8;i++) { x+=gr_x_offsets[j]; y+=gr_y_offsets[j]; k=BrdPeek(brd,x,y); if (k==T_CLR || k==cur_p->player^1) { mvs[result].x=x; mvs[result].y=y; result++; if (k!=T_CLR) break; } else break; } } break; case P_KING: for (j=0;j<8;j++) { x=xx+gr_x_offsets[j]; y=yy+gr_y_offsets[j]; k=BrdPeek(brd,x,y); if (k==T_CLR || k==cur_p->player^1) { mvs[result].x=x; mvs[result].y=y; result++; } } if (!Bt(&state->moved_mask,piece_num)) { if (!state->cur_player) { if (state->pieces[0].player>=0 && !Bt(&state->moved_mask,0) && BrdPeek(brd,0,1)==T_CLR && BrdPeek(brd,0,2)==T_CLR && BrdPeek(brd,0,3)==T_CLR) { mvs[result].x=0; mvs[result].y=2; result++; } if (state->pieces[7].player>=0 && !Bt(&state->moved_mask,7) && BrdPeek(brd,0,6)==T_CLR && BrdPeek(brd,0,5)==T_CLR) { mvs[result].x=0; mvs[result].y=6; result++; } } else { if (state->pieces[24].player>=0 && !Bt(&state->moved_mask,24) && BrdPeek(brd,7,1)==T_CLR && BrdPeek(brd,7,2)==T_CLR && BrdPeek(brd,7,3)==T_CLR) { mvs[result].x=7; mvs[result].y=2; result++; } if (state->pieces[31].player>=0 && !Bt(&state->moved_mask,31) && BrdPeek(brd,7,6)==T_CLR && BrdPeek(brd,7,5)==T_CLR) { mvs[result].x=7; mvs[result].y=6; result++; } } } break; } for (i=0;ipieces[i].player==state->cur_player) { mv_cnt=PieceMoves(state,i,mvs); for (j=0;jpieces[piece_num]; I64 j,ty=-1,score_adjust=0,x1=p->x,y1=p->y; j=PieceFind(x2,y2,state->cur_player^1); if (j>=0) { state->pieces[j].player-=2; //dead ty=state->pieces[j].type; score_adjust=piece_scores[ty]; } else if (p->type==P_PAWN && AbsI64(y1-y2)==1) { //en passant? if (!state->cur_player) j=PieceFind(x2-1,y2,1); else j=PieceFind(x2+1,y2,0); if (j>=0) { state->pieces[j].player-=2; //dead ty=state->pieces[j].type; score_adjust=piece_scores[ty]; } } if (p->type==P_PAWN && AbsI64(x1-x2)==2) { state->potential_en_passant_victim.x=x2; state->potential_en_passant_victim.y=y2; } else { state->potential_en_passant_victim.x=-1; state->potential_en_passant_victim.y=-1; } if (p->type==P_PAWN && (!x2||x2==7)) { if (!state->is_human[state->cur_player] || !final) p->type=P_QUEEN; else p->type=PopUpPiece(state->cur_player); score_adjust+=piece_scores[p->type]-piece_scores[P_PAWN]; } else if (p->type==P_KING && AbsI64(y1-y2)==2) { //castling? if (!state->cur_player) { if (y2-y1<0) state->pieces[6].y=y2+1; else state->pieces[7].y=y2-1; } else { if (y2-y1<0) state->pieces[22].y=y2+1; else state->pieces[23].y=y2-1; } } p->x=x2; p->y=y2; LBts(&state->moved_mask,piece_num); if (!state->cur_player) state->raw_score+=score_adjust; else state->raw_score-=score_adjust; state->cur_player^=1; state->mv_num++; if (final) { last_mv.x=x2; last_mv.y=y2; DocPrintF(chess_doc,"%02d)",state->mv_num); if (state->cur_player) DocPutS(chess_doc,"$$FG,LTGRAY$$"); else DocPutS(chess_doc,"$$FG,BLACK"); DocPrintF(chess_doc,"%c:%c%c-%c%c",piece_letters[p->type], y1+'A',x1+'1',y2+'A',x2+'1'); if (ty>=0) { if (state->cur_player) DocPutS(chess_doc,"$$FG$$*$$FG,BLACK$$"); else DocPutS(chess_doc,"$$FG$$*$$FG,LTGRAY$$"); DocPrintF(chess_doc,"%c",piece_letters[ty]); } DocPutS(chess_doc,"$$FG$$\n"); if (!MoveCnt(&cur_state)) { DocPutS(chess_doc,"$$FG,RED$$Game Over$$FG$$\n"); game_over=TRUE; } GameSnapShot; } return ToBool(score_adjust); } I64 MoveFind(I64 x,I64 y,Move *mvs,I64 mv_cnt) { I64 i; for (i=0;i=0 && MoveFind(x,y,mvs,mv_cnt)>=0) { MoveDo(state,piece_num,x,y,TRUE); return TRUE; } else return FALSE; } I64 ChkPieceMoves(GameState *state,I64 piece_num,Move *src,I64 mv_cnt) { //Goes through moves list for one piece, eliminating invalid moves. I64 k,cnt=mv_cnt,result=0,x,y,dy; GameState state2,*tempg; Move *dst=src; if (state->cur_player) //Find King k=16; else k=0; while (cnt--) { MemCpy(&state2,state,sizeof(GameState)); MoveDo(&state2,piece_num,src->x,src->y,FALSE); //Don't repeat board position tempg=cur_state.next; while (tempg!=&cur_state) { if (!MemCmp(tempg->pieces,state2.pieces,sizeof(PieceState)*32)) goto cm_skip; tempg=tempg->next; } if (piece_num==k) { //If king is moving, check his new location. x=state2.pieces[k].x; y=state2.pieces[k].y; dy=y-state->pieces[k].y; if (AbsI64(dy)==2 && //castling? (SqrInChk(&state2,x,y-dy) || SqrInChk(&state2,x,y-SignI64(dy)))) goto cm_skip; // This really needs to go into PieceMoves } else { x=state->pieces[k].x; y=state->pieces[k].y; } if (!SqrInChk(&state2,x,y)) { MemCpy(dst++,src,sizeof(Move)); result++; } cm_skip: src++; } return result; } I64 MoveCnt(GameState *state) { I64 i,result=0,mv_cnt; Move mvs[32]; for (i=0;i<32;i++) if (state->pieces[i].player==state->cur_player) { mv_cnt=PieceMoves(state,i,mvs); mv_cnt=ChkPieceMoves(state,i,mvs,mv_cnt); result+=mv_cnt; } return result; } U0 DrawIt(CTask *task,CDC *dc) { I64 i,x,y,z,k0,k1; PieceState *s=cur_state.pieces; brd_dc->flags|=DCF_NO_TRANSPARENTS; GrBlot(dc,cx-cx2,cy-cy2,brd_dc); task->text_attr=YELLOW<<4; dc->x=cx; dc->y=cy; dc->flags|=DCF_TRANSFORMATION; MemCpy(dc->r,w2s,sizeof(I64)*16); if (ai_thinking) { if (cur_state.cur_player) dc->color=BLACK; else dc->color=WHITE; if (Blink(,tP(task))) GrPutS(dc,-11*FONT_WIDTH/2,2*FONT_HEIGHT-cy,"Thinking..."); } dc->color=RED; for (i=0;icolor=LTRED; dc->pen_width=2; GrLineRect4(dc,(cursor_x-4)*g+2,(cursor_y-4)*g+2,(cursor_x-3)*g-1,(cursor_y-3)*g-1); DCAllocDepthBuf(dc); k0=k1=0; for (i=0;i<32;i++,s++) { if (s->player>=0) { //Alive? if (s->x!=last_mv.x || s->y!=last_mv.y || Blink(,tP(task))) { x=g/2+(s->x-4)*g; y=g/2+(s->y-4)*g; z=0; GrTransform(dc,&x,&y,&z); z=GR_Z_ALL+s->x-s->y; dc->flags&=~DCF_TRANSFORMATION; CSpritePlot3(dc,x,y,z,imgs[s->type*2+s->player]); dc->flags|=DCF_TRANSFORMATION; } } else { //Dead if (s->player==-2) { if (k1<8) { x=cx+100+k1++*g/2; y=cy-180; } else { x=cx+100+(k1++-8)*g/2; y=cy-130; } z=0; } else { if (k0<8) { x=cx+100+k0++*g/2; y=cy+220; } else { x=cx+100+(k0++-8)*g/2; y=cy+170; } z=0; } dc->flags&=~DCF_TRANSFORMATION; CSpritePlot3(dc,x,y,z,imgs[s->type*2+s->player+2]); dc->flags|=DCF_TRANSFORMATION; } } if (game_over && Blink(,tP(task))) { dc->color=LTRED; GrPutS3(dc,-9*FONT_WIDTH/2,-FONT_HEIGHT/2,0,"Game Over"); } } #define DEPTH -5 CDC *BrdNew() { I64 i,j,k,w=Fs->win_pixel_width,h=Fs->win_pixel_height; CDC *dc; g=42; cx=w/2+40; cy=h/2; w=Sqrt(2.0)*(8*g+2*FONT_WIDTH); h=8*g+2*FONT_HEIGHT; cx2=w/2; cy2=h/2; dc=DCNew(DCT_COLOR8,w,h); dc->x=cx2; dc->y=cy2; dc->flags|=DCF_TRANSFORMATION; MemCpy(dc->r,w2s,sizeof(I64)*16); dc->color=YELLOW; GrRect(dc,0,0,w,h); dc->color=BLACK; for (i=-4;i<4;i++) { GrPrintF3(dc,-4*g-4-FONT_WIDTH,i*g+g/2-4,0,"%C",i+4+'A'); GrPrintF3(dc,4*g+14,i*g+g/2-4,0,"%C",i+4+'A'); GrPrintF3(dc,i*g+g/2+6,-4*g-12-FONT_HEIGHT,0,"%C",i+4+'1'); GrPrintF3(dc,i*g+g/2-2,4*g+9,0,"%C",i+4+'1'); } dc->pen_width=1; dc->color=BLACK; for (i=-4;i<=4;i++) { GrLine3(dc,-4*g,i*g,0,4*g,i*g,0); GrLine3(dc,i*g,-4*g,0,i*g,4*g,0); GrLine3(dc,-4*g,i*g,0,-4*g,i*g,DEPTH); GrLine3(dc,i*g,4*g,0,i*g,4*g,DEPTH); } GrLine3(dc,-4*g,4*g,DEPTH,-4*g,-4*g,DEPTH); GrLine3(dc,-4*g,4*g,DEPTH,4*g,4*g,DEPTH); k=0; for (j=-4;j<4;j++) { for (i=-4;i<4;i++) { if ((i+j)&1) dc->color=WHITE; else dc->color=DKGRAY; GrFloodFill3(dc,i*g+g/2,j*g+g/2,0); } if (j&1) dc->color=DKGRAY; else dc->color=WHITE; GrFloodFill3(dc,-4*g,j*g+g/2,DEPTH/2); if (j&1) dc->color=WHITE; else dc->color=DKGRAY; GrFloodFill3(dc,j*g+g/2,4*g,DEPTH/2); } return dc; } I64 AIStateScore(GameState *state,I64 player) { if (player) return -state->raw_score; else return state->raw_score; } I64 move_depth,kill_depth; I64 AIMove2(GameState *state,I64 depth) { I64 i,possible_moves=0,best_piece,score,best_score=MIN_I64,mv_cnt,score_adjust; Move best_mv,mvs[32],*ptr; GameState state2; Bool first=TRUE; if (UnusedStk<0x1000) { //Shouldn't happen DocPutS(chess_doc,"StkOverflow\n"); return AIStateScore(state,state->cur_player); } for (i=0;i<32;i++) if (state->pieces[i].player==state->cur_player) { mv_cnt=PieceMoves(state,i,mvs); possible_moves+=mv_cnt; ptr=mvs; while (mv_cnt--) { MemCpy(&state2,state,sizeof(GameState)); state2.parent=state; if (MoveDo(&state2,i,ptr->x,ptr->y,FALSE)&&depthcur_player); if (score_adjust=AbsI64(state2.raw_score-state->raw_score)) score+=score_adjust-piece_scores[state->pieces[i].type]; } if (first || score>best_score) { best_score=score; best_piece=i; MemCpy(&best_mv,ptr,sizeof(Move)); first=FALSE; } ptr++; } } if (!first) MoveDo(state,best_piece,best_mv.x,best_mv.y,FALSE); return best_score+possible_moves<mv; Bool old_preempt=Preempt(ON); MemCpy(&state2,cj->state,sizeof(GameState)); state2.parent=cj->state; MoveDo(&state2,ptr->piece,ptr->x,ptr->y,FALSE); ptr->score=-AIMove2(&state2,1); Free(cj); Preempt(old_preempt); } I64 MoveCmp(Move *e1,Move *e2) { if (e1->scorescore) return 1; else if (e1->score==e2->score) return 0; else return -1; } U0 AIMove(GameState *state) { I64 i,cnt=0,mv_cnt,best_score; Move mvs[32],*ptr,*ptr2; ChessJob *cj; if (cnt=MoveCnt(state)) { //Collect AI possible valid moves ptr=ptr2=MAlloc(cnt*sizeof(Move)); for (i=0;i<32;i++) if (state->pieces[i].player==state->cur_player) { mv_cnt=PieceMoves(state,i,mvs); mv_cnt=ChkPieceMoves(state,i,mvs,mv_cnt); MemCpy(ptr,mvs,mv_cnt*sizeof(Move)); ptr+=mv_cnt; } //Dispatch to MP scoring all moves for (i=0,ptr=ptr2;iscore=-MAX_I32; cj=MAlloc(sizeof(ChessJob)); cj->state=state; cj->mv=ptr; if (i%mp_cnt==mp_cnt-1) AIMove1(cj); else MPJob(&AIMove1,cj,1+i%(mp_cnt-1)); } //Wait for finish for (i=0,ptr=ptr2;iscore==-MAX_I32) Yield; QSort(ptr2,cnt,sizeof(Move),&MoveCmp); //Cnt ties for first best_score=ptr2->score; mv_cnt=0; ptr=ptr2; while (mv_cntscore==best_score) { mv_cnt++; ptr++; } ptr=ptr2+RandU16%mv_cnt; MoveDo(state,ptr->piece,ptr->x,ptr->y,TRUE); Free(ptr2); } } U0 Init() { chess_doc=DocCur; DocClear; "$$FD,BLACK$$$$BD,YELLOW$$"; game_over=FALSE; ai_thinking=FALSE; move_depth=3; kill_depth=5; cur_mv_cnt=0; last_mv.x=-1; last_mv.y=-1; MemCpy(&cur_state,&setup_state,sizeof(cur_state)); QueInit(&cur_state); cur_state.is_human[0]=PopUpNoYes("$$FG,BLACK$$WHITE is human?"); cur_state.is_human[1]=PopUpNoYes("$$FG,BLACK$$BLACK is human?"); GameSnapShot; } U0 CleanUp() { QueDel(&cur_state,TRUE); } U0 SetMouseCursor() { I64 x=(cursor_x-4)*g+g/2, y=(cursor_y-4)*g+g/2, z=0; GrRot(w2s,&x,&y,&z); x+=cx+Fs->win_pixel_left+Fs->win_scroll_x; y+=cy+Fs->win_pixel_top +Fs->win_scroll_y; if (ipx!=x || ipy!=y) SetIP(x,y); } U0 SetKbdCursor(I64 x,I64 y) { I64 z; x-=cx; y-=cy; z=y; GrRot(s2w,&x,&y,&z); cursor_x=LimitI64((x+4*g)/g,0,7); cursor_y=LimitI64((y+4*g)/g,0,7); } U0 Chess() { I64 p1,p2,cur_piece; SettingsPush; //See $LK,"SettingsPush","MN:SettingsPush"$ WinMax; WinBorder; Preempt(OFF); Init; WordStat; MenuPush( "File {" " Abort(,CH_SHIFT_ESC);" " Exit(,CH_ESC);" "}" "Play {" " Move(,CH_SPACE);" " Restart(,CH_NEW_LINE);" "}"); Fs->win_inhibit=WIF_ALL-WIF_BORDER-WIF_MENU; cursor_x=cursor_y=3; w2s=GrIdent; //World-to-Screen GrRotZEqu(w2s,-ã/4); GrRotXEqu(w2s,ã/4); s2w=GrIdent; //Screen-to-World GrRotXEqu(s2w,-ã/4); GrRotZEqu(s2w,ã/4); brd_dc=BrdNew; SetMouseCursor; Fs->draw_it=&DrawIt; try { while (TRUE) { switch (ScanMsg(&p1,&p2,1<=0) { cur_mv_cnt=PieceMoves(&cur_state,cur_piece,cur_mvs); cur_mv_cnt=ChkPieceMoves(&cur_state,cur_piece,cur_mvs,cur_mv_cnt); } else cur_mv_cnt=0; } break; case MSG_IP_L_UP: SetKbdCursor(p1,p2); ch_mv_end: if (!game_over && cur_state.is_human[cur_state.cur_player]) { if (cur_piece>=0 && HumanMove(&cur_state,cur_piece,cur_mvs,cur_mv_cnt, cursor_x,cursor_y)) { Beep(250); cur_piece=-1; cur_mv_cnt=0; } else { cur_piece=-1; cur_mv_cnt=0; } } break; case MSG_KEY_UP: if (p1==CH_SPACE) goto ch_mv_end; break; case MSG_KEY_DOWN: switch (p1) { case CH_NEW_LINE: CleanUp; Init; break; case CH_ESC: case CH_SHIFT_ESC: goto ch_done; case CH_SPACE: goto ch_mv_start; case 0: switch (p2.u8[0]) { case SC_CURSOR_RIGHT: cursor_y=LimitI64(cursor_y+1,0,7); SetMouseCursor; break; case SC_CURSOR_LEFT: cursor_y=LimitI64(cursor_y-1,0,7); SetMouseCursor; break; case SC_CURSOR_DOWN: cursor_x=LimitI64(cursor_x-1,0,7); SetMouseCursor; break; case SC_CURSOR_UP: cursor_x=LimitI64(cursor_x+1,0,7); SetMouseCursor; break; } } break; } } ch_done: } catch CatchAll; DocClear; SettingsPop; MenuPop; DCDel(brd_dc); Free(s2w); Free(w2s); CleanUp; } Chess; R úÿÿÿðÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿòúÿÿÿæÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ"!úÿÿÿâÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ2"øÿÿÿâÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ òúÿÿÿæÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ 2"øÿÿÿâÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ’úÿÿÿìÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÂúÿÿÿêÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿR úÿÿÿðÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ’úÿÿÿëÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ "!øÿÿÿãÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ Òøÿÿÿêÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ