Implement the Game Logic | Modern Ludo

Think of the game, we know that we have 4 teams in play. At a given time, all we need to see is where these 16 planes are. For the game engine, all it needs to know is the coordinates of these 16 planes. So we need to create another map which has a different value for each and every position a plane might be placed. So here it is:

function createValueMap() {
    var mapxy = new Array();
    mapxy.push([00, 00, 00, 00, 01, 02, 03, 04, 05, 06, 07, -4, 00, 00, 00]);
    mapxy.push([00, 00, 00, 00, 52, 00, 00, 60, 00, 00, 08, 00, 00, 00, 00]);
    mapxy.push([00, 00, 00, 00, 51, 00, 00, 61, 00, 00, 09, 00, 00, 00, 00]);
    mapxy.push([-5, 00, 00, 00, 50, 00, 00, 62, 00, 00, 10, 00, 00, 00, 00]);
    mapxy.push([46, 47, 48, 49, 00, 00, 00, 63, 00, 00, 00, 11, 12, 13, 14]);
    mapxy.push([45, 00, 00, 00, 00, 00, 00, 64, 00, 00, 00, 00, 00, 00, 15]);
    mapxy.push([44, 00, 00, 00, 00, 00, 00, 65, 00, 00, 00, 00, 00, 00, 16]);
    mapxy.push([43, 90, 91, 92, 93, 94, 95, 99, 75, 74, 73, 72, 71, 70, 17]);
    mapxy.push([42, 00, 00, 00, 00, 00, 00, 85, 00, 00, 00, 00, 00, 00, 18]);
    mapxy.push([41, 00, 00, 00, 00, 00, 00, 84, 00, 00, 00, 00, 00, 00, 19]);
    mapxy.push([40, 39, 38, 37, 00, 00, 00, 83, 00, 00, 00, 23, 22, 21, 20]);
    mapxy.push([00, 00, 00, 00, 36, 00, 00, 82, 00, 00, 24, 00, 00, 00, -3]);
    mapxy.push([00, 00, 00, 00, 35, 00, 00, 81, 00, 00, 25, 00, 00, 00, 00]);
    mapxy.push([00, 00, 00, 00, 34, 00, 00, 80, 00, 00, 26, 00, 00, 00, 00]);
    mapxy.push([00, 00, 00, -2, 33, 32, 31, 30, 29, 28, 27, 00, 00, 00, 00]);
    return mapxy;
}

Initialize the routes of all planes:

var roles = ["red", "yellow", "blue", "green"];
var routs = []; var specialPos = []; 

function initiatePlaneRouts() {
    //fly over index -->17 ~ 29 **57 each~~
    var redRout = [
        46, 47, 48, 49, 50, 51, 52, 01, 02, 03, 04, 05, 06, 07, 08, 09, 10, 11,
        12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29,
        30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 90, 91, 92, 93,
        94, 95, 72];
    var yellowRout = [
        07, 08, 09, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24,
        25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42,
        43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 01, 02, 03, 04, 60, 61, 62, 63,
        64, 65, 82];
    var blueRout = [
        20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37,
        38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 01, 02, 03,
        04, 05, 06, 07, 08, 09, 10, 11, 12, 13, 14, 15, 16, 17, 70, 71, 72, 73,
        74, 75, 92];
    var greenRout = [
        33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50,
        51, 52, 01, 02, 03, 04, 05, 06, 07, 08, 09, 10, 11, 12, 13, 14, 15, 16,
        17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 80, 81, 82, 83,
        84, 85, 62];
    routs.push(redRout);
    routs.push(yellowRout);
    routs.push(blueRout);
    routs.push(greenRout);
    var redSpecial = [47, 51, 03, 07, 11, 15, 19, 23, 27, 31, 35, 39];
    var yellowSpecial = [08, 12, 16, 20, 24, 28, 32, 36, 40, 44, 48, 52];
    var blueSpecial = [21, 25, 29, 33, 37, 41, 45, 49, 01, 05, 09, 13];
    var greenSpecial = [34, 38, 42, 46, 50, 02, 06, 10, 14, 18, 22, 26];
    specialPos.push(redSpecial);
    specialPos.push(yellowSpecial);
    specialPos.push(blueSpecial);
    specialPos.push(greenSpecial);
}

Now  it’s time to create a JS object to represent the status of the game. The ‘playStatus’ basically holds all the positions of the 16 planes and other information like the name of the player, the color of the player, whether it’s allowed to take off, etc. The initial value -1 means it’s in the airport:

var playStatus = (function () {
    var s = [];
    for (var k = 0; k < roles.length; k++) {
        var role = {
            self: false,
            name: null,
            color: roles[k],
            index: k,
            allowTakeOff: false,
            continuePlaying: false,
            fly: false,
            overLimit: 0,
            touchBaseCount: 0,
            win: false,
            planes: []
        };
        for (var j = 0; j < 4; j++) {
            var plane = {
                previousValue: -1,
                value: -1,
                pos: {
                    left: -1,
                    top: -1,
                    right: -1,
                    bottom: -1
                }
            };
            role.planes.push(plane);
        }
        s.push(role);
}
    return s;
})();

When we have the positions of all planes, how to place them? Here are basically three scenarios

  • The plane is in the airport
  • The plane is in the runway preparing to take off
  • The plane has taken off

For the first two scenarios, we use one function to handle it. This is a modified version of the function placeDefaultPlanes:

function placeDefaultPlanes(color, planeindex, atTheDoor) {
    var redposes = [1.65, 0.75, 3.05, 0.75, 1.65, 2.15, 3.05, 2.15, 0.5, 3.5];
    var yellowposes = [12.75, 1.65, 14.15, 1.65, 12.75, 3.05, 14.15, 3.05, 11.5, 0.5];
    var blueposes = [11.85, 12.75, 13.25, 12.75, 11.85, 14.15, 13.25, 14.15, 14.5, 11.5];
    var greenposes = [0.75, 11.85, 2.15, 11.85, 0.75, 13.25, 2.15, 13.25, 3.5, 14.5];
    var currentpos = null;
    var i_role = null;
    switch (color) {
        case "red": currentpos = redposes; i_role = 0; break;
        case "yellow": currentpos = yellowposes; i_role = 1; break;
        case "blue": currentpos = blueposes; i_role = 2; break;
        case "green": currentpos = greenposes; i_role = 3; break;
        default: break;
    }
    var currentplane = color + "plane";
    var img = document.getElementById(currentplane);
    upctx.shadowBlur = 10;
    upctx.shadowOffsetX = 2;
    upctx.shadowOffsetY = 2;
    upctx.shadowColor = "black";
    if (planeindex != undefined) {//not initiation  
        var tempPosInd = 0;
        if (atTheDoor == true) {
            tempPosInd = 8;
        }
        else {
            tempPosInd = planeindex * 2
        }
        upctx.drawImage(img, tileWidth * currentpos[tempPosInd], tileWidth * currentpos[tempPosInd + 1], tileWidth, tileWidth);
        playStatus[i_role].planes[planeindex].pos.left = Math.floor(tileWidth * currentpos[tempPosInd]) - 1;
        playStatus[i_role].planes[planeindex].pos.top = Math.floor(tileWidth * currentpos[tempPosInd + 1]) - 1;
        playStatus[i_role].planes[planeindex].pos.right = Math.floor(tileWidth * currentpos[tempPosInd] + tileWidth) + 1;
        playStatus[i_role].planes[planeindex].pos.bottom = Math.floor(tileWidth * currentpos[tempPosInd + 1] + tileWidth) + 1;
    }
    else {
        return;
    }
}

Each time a player throws the dice, we get the dice value. When a player clicks on a plane, we add the value to that plane. Below is the function called when a plane is clicked:

function aPlaneClicked(clickedindex, selfclick) {
    var tempvar = clickedindex;
    if (selfclick) {
        var msg = JSON.stringify({ "planeclicked": tempvar });
        sendJSONMessage(msg);
    }
    else {
        notMe = true;
    }
    //////
    if (playhand.role.planes[tempvar].value == 56)//clicking on one that has touched base. do nothing
        return;
    if (diceValue == 0) {
        document.getElementById("info").innerText = "Please roll dice";
        return;
    }
    if (diceValue != 6 && playhand.role.planes[tempvar].value == -1) {//There is a plane flying, but he choose to click on one in the airport
        return;
    }
    playhand.role.planes[tempvar].previousValue = playhand.role.planes[tempvar].value;
    switch (playhand.role.planes[tempvar].value) {
        case -1: if (playhand.role.allowTakeOff) { playhand.role.allowTakeOff = false; playhand.role.planes[tempvar].value = -5 + playhand.value; } diceValue = 0; break;
        default:
            playhand.role.planes[tempvar].value += diceValue;
            if (playhand.role.planes[tempvar].value > 55) {
                playhand.role.overLimit = diceValue;
            }
            if (playhand.role.planes[tempvar].value < 57 && playhand.role.planes[tempvar].value > 0) {
                var tempRoutValue = routs[playhand.role.index][playhand.role.planes[tempvar].value - 1];
                for (var j = 0; j < specialPos[playhand.role.index].length; j++) {
                    if (specialPos[playhand.role.index][j] == tempRoutValue) {
                        switch (j) {
                            case 3: playhand.role.planes[tempvar].value += 16; playhand.role.fly = true; break;
                            case 4: playhand.role.planes[tempvar].value += 12; playhand.role.fly = true; break;
                            default: playhand.role.planes[tempvar].value += 4; playhand.role.fly = true; break;
                        }
                    }
                }
            }
            diceValue = 0; break;
    }
    updatePlayBoard();
    if (onmobile) {
        dicectx.clearRect(0, 0, tileWidth * 2, tileWidth * 2);
    }
    else
        dicectx.clearRect(0, 0, tileWidth * 4, tileWidth * 4);
}

Every time a plane value is changed, we update all planes:

function updatePlayBoard() {
    var ifChangeHands = -1;
    if (playhand.role) {
        for (var i = 0; i < playhand.role.planes.length; i++) {
            if (ifChangeHands < playhand.role.planes[i].value)
                ifChangeHands = playhand.role.planes[i].value;
            if (playhand.role.planes[i].value != playhand.role.planes[i].previousValue) {//a plane needs to be moved
                var coordinates = moveAPlane(playhand.role.planes[i], playhand.role.planes[i].previousValue, playhand.role.planes[i].value);
                playhand.role.planes[i].pos.left = Math.floor(coordinates.co_x) - 1;
                playhand.role.planes[i].pos.top = Math.floor(coordinates.co_y) - 1;
                playhand.role.planes[i].pos.right = Math.floor(coordinates.co_x + tileWidth) + 1;
                playhand.role.planes[i].pos.bottom = Math.floor(coordinates.co_y + tileWidth) + 1;
                if (playhand.role.planes[i].previousValue == playhand.role.planes[i].value) {
                    handcount++;
                    changeHands();
                }
                break;
            }
        }
    }
    if (ifChangeHands == -1 && clickOverflow != true) {
        handcount++;
        changeHands();
    }
}

When a planes is hit, it gets sent home:

function hitAPlane(ind, val) {
    for (var j = 0; j < 4; j++) {//role index
        for (var k = 0; k < 4; k++) {//plane index in each role
            if (j != ind && //Not the same color
                playStatus[j].planes[k].value != 0 &&
                routs[j][playStatus[j].planes[k].value - 1] == val) { //overlapped
                playStatus[j].planes[k].value = -1; //This plane is sent back home, there might be more than 1 plane that get hit at a time
                playStatus[j].planes[k].previousValue = -1;
            }
        }
    }
}

Source Code

https://github.com/DynamsoftRD/Modern-Ludo

git clone https://github.com/DynamsoftRD/Modern-Ludo.git