Home > database >  Another if statement to execute the goal function
Another if statement to execute the goal function

Time:02-15

I am making a matchmaking system where 2 players with the same weight will be matched. My target is when i have a nofight the player should not be matched with the entry ID. (More explanation below)

NOTE: my noFight is based on player's entryID.

const source = [
  {
    entryID: 1,
    entryName: "player1",
    weight: 1900,
    noFight: 2&3, //Will not be matched with entryID: 2 & 3
    
  },
  {
    entryID: 2,
    entryName: "player2",
    weight: 1900,
   noFight: 1&3&4, //Will not be matched with entryID: 1 & 2 & 3
  },
  {
    entryID: 3,
    entryName: "player3",
    weight: 1900,
    noFight: 1&2&4, //Will not be matched with entryID: 1 & 2 & 4
  },
    {
    entryID: 4,
    entryName: "player4",
    weight: 1900,
    noFight: 2&3&4, //Will not be matched with entryID: 2 & 3 & 4
    
  },



];

function combine(
  data = [],
  different = 0,
  maxGroupSize = 2,
  sortedStatement = (a, b) => a.weight - b.weight
) {
  const sortedData = [...data].sort(sortedStatement); // "weight" must be in ascending order

  const dataGroups = sortedData.reduce((acc, item) => {
    const findedAccItem = acc.find(
      (accItem) =>
        accItem.length < maxGroupSize && // if the array is not filled
        accItem[0].weight   different >= item.weight && // and if the minimum is in the acceptable range
        !accItem.find((obj) => obj.entryName === item.entryName /* || obj.entryID === item.nofight */) // I think i need to add more statement here. I have tried  obj.entryID === item.nofight but it is not working.
    );
    if (findedAccItem) {
      findedAccItem.push(item);
    } else {
      acc.push([item]);
    }
    return acc;
  }, []);

  const namedDataGroups = dataGroups.reduce((acc, item, index) => {
    // added an index as a prefix because the keys can match
    const key = [index, ...item.map((item) => item.weight)].join("_");
    acc[key] = item;
    return acc;
  }, {});

  return namedDataGroups;
}

// default example
console.log("Example #1: ", combine(source));

We can see the result on the snippet that entryID: 1 & entryID: 2 has been matched. Same with entryID: 3 & entryID: 4.

Now, if I achieve the goal of nofight. The result would be like this:

Example #1:  {
    "0_1900_1900": [
      {
        "entryID": 1,
        "entryName": "player1",
        "weight": 1900,
        "noFight": 2&3,
      },
      {
        "entryID": 4,
        "entryName": "player4",
        "weight": 1900,
        "noFight": 2&3&4,
      }
    ],

  }

Only entryID: 1 & entryID: 4 has been matched.

Any help will be appreciated. Thank you

CodePudding user response:

This might be an issue on my end, but I've never seen the syntax noFight: 2&3 used in this context, so my first step was changing this to arrays instead like so noFight: [2,3].

Once that's done all you need to do is check if the noFight array contains the current fighter being checked. And finally, when setting up the final data group you'll also need to check that the groups contain two fighters. Because of the way the reduce in the previous section works, you'll end up with an array that also contains single players who didn't get a match. You could probably push this logic somewhere inside the reduce but it's convoluted enough as is and this does the job.

Here's the updated code with comments on the changes.

const source = [
  {
    entryID: 1,
    entryName: "player1",
    weight: 1900,
    noFight: [2,3], // changed these to arrays
  },
  {
    entryID: 2,
    entryName: "player2",
    weight: 1900,
   noFight: [1,3,4],
  },
  {
    entryID: 3,
    entryName: "player3",
    weight: 1900,
    noFight: [1,2,4],
  },
    {
    entryID: 4,
    entryName: "player4",
    weight: 1900,
    noFight: [2,3,4],
  },
    { // added a new player that will fight anyone to test the logic
    entryID: 5,
    entryName: "player5",
    weight: 1900,
    noFight: [],
  },
];

function combine(
  data = [],
  different = 0,
  maxGroupSize = 2,
  sortedStatement = (a, b) => a.weight - b.weight
) {
  const sortedData = [...data].sort(sortedStatement);

  const dataGroups = sortedData.reduce((acc, item) => {
    const findedAccItem = acc.find(
      (accItem) =>
        accItem.length < maxGroupSize &&
        accItem[0].weight   different >= item.weight &&
        !accItem.find((obj) => obj.entryName === item.entryName || item.noFight.includes(obj.entryID)) // here we check if the fighter is in the noFight array or not
    );
    
    if (findedAccItem) {
      findedAccItem.push(item);
    } else {
      acc.push([item]);
    }
    
    return acc;
  }, []);

  const namedDataGroups = dataGroups.reduce((acc, item, index) => {
    if (item.length > 1) { // and finally we check that there are in fact two fighters in the grouping; without this you'll end up with  fighters that didn't get a match in the array as a result of how the reduce above works
      const key = [index, ...item.map((item) => item.weight)].join("_");
      acc[key] = item;
    }
    return acc;
  }, {});

  return namedDataGroups;
}

console.log("Example #1: ", combine(source));


EDIT: A quick final thought on preference. Personally, I would remove the first reduce altogether and opt for traversing the array myself. I know you would lose some performance but the current method is incredibly difficult to read. That's just my 2c of course, but it would make life so much easier if you need to make changes in the future.

  • Related