<commit_before>///////////////////////////////////////////////////////////////////////////////
//// poor-man's enums

var RED = 'r'; // always goes first
var BLACK = 'b';
var EMPTY = '.';

var WIDTH = 7;
var HEIGHT = 6;

var IN_PROGRESS = 0;
var RED_WON = 1;
var BLACK_WON = 2;
var DRAW = 3;

var ERROR_ILLEGAL_MOVE = 0;
var ERROR_NO_LEGAL_MOVES_FOUND = 1;

///////////////////////////////////////////////////////////////////////////////
//// game-agnostic primatives

Array.prototype.clone = function() {
    return this.slice(0);
};

function clone2DArray(array) {
    var a = [];
    for(var i = 0; i < array.length; ++i) {
        a.push(array[i].clone());
    }
    return a;
}

function initArray(size, value) {
    var array = [];
    for(var i = 0; i < size; ++i) {
        array.push(value);
    }
    return array;
}

function init2DArray(width, height, value) {
    var array = [];
    for(var x = 0; x < width; ++x) {
        array[x] = initArray(height, value);
    }
    return array;
}

function incKey(obj, key) {
    if(!(key in obj)) {
        obj[key] = 0;
    }
    obj[key]++;
    return obj;
}

function isEven(n) {
    return n % 2 === 0;
}

///////////////////////////////////////////////////////////////////////////////
//// Connect Four logic

function Board() {
    // (0, 0) is bottom left
    this.board = init2DArray(WIDTH, HEIGHT, EMPTY);
    this.turn = RED;
    this.status = IN_PROGRESS;
    this.moveHistory = [];
}

Board.prototype.clone = function() {
    var b = new Board();
    b.board = clone2DArray(this.board);
    b.turn = this.turn;
    b.status = this.status;
    b.moveHistory = this.moveHistory.clone();
    return b;
};

Board.prototype.toString = function() {
    var rows = [];
    rows.push("0  1  2  3  4  5  6");
    rows.push("-------------------");
    for(var y = HEIGHT - 1; y >= 0; --y) {
        var row = [];
        for(var x = 0; x < WIDTH; ++x) {
            row.push(this.board[x][y]);
        }
        rows.push(row.join("  "));
    }
    rows.push("===================");
    rows.push("Status: " + this._prettyStatus(this.status));
    return rows.join('\n');
};

Board.prototype._prettyStatus = function(status) {
    switch(status) {
        case RED_WON:
            return "red wins!";
        case BLACK_WON:
            return "black wins!";
        case DRAW:
            return "draw";
        case IN_PROGRESS:
            return "in progress...";
    }
};

// destructive operation
Board.prototype.makeMove = function(move) {
    if(!this.isLegalMove(move)) {
        throw ERROR_ILLEGAL_MOVE;
    }
    var y = HEIGHT - 1;
    while(y > 0 && this.board[move][y - 1] == EMPTY) {
        y--;
    }
    this.board[move][y] = this.turn;
    this.moveHistory.push([move, y]);
    this.status = this._calcStatus([move, y], this.turn);
    this.turn = this.turn == RED ? BLACK : RED;
    return this;
};

Board.prototype.isLegalMove = function(move) {
    return this.board[move][HEIGHT - 1] == EMPTY;
};

Board.prototype._calcStatus = function(pos, turn) {
    var winCode = turn == RED ? RED_WON : BLACK_WON;
    if(this._dirCheck(pos, turn, [0, -1]) >= 3) {
        return winCode;
    }
    if(this._dirCheck(pos, turn, [1, 0]) + this._dirCheck(pos, turn, [-1, 0]) >= 3) {
        return winCode;
    }
    if(this._dirCheck(pos, turn, [1, 1]) + this._dirCheck(pos, turn, [-1, -1]) >= 3) {
        return winCode;
    }
    if(this._dirCheck(pos, turn, [-1, 1]) + this._dirCheck(pos, turn, [1, -1]) >= 3) {
        return winCode;
    }

    if(this._isDrawn()) {
        return DRAW;
    }

    return IN_PROGRESS;
};

// Starting from a position on the board, and given a direction, return
// how many pieces of a given color are in that direction in a row.
Board.prototype._dirCheck = function(pos, turn, vec) {
    for(var factor = 1; factor <= 3; ++factor) {
        var x = pos[0] + vec[0] * factor;
        var y = pos[1] + vec[1] * factor;
        if(x < 0 || x > WIDTH - 1 || y < 0 || y > HEIGHT - 1
                || this.board[x][y] != turn) {
            return factor - 1;
        }
    }
    return 3;
};

Board.prototype._isDrawn = function() {
    return this.moveHistory.length >= WIDTH * HEIGHT;
};

///////////////////////////////////////////////////////////////////////////////
//// playing algorithms

function randomMove() {
    return Math.floor(WIDTH * Math.random());
}

function randomLegalMove(board) {
    var move = randomMove();
    var tries = 100;
    while(!board.isLegalMove(move)) {
        move = randomMove();
        tries--;
        if(tries < 0) {
            throw ERROR_NO_LEGAL_MOVES_FOUND;
        }
    }
    return move;
}

function oppositeColor(color) {
    return color == RED ? BLACK : RED;
}

function IWon(myColor, boardStatus) {
    return (myColor == RED && boardStatus == RED_WON)
        || (myColor == BLACK && boardStatus == BLACK_WON);
}

function ILost(myColor, boardStatus) {
    return (myColor == RED && boardStatus == BLACK_WON)
        || (myColor == BLACK && boardStatus == RED_WON);
}<commit_msg>increased tries<commit_after>///////////////////////////////////////////////////////////////////////////////
//// poor-man's enums

var RED = 'r'; // always goes first
var BLACK = 'b';
var EMPTY = '.';

var WIDTH = 7;
var HEIGHT = 6;

var IN_PROGRESS = 0;
var RED_WON = 1;
var BLACK_WON = 2;
var DRAW = 3;

var ERROR_ILLEGAL_MOVE = 0;
var ERROR_NO_LEGAL_MOVES_FOUND = 1;

///////////////////////////////////////////////////////////////////////////////
//// game-agnostic primatives

Array.prototype.clone = function() {
    return this.slice(0);
};

function clone2DArray(array) {
    var a = [];
    for(var i = 0; i < array.length; ++i) {
        a.push(array[i].clone());
    }
    return a;
}

function initArray(size, value) {
    var array = [];
    for(var i = 0; i < size; ++i) {
        array.push(value);
    }
    return array;
}

function init2DArray(width, height, value) {
    var array = [];
    for(var x = 0; x < width; ++x) {
        array[x] = initArray(height, value);
    }
    return array;
}

function incKey(obj, key) {
    if(!(key in obj)) {
        obj[key] = 0;
    }
    obj[key]++;
    return obj;
}

function isEven(n) {
    return n % 2 === 0;
}

///////////////////////////////////////////////////////////////////////////////
//// Connect Four logic

function Board() {
    // (0, 0) is bottom left
    this.board = init2DArray(WIDTH, HEIGHT, EMPTY);
    this.turn = RED;
    this.status = IN_PROGRESS;
    this.moveHistory = [];
}

Board.prototype.clone = function() {
    var b = new Board();
    b.board = clone2DArray(this.board);
    b.turn = this.turn;
    b.status = this.status;
    b.moveHistory = this.moveHistory.clone();
    return b;
};

Board.prototype.toString = function() {
    var rows = [];
    rows.push("0  1  2  3  4  5  6");
    rows.push("-------------------");
    for(var y = HEIGHT - 1; y >= 0; --y) {
        var row = [];
        for(var x = 0; x < WIDTH; ++x) {
            row.push(this.board[x][y]);
        }
        rows.push(row.join("  "));
    }
    rows.push("===================");
    rows.push("Status: " + this._prettyStatus(this.status));
    return rows.join('\n');
};

Board.prototype._prettyStatus = function(status) {
    switch(status) {
        case RED_WON:
            return "red wins!";
        case BLACK_WON:
            return "black wins!";
        case DRAW:
            return "draw";
        case IN_PROGRESS:
            return "in progress...";
    }
};

// destructive operation
Board.prototype.makeMove = function(move) {
    if(!this.isLegalMove(move)) {
        throw ERROR_ILLEGAL_MOVE;
    }
    var y = HEIGHT - 1;
    while(y > 0 && this.board[move][y - 1] == EMPTY) {
        y--;
    }
    this.board[move][y] = this.turn;
    this.moveHistory.push([move, y]);
    this.status = this._calcStatus([move, y], this.turn);
    this.turn = this.turn == RED ? BLACK : RED;
    return this;
};

Board.prototype.isLegalMove = function(move) {
    return this.board[move][HEIGHT - 1] == EMPTY;
};

Board.prototype._calcStatus = function(pos, turn) {
    var winCode = turn == RED ? RED_WON : BLACK_WON;
    if(this._dirCheck(pos, turn, [0, -1]) >= 3) {
        return winCode;
    }
    if(this._dirCheck(pos, turn, [1, 0]) + this._dirCheck(pos, turn, [-1, 0]) >= 3) {
        return winCode;
    }
    if(this._dirCheck(pos, turn, [1, 1]) + this._dirCheck(pos, turn, [-1, -1]) >= 3) {
        return winCode;
    }
    if(this._dirCheck(pos, turn, [-1, 1]) + this._dirCheck(pos, turn, [1, -1]) >= 3) {
        return winCode;
    }

    if(this._isDrawn()) {
        return DRAW;
    }

    return IN_PROGRESS;
};

// Starting from a position on the board, and given a direction, return
// how many pieces of a given color are in that direction in a row.
Board.prototype._dirCheck = function(pos, turn, vec) {
    for(var factor = 1; factor <= 3; ++factor) {
        var x = pos[0] + vec[0] * factor;
        var y = pos[1] + vec[1] * factor;
        if(x < 0 || x > WIDTH - 1 || y < 0 || y > HEIGHT - 1
                || this.board[x][y] != turn) {
            return factor - 1;
        }
    }
    return 3;
};

Board.prototype._isDrawn = function() {
    return this.moveHistory.length >= WIDTH * HEIGHT;
};

///////////////////////////////////////////////////////////////////////////////
//// playing algorithms

function randomMove() {
    return Math.floor(WIDTH * Math.random());
}

function randomLegalMove(board) {
    var move = randomMove();
    var tries = 200;
    while(!board.isLegalMove(move)) {
        move = randomMove();
        tries--;
        if(tries < 0) {
            throw ERROR_NO_LEGAL_MOVES_FOUND;
        }
    }
    return move;
}

function oppositeColor(color) {
    return color == RED ? BLACK : RED;
}

function IWon(myColor, boardStatus) {
    return (myColor == RED && boardStatus == RED_WON)
        || (myColor == BLACK && boardStatus == BLACK_WON);
}

function ILost(myColor, boardStatus) {
    return (myColor == RED && boardStatus == BLACK_WON)
        || (myColor == BLACK && boardStatus == RED_WON);
}
{'fraction_non_alphanumeric': 0.2210985524489391, 'fraction_numerical': 0.013682331945270671, 'mean_word_length': 1.8688850967007964, 'pattern_counts': {'":': 0, '<': 19, '<?xml version=': 0, '>': 21, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '7328408', 'n_tokens_mistral': 3494, 'n_tokens_neox': 3345, 'n_words': 827}