static colour brighten(colour c, colour against) { uint r = red(c), g = green(c), b = blue(c); // "brighten" away from the background: // if we are closer to black than the contrast reference, rather darken bool darken = colour_dist(c, 0) < colour_dist(against, 0); #ifdef debug_brighten printf ("%s %06X against %06X\n", darken ? "darkening" : "brighting", c, against); #endif uint _brighter() { uint s = min(85, 255 - max(max(r, g), b)); return make_colour(r + s, g + s, b + s); } uint _darker() { int sub = 70; return make_colour(max(0, (int)r - sub), max(0, (int)g - sub), max(0, (int)b - sub)); } colour bright; uint thrsh = 22222; // contrast threshhold; // if we're closer to either fg or bg, // turn "brightening" into the other direction if (darken) { bright = _darker(); #ifdef debug_brighten printf ("darker %06X -> %06X dist %d\n", c, bright, colour_dist(c, bright)); #endif if (colour_dist(bright, c) < thrsh || colour_dist(bright, against) < thrsh) { bright = _brighter(); #ifdef debug_brighten printf (" fix %06X -> %06X dist %d/%d\n", c, bright, colour_dist(bright, c), colour_dist(bright, against)); #endif } } else { bright = _brighter(); #ifdef debug_brighten printf ("lightr %06X -> %06X dist %d\n", c, bright, colour_dist(c, bright)); #endif if (colour_dist(bright, c) < thrsh || colour_dist(bright, against) < thrsh) { bright = _darker(); #ifdef debug_brighten printf (" fix %06X -> %06X dist %d/%d\n", c, bright, colour_dist(bright, c), colour_dist(bright, against)); #endif } } return bright; }
static colour brighten(colour c) { uint r = red(c), g = green(c), b = blue(c); uint s = min(85, 255 - max(max(r, g), b)); return make_colour(r + s, g + s, b + s); }
// ------------------------------------------------------------------- // Determine whether the given move puts one's own king in check // ------------------------------------------------------------------- bool ChessBoard::causes_check(const chessmove& m) const { bool w_turn=is_white(square[m.from]); ChessBoard c=*this; piece_type promotion=m.promotion; if (c.square[m.from]==w_Pawn && c.square[m.to]==Empty && m.to!=m.from+Rank) { c.square[m.to]=w_Pawn; // White captures en-passant c.square[m.from]=c.square[m.to-Rank]=Empty; } else if (c.square[m.from]==b_Pawn && c.square[m.to]==Empty && m.to!=m.from-Rank) { c.square[m.to]=b_Pawn; // Black captures en-passant c.square[m.from]=c.square[m.to+Rank]=Empty; } else { promotion=make_colour(promotion, w_turn); // Normal move c.square[m.to]=(promotion!=Empty)?promotion:c.square[m.from]; c.square[m.from]=Empty; } // Update king position if (c.square[m.to]==w_King) c.w_king_pos=m.to; else if (c.square[m.to]==b_King) c.b_king_pos=m.to; return w_turn? c.is_attacked(!w_turn, c.w_king_pos): c.is_attacked(!w_turn, c.b_king_pos); }
inline Colour make_rgb(int r, int g, int b, int a=255) { return make_colour( static_cast<float>(r) / 255.0f, static_cast<float>(g) / 255.0f, static_cast<float>(b) / 255.0f, static_cast<float>(a) / 255.0f); }
void terminal_initialize() { terminal_row = 0; terminal_column = 0; terminal_colour = make_colour(C_L_GRAY, C_BLACK); terminal_buffer = (uint16_t*) 0xB8000; for (size_t y = 0; y < VGA_HEIGHT; y++) { for (size_t x = 0; x < VGA_WIDTH; x++) { const size_t index = y * VGA_WIDTH + x; terminal_buffer[index] = make_vgaentry(' ', terminal_colour); } } }
int parse_option(char *option) { char *eq= strchr(option, '='); if (!eq) return -1; uint name_len = eq - option; char name[name_len + 1]; memcpy(name, option, name_len); name[name_len] = 0; int i = find_option(name); if (i < 0) return i; char *val = eq + 1; uint offset = options[i].offset; switch (options[i].type) { when OPT_BOOL: atoffset(bool, &cfg, offset) = atoi(val); when OPT_INT: atoffset(int, &cfg, offset) = atoi(val); when OPT_STRING: { char *str = &atoffset(char, &cfg, offset); uint size = options[i].size; strncpy(str, val, size - 1); str[size - 1] = 0; } when OPT_COLOUR: { uint r, g, b; if (sscanf(val, "%u,%u,%u", &r, &g, &b) == 3) atoffset(colour, &cfg, offset) = make_colour(r, g, b); } } return i; }
namespace colour { const Colour WHITE = make_colour(1.0f, 1.0f, 1.0f); }
// ------------------------------------------------------------------- // Determine whether the given square is under attack by a given side // ------------------------------------------------------------------- bool ChessBoard::is_attacked(bool by_white, int to) const { int from, i; const int ahead=by_white?-1:1; // Check for pawn attacks from=to+ahead*Rank-File; if (is_on_board(from) && square[from]==make_colour(Pawn, by_white) && abs(which_file(from)-which_file(to))==1) return true; from=to+ahead*Rank+File; if (is_on_board(from) && square[from]==make_colour(Pawn, by_white) && abs(which_file(from)-which_file(to))==1) return true; // Check for bishop/queen attacks static const int b_increment[]={-Rank-File, Rank-File, -Rank+File, Rank+File}; for(i=0;i<4;i++) { for (from=to+b_increment[i]; is_on_board(from) && abs(which_file(from)-which_file(from-b_increment[i]))==1; from+=b_increment[i]) { if (square[from]==make_colour(Bishop, by_white) || square[from]==make_colour(Queen, by_white)) return true; if (square[from]!=Empty) break; } } // Check for rook/queen attacks static const int r_increment[]={-Rank, Rank, -File, File}; for(i=0;i<4;i++) { for (from=to+r_increment[i]; is_on_board(from) && abs(which_file(from)-which_file(from-r_increment[i]))<=1; from+=r_increment[i]) { if (square[from]==make_colour(Rook, by_white) || square[from]==make_colour(Queen, by_white)) return true; if (square[from]!=Empty) break; } } // Check for knight attacks static const int n_source[] = {-2*Rank-File, -2*Rank+File, -2*File-Rank, -2*File+Rank, 2*Rank-File, 2*Rank+File, 2*File-Rank, 2*File+Rank}; for (i=0;i<8;i++) { from=to+n_source[i]; if (is_on_board(from) && square[from]==make_colour(Knight, by_white) && abs(which_file(from)-which_file(to))<3) return true; } // Check for king attacks static const int k_source[] = {-Rank-File, -Rank, -Rank+File, -File, File, Rank-File, Rank, Rank+File}; for (i=0;i<8;i++) { from=to+k_source[i]; if (is_on_board(from) && square[from]==make_colour(King, by_white) && abs(which_file(from)-which_file(to))<=1) return true; } // Check for en passant attacks if (to-ahead*Rank==en_passant && (square[to-File]==make_colour(Pawn, by_white) || square[to+File]==make_colour(Pawn, by_white))) return true; return false; }
// ------------------------------------------------------------------- // Piece movement: // - this function must be passed a *VALID* move (e.g. one that has // been verified by can_move()) // - promotion piece will be automatically cast to correct colour // ------------------------------------------------------------------- game_status ChessBoard::do_move(int from, int to, piece_type promotion) { // Disable castling if rook is captured or moved for (int *sq=&to;sq;sq=sq==&to?&from:(int *)NULL) switch (*sq) { case a1: w_castle_q=false; break; case a8: b_castle_q=false; break; case h1: w_castle_k=false; break; case h8: b_castle_k=false; } // Reset castled flags b_castled=w_castled=false; // Mark en-passant square, if any if (square[from]==w_Pawn && to==from+2*Rank) en_passant=from+Rank; else if (square[from]==b_Pawn && to==from-2*Rank) en_passant=from-Rank; else en_passant=No_square; // Perform actual rearrangement of board pieces bool increment_fifty=true; if (w_castle_k && from==e1 && to==g1) { square[g1]=w_King; // White castles kingside square[f1]=w_Rook; square[e1]=square[h1]=Empty; w_castled=true; } else if (w_castle_q && from==e1 && to==c1) { square[c1]=w_King; // White castles queenside square[d1]=w_Rook; square[e1]=square[a1]=Empty; w_castled=true; } else if (b_castle_k && from==e8 && to==g8) { square[g8]=b_King; // Black castles kingside square[f8]=b_Rook; square[e8]=square[h8]=Empty; b_castled=true; } else if (b_castle_q && from==e8 && to==c8) { square[c8]=b_King; // Black castles queenside square[d8]=b_Rook; square[e8]=square[a8]=Empty; b_castled=true; } else if (square[from]==w_Pawn && square[to]==Empty && to!=from+Rank) { square[to]=w_Pawn; // White captures en-passant square[from]=square[to-Rank]=Empty; increment_fifty=false; } else if (square[from]==b_Pawn && square[to]==Empty && to!=from-Rank) { square[to]=b_Pawn; // Black captures en-passant square[from]=square[to+Rank]=Empty; increment_fifty=false; } else { // Normal move if (square[to]!=Empty || is_pawn(square[from])) increment_fifty=false; promotion=make_colour(promotion, w_turn); square[to]=(promotion!=Empty)?promotion:square[from]; square[from]=Empty; } // Disable castling if king was moved if (square[e1]!=w_King) w_castle_q=w_castle_k=false; if (square[e8]!=b_King) b_castle_q=b_castle_k=false; // Update king position if (square[to]==w_King) w_king_pos=to; else if (square[to]==b_King) b_king_pos=to; // Adjust 50-move rule counter fifty=increment_fifty?fifty+1:0; // Set check flag if (w_turn) { w_check=is_attacked(!w_turn, w_king_pos); b_check=is_attacked(w_turn, b_king_pos); } else { b_check=is_attacked(!w_turn, b_king_pos); w_check=is_attacked(w_turn, w_king_pos); } // Change active player w_turn=!w_turn; // Check for checkmate/stalemate move_list moves; for (int i=a1;i<=h8;i++) { if (is_colour(square[i], w_turn)) { switch (make_neutral(square[i])) { case King: moves=mobility_king(i); break; case Pawn: moves=mobility_pawn(i); break; case Knight: moves=mobility_knight(i); break; case Bishop: moves=mobility_bishop(i); break; case Rook: moves=mobility_rook(i); break; case Queen: moves=mobility_queen(i); break; } if (!moves.empty()) break; } } // Update log of board configurations boardlog.append(*this); // Set game status if (triple_occurrence()) { status=TripleOccurrence; in_progress=false; } else if (moves.empty() && is_in_check(w_turn)) { status=Checkmate; in_progress=false; } else if (moves.empty()) { status=Stalemate; in_progress=false; } else if (fifty>=99) { status=FiftyMoves; in_progress=false; } else if (is_in_check(w_turn)) status=Check; else status=Normal; return status; }
void draw_string_full(framebuffer_t fb, vector_font_t *font, char *string, xy_t p, xy_t off, double scale, col_t colour, double intensity, double line_thick, const int mode, int32_t len, double glyph_limit, double line_limit, const int bidi, const int recur, text_param_t *tp) { uint32_t i, is, c, co; double w=0., base_off=0.; xy_t off_ls=XY0; int drawline=0; unicode_data_t ucd; int c_bidi, len_sec, con_prev=0, use_textedit=0, curpos, bidi_change=0; col_t colm; xy_t expected_pos=XY0; static double closest_deltapos[3]; if (recur==0) // if it's the top recursion of the function for this string for (i=0; i<3; i++) closest_deltapos[i] = FLT_MAX; if (font==NULL) return ; if (scale < line_limit) return ; if (scale < glyph_limit) drawline = 1; if (recur==0) intensity *= intensity_scaling(scale, 1.); if (((mode&3)!=ALIG_LEFT && bidi!=-2) || ((mode&3)!=ALIG_RIGHT && bidi==-2)) { //w = calc_strwidth_len(font, string, scale, mode, len); w = calc_strwidth_firstline(font, string, scale, mode, len, NULL); if ((mode&3)==ALIG_CENTRE) if (bidi==-2) base_off += w*0.5; else base_off -= w*0.5; if ((mode&3)==ALIG_LEFT && bidi==-2) base_off += w; if ((mode&3)==ALIG_RIGHT && bidi!=-2) base_off -= w; } if (bidi==1) { if (w==0.) w = calc_strwidth_firstline(font, string, scale, mode, len, NULL); base_off -= w; } off.x += base_off; colm = colour; if (drawline==0) colm = colour_mul(colm, intensity); if (len < 0) len = strlen(string); if (cur_textedit) if (cur_textedit->string) if (string >= cur_textedit->string && string <= &cur_textedit->string[strlen(cur_textedit->string)]) // if the string belongs to text being edited { use_textedit = 1; curpos = &cur_textedit->string[cur_textedit->curpos] - string; if (curpos==0 && cur_textedit->click_on==0 && recur==0 && len==0) // draw cursor if the string is empty draw_textedit_cursor(fb, add_xy(p, off), scale, bidi, bidi_change, line_thick); if (cur_textedit->click_on) { expected_pos = add_xy( mul_xy(xy(0.5*LETTERSPACING * (bidi == -2 ? -1. : 1.), 3.), set_xy(scale)) , sub_xy(cur_textedit->click, p) ); expected_pos.y = MAXN(0., expected_pos.y); if (recur==0) cur_textedit->curpos = strlen(cur_textedit->string); } } for (i=0; i<len; i++) { is = i; // save i at start (it might get incremented right below) co = utf8_to_unicode32(&string[i], &i); // get (original) codepoint and increment i c = get_arabic_form(co, &string[i+1], len-(i+1), con_prev); // substitute for Arabic form if needed ucd = get_unicode_data(c); if (ucd.bidicat!=bidicat_NSM) // if character that is not a combining mark con_prev = unicode_arabic_can_connect(co, 1); // if the current character connects with the next (in Arabic) if (c > sc_start && c < sc_end) // custom colour-setting Unicode characters { switch (c) { case sc_white: colour = make_colour(1., 1., 1., 1.); break; case sc_black: colour = make_colour(0., 0., 0., 1.); break; case sc_red: colour = make_colour(1., 0., 0., 1.); break; case sc_green: colour = make_colour(0., 0.5, 0., 1.); break; case sc_blue: colour = make_colour(0., 0., 1., 1.); break; case sc_baby_azure: colour = make_colour(0.1, 0.3, 1., 1.); break; case sc_amber: colour = make_colour(1., 0.55, 0., 1.); break; case sc_azure: colour = make_colour(0., 0.45, 1., 1.); break; case sc_grey: colour = make_colour(0.184, 0.184, 0.184, 1.); break; default: colour = make_colour(0.184, 0.184, 0.184, 1.); } colm = colour_mul(colour, intensity); } else // regular Unicode characters { // draw the line for the last word it represents if (drawline && recur==0) if (c==' ' || c=='\t' || c=='\n') // if c is whitespace char if (equal_xy(off, off_ls)==0) draw_line_thin(fb, add_xy(add_xy(p, off_ls), xy(0., -2.5*scale)), add_xy(add_xy(p, off), xy(-LETTERSPACING*scale, -2.5*scale) ), line_thick, colour, cur_blend, intensity*3.); c_bidi = bidicat_direction(ucd.bidicat); bidi_change = (bidi!=-2 && c_bidi==-2) || (bidi==-2 && c_bidi>0); if (use_textedit) cursor_processing(fb, font, string, c, p, off, scale, expected_pos, is, curpos, recur, mode, bidi, bidi_change, line_thick, closest_deltapos); if (bidi_change) { len_sec = find_len_bidi_section(&string[is], len-is, c_bidi); draw_string_full(fb, font, &string[is], p, off, scale, colour, intensity, line_thick, mode, len_sec, glyph_limit, line_limit, c_bidi, recur+1, tp); off.x += (calc_strwidth_len(font, &string[is], scale, mode, len_sec) + LETTERSPACING * scale) * (bidi == -2 ? -1. : 1.); is += len_sec; i = is-1; } else switch (c) { case '\n': off.x = base_off; off.y += LINEVSPACING * scale; break; default: if (drawline==0) i += draw_vector_char_lookahead(fb, font, c, &string[i+1], p, &off, scale, colm, line_thick, mode, bidi); off.x += letter_width(font, off.x, c, scale, mode) * (bidi == -2 ? -1. : 1.); } if (use_textedit && i+1==len) // if we're reaching the end of the string cursor_processing(fb, font, string, 0, p, off, scale, expected_pos, i+1, curpos, recur, mode, bidi, bidi_change, line_thick, closest_deltapos); if (drawline) if (c==' ' || c=='\t' || c=='\n') // if c is whitespace char off_ls = off; // fix position in RTL } } if (drawline && recur==0) if (equal_xy(off, off_ls)==0) draw_line_thin(fb, add_xy(add_xy(p, off_ls), xy(0., -2.5*scale)), add_xy(add_xy(p, off), xy(-LETTERSPACING*scale, -2.5*scale) ), line_thick, colour, cur_blend, intensity*3.); }
void cursor_processing(framebuffer_t fb, vector_font_t *font, char *string, uint32_t c, xy_t p, xy_t off, double scale, xy_t expected_pos, int is, int curpos, int recur, const int mode, int bidi, int bidi_change, double line_thick, double *closest_deltapos) { static int32_t sel0=0, sel1=0, newline=0; static xy_t p0, p1; rect_t box; int isa = is + string - cur_textedit->string; double wc1; if (is0_col(text_sel_col)) text_sel_col = make_colour(0.0033, 0.028, 0.1, 1.); if (recur==0 && is==0) // if it's the first run of this function for this string in this loop { sel0 = cur_textedit->sel0; sel1 = cur_textedit->sel1; minmax_i32(&sel0, &sel1); newline = 0; } if (recur > 0 && is==0) newline = 1; if (newline) { newline = 0; p0 = add_xy(p, off); } if (sel0 < sel1) // if there's a selection to display { if (sel0==isa) p0 = add_xy(p, off); if (sel1==isa || (c=='\n' && isa > sel0)) { p1 = add_xy(p, off); box.p0 = add_xy(p0, xy(-LETTERSPACING*0.5*scale * (bidi == -2 ? -1. : 1.), 2.*scale)); box.p1 = add_xy(p1, xy(-LETTERSPACING*0.5*scale * (bidi == -2 ? -1. : 1.), -8.*scale)); // draw_rect_full(fb, box, line_thick, text_sel_col, 1.); if (c=='\n') newline = 1; if (sel1==isa) sel0 = sel1 = 0; } } if (isa >= sel0 && isa <= sel1 && sel0 < sel1 && bidi_change==0) // display selection one character at a time { wc1 = glyph_width(font, off.x, c, scale, mode); box.p0 = add_xy(add_xy(p, off), xy(-LETTERSPACING*0.5*scale * (bidi == -2 ? -1. : 1.), 2.*scale)); box.p1 = add_xy(box.p0, xy(wc1 * (bidi == -2 ? -1. : 1.), -10.*scale)); draw_rect_full(fb, box, line_thick, text_sel_col, cur_blend, 1.); } if (cur_textedit->click_on==0 && is==curpos) // if the cursor is on the current character { if (cur_textedit->read_only==0) draw_textedit_cursor(fb, add_xy(p, off), scale, bidi, bidi_change, line_thick); cur_textedit->cur_screen_pos = div_xy(off, set_xy(scale)); } if (cur_textedit->click_on) check_closest_cursor(off, scale, expected_pos, &closest_deltapos[0], isa, &cur_textedit->curpos); // find the position in the line above and below expected_pos = add_xy( mul_xy(cur_textedit->cur_screen_pos_prev, set_xy(scale)) , xy(0., LINEVSPACING * -scale) ); expected_pos = add_xy( mul_xy(xy(0.5*LETTERSPACING * (bidi == -2 ? -1. : 1.), 3.), set_xy(scale)) , expected_pos ); //expected_pos.y = MAXN(0., expected_pos.y); check_closest_cursor(off, scale, expected_pos, &closest_deltapos[1], isa, &cur_textedit->curpos_up); expected_pos = add_xy( mul_xy(cur_textedit->cur_screen_pos_prev, set_xy(scale)) , xy(0., LINEVSPACING * scale) ); expected_pos = add_xy( mul_xy(xy(0.5*LETTERSPACING * (bidi == -2 ? -1. : 1.), 3.), set_xy(scale)) , expected_pos ); check_closest_cursor(off, scale, expected_pos, &closest_deltapos[2], isa, &cur_textedit->curpos_down); }