A Few Minutes Of Code
A Few Minutes Of Code

    Create a Cricket Points Table in JavaScript - Part 4

    August 15, 2019

    Video Blogger

    image from undraw.co

    Overview

    Click on the following links to read part1, part2 or part3 of the series.

    In this tutorial we are going to complete the rest of the calculations required for the points table, including creating a function to calculate overs and Net Run Rate.

    Calculate a cricket team stat.

    We are going to start off here by creating a function that will count a stat for a team, it will have the below arguments.

    • matches - Our matches array
    • teamNum - Whether to filter the home team or away team
    • team - The Team eg IND (in this post we will focus on one team but in future posts we will loop over all teams)
    • stat - This function will be able to be used for runs, overs and played status (fin = 1 means the match has finished)
    • opp - where we can toggle to show the current team or their opponent so we can calculate runs against etc.
    • filterTeam - if this is true we will look for the stat only else we will look for a combination of the stat and the team number to get the correct data.
    const cricketTeamStat = ({
      matches,
      teamNum = "t1",
      team,
      stat,
      opp,
      filterTeam = false
    })

    Here we are creating some constants to determine which team to check for to help us to determine whether we want for example runs scored for or runs scored against.

      const oppTeam = getOppTeam(teamNum);
      const showTeam = opp === true ? oppTeam : teamNum;
      const statName = filterTeam
        ? `${stat}`
        : `${showTeam}${stat}`;

    We will then filter out matches so we are only getting completed matches for the current team and we will use reduce to count the total.

      const statTotal = matches
        .filter(
          match =>
            match[teamNum] === team &&
            match["type"] === 1 &&
            match["fin"] === 1
        )
        .reduce((total, match) => {
          const value =
            stat === "Ov"
              ? calcOver(match[statName])
              : match[statName];
          return total + value;
        }, 0);
      return statTotal;
    Full Snippet on github.

    Tests

    To help illustrate what we are trying to achieve here see the below test where we run the function twice for India once as t1 and once as t2 and we can see that they have scored 2260 during the group stage of the tournament.

    it("cricketTeamStat total Runs", () => {
      expect(
        cricketTeamStat({
          matches,
          teamNum: "t1",
          team: "IND",
          stat: "Ru",
          opp: SHOW_TEAM,
          filterTeam: false
        }) +
          cricketTeamStat({
            matches,
            teamNum: "t2",
            team: "IND",
            stat: "Ru",
            opp: SHOW_TEAM,
            filterTeam: false
          })
      ).toBe(2260);
    });

    Calculate an over.

    You may have noticed in the above code a reference to calcOver. This is required because the date returns overs in the format of overs.balls so we need to do a calculation to convert this so that we will be able to convert our net run rate properly.

    const splitOver = over => (over + "").split(".");
    const makeFloat = str => parseFloat(str) || 0;
    
    export const calcOver = overStr => {
      /*
        calc nrr overs here
        (1): 0.167 (2): 0.333 (3): 0.500 (4): 0.667 (5): 0.833
      */
      const over = Number(splitOver(overStr)[0]);
      const balls = Number(splitOver(overStr)[1]);
      const ballsCalculated =
        balls > 0 ? (balls / 6).toFixed(3) : balls;
      return over + makeFloat(ballsCalculated);
    };

    Tests

      expect(calcOver("1")).toBe(1);
      expect(calcOver("1.0")).toBe(1);
      expect(calcOver("1.1")).toBe(1.167);
      expect(calcOver("1.2")).toBe(1.333);
      expect(calcOver("1.3")).toBe(1.5);
      expect(calcOver("1.4")).toBe(1.667);
      expect(calcOver("1.5")).toBe(1.833);

    Accumulate Team Stats Total

    The below function simply combines matches where a team is team1 and teams2 to get there total for the competition.

    const cricketTeamTotal = ({
      matches,
      team,
      stat,
      opp,
      filterTeam
    }) => {
      return (
        cricketTeamStat({
          matches,
          teamNum: TEAM1,
          team,
          stat,
          opp,
          filterTeam
        }) +
        cricketTeamStat({
          matches,
          teamNum: TEAM2,
          team,
          stat,
          opp,
          filterTeam
        })
      );

    Calculating Net Run Rate

    To calculate net run rate we use the Net Run Rate formulate which is runs for / overs for - runs against / overs against.

    export const calcNRR = ({
      runsFor,
      oversFor,
      runsAgainst,
      oversAgainst
    }) => {
      const forTotal = runsFor / oversFor;
      const againstTotal = runsAgainst / oversAgainst;
      return (forTotal - againstTotal).toFixed(3);
    };

    Tests

    it("calcNRR for IND", () => {
      expect(
        calcNRR({
          runsFor: 2260,
          oversFor: 381.0,
          runsAgainst: 1998,
          oversAgainst: 390.0
        })
      ).toBe("0.809");
    });

    Create our data for the points table.

    We now have created functions to handle all the required aspects of the points table. Below we will make a function to store these in an object for each team.

    const cricketPointsTableStats = ({
      matches,
      team,
      config
    }) => {
      const runsFor = cricketTeamTotal({
        matches,
        team,
        stat: "Ru",
        opp: SHOW_TEAM
      });
      const oversFor = cricketTeamTotal({
        matches,
        team,
        stat: "Ov",
        opp: SHOW_TEAM
      });
      const runsAgainst = cricketTeamTotal({
        matches,
        team,
        stat: "Ru",
        opp: SHOW_OPP
      });
      const oversAgainst = cricketTeamTotal({
        matches,
        team,
        stat: "Ov",
        opp: SHOW_OPP
      });
      return {
        team: team,
        played: cricketTeamTotal({
          matches,
          team,
          stat: "fin",
          opp: SHOW_TEAM,
          filterTeam: true
        }),
        won: cricketTeamTotalCalc({
          config,
          matches,
          team,
          stat: WON,
          SHOW_TEAM
        }),
        lost: cricketTeamTotalCalc({
          config,
          matches,
          team,
          stat: LOST
        }),
        noresult: cricketTeamTotal({
          matches,
          team,
          stat: "NR",
          opp: SHOW_TEAM
        }),
        runsFor: runsFor,
        oversFor: oversFor,
        runsAgainst: runsAgainst,
        oversAgainst: oversAgainst,
        netrr: calcNRR({
          runsFor,
          oversFor,
          runsAgainst,
          oversAgainst
        }),
        pts: cricketTeamTotalCalc({
          config,
          matches,
          team,
          stat: POINTS
        })
      };
    };

    Tests

    The below example shows how our results will look in the object for each team.

    const config = { pts4Win: 2, pts4NR: 1 };
    const expectedData = {
      lost: 1,
      netrr: "0.809",
      noresult: 1,
      oversAgainst: 390,
      oversFor: 381,
      played: 9,
      pts: 15,
      runsAgainst: 1998,
      runsFor: 2260,
      team: "IND",
      won: 7
    };
    
    it("cricketPointsTableStats IND", () => {
      expect(
        cricketPointsTableStats({
          matches,
          team: "IND",
          config
        })
      ).toMatchObject(expectedData);

    We now have all the data required to render out our points table. In part 5 of the series we will take the data for each team and render it in our react application.

    To follow the code so far head over to codesandbox.

    Edit new

    Categories:
    Previous Create a Cricket Points Table in JavaScript - Part 5Next Create a Cricket Points Table in JavaScript - Part 3