Tweath
Tweath

Reputation: 134

Filtering array by index and matching values

I'm tying to filter out a pattern for a slot machine, in this case I want the following indexes to be selected if they have the same value.

If indexes 0, 2 and 6 has the same value if should be outputted. I was thinking something like a function call maybe like this

if (win_filter([0, 2, 6] == "slot-2") {
    console.log("You won");
}

My code is the following below.

var final_score = new Array();

$(".shoot").click(function() {

  //var numbers_array = ["slot-1", "slot-1", "slot-1", "slot-1", "slot-1", "slot-2", "slot-2", "slot-2", "slot-2", "slot-3", "slot-3", "slot-3", "slot-4", "slot-4", "slot-5"];
  var numbers_array = ["slot-1", "slot-2", "slot-3", "slot-4", "slot-5"];
  var target = $("div.window table");

  target.find("tr td > div").each(function() {
    $(this).fadeOut(function() {
      $(this).removeAttr('class');
      $(this).addClass(numbers_array[Math.floor(Math.random() * numbers_array.length)]);
      $(this).fadeIn();
      final_score.push($(this).attr("class"));
    });
  });

  function filterResults(arr) {
    return final_score.filter(function(el) {
      return arr.some(function(e) {
        return el.timeframe == e;
      });
    });
  }

  var result = filterResults(['0','2','6']);
  console.log(result);

  $.each(numbers_array, function(index, value) {
    if (result == value) {
      $(".notice").html("You have won.").addClass("success").show();
      console.log("You won!");
    }
  });
  console.log(final_score);
});

Edit

If it wasn't clear I meant the indexes in the array, in case if I picked the indexes 0, 2 and 6 from this generated array the value of those would be (even if they aren't the same).

0 => "slot-2", 2 => "slot-5", 6 => "slot-1"

The goal is to check if the selected indexes has the same value output. And the amount of indexes shouldn't be hardcoded, it can be anything from 3 index searches to 5 index searches.

jsFiddle.net

Array[0]
0 : "slot-2"
1 : "slot-3"
2 : "slot-5"
3 : "slot-5"
4 : "slot-4"
5 : "slot-3"
6 : "slot-1"
7 : "slot-4"
8 : "slot-1"
9 : "slot-2"
10 : "slot-2"
11 : "slot-4"
12 : "slot-5"
13 : "slot-1"
14 : "slot-4"

Upvotes: 13

Views: 1508

Answers (5)

jonno
jonno

Reputation: 76

Fiddle: https://jsfiddle.net/q3eh0n9f/4/

var options = [
    "slot-2",
    "slot-3",
    "slot-5",
    "slot-5",
    "slot-4",
    "slot-3",
    "slot-1",
    "slot-4",
    "slot-1",
    "slot-2",
    "slot-2",
    "slot-4",
    "slot-5",
    "slot-1",
    "slot-4"
];

// convert selections to usable values and filter unique elements
function buildResults (arr) {
    return arr.map(function (index) {
        return options[index];
    }).filter(function (value, i, arr) {
        return arr.indexOf(value) === i;
    });
}

// if array has been reduced to the length of 1 it is a winner
function checkResults (results) {
    if (results.length === 1) return true;
    if (results.length !== 1) return false;
}

var result = checkResults(buildResults([0, 2, 3]));

console.log(result); // false

Upvotes: 0

Sergei Klykov
Sergei Klykov

Reputation: 1037

You asked for a comparison function, here it is:

function compareMultiple(sourceArray, indexesArray, compareToValue){ 

    for (let i = 0; i < indexesArray.length; i++){ 

        let index = indexesArray[i]

        if (!sourceArray[index] || sourceArray[index] !== compareToValue) {
            return false
        }
    } 

    return true
}

It accept three arguments: array of values, array of indexes to pick items and value to match the condition. Function returns a true / false. You can call it this way:

let isWin = compareMultiple(
    ['slot-1','slot-2','slot-1','slot-3','slot-4', 'slot-2', 'slot-1'], 
    [0, 2, 6], 
    'slot-1'
)

console.log(isWin); // true

Here is an example (i reduced number_array to increase a chance to win and rewrite a little bit of code just for demonstration). In this example i also used promises to wait until jquery fadeOut animation will be completed and we can check if new combination of slots is win (since you put new values in a final_score only on fadeOut complete asynchronous callback but check it right after the $.each your fiddle wont work as expected).

Upvotes: 0

GantTheWanderer
GantTheWanderer

Reputation: 1292

This scheme could check for winning conditions given a non-empty arbitrary length list of valid indexes. Here is the working JSFiddle.

var win_filter = function(indexes, allValues) {
    // assumes all indexes are valid

    // gather all the values from the slot machine by index.
    var values = [];
    for (var i = 0; i < indexes.length; i++)
        values.push(allValues[indexes[i]]);

    // if every value matches the others, then all values match the first
    if (values.every(function(x) { return x == values[0]; }))
        return values[0];  // return the value that was the same

    // No match found, return null to signify that no winning condition was found.
    return null;
}

$(".shoot").on('click', function() {
    var final_score = [];
    var numbers_array = ["slot-1", "slot-2", "slot-3", "slot-4", "slot-5"];

    // ...

    // Instead of iterating through the possible winning values, if there was any match, it means they won, and winningMatch will contain that matching value. ie 'slot-1'
    var winningMatch = win_filter([0, 2, 6], final_score);
    if (winningMatch) {
        $(".notice").html("You have won.").addClass("success").show();
    }
});

Note that if any matching set of any available class name wins, then we don't have to iterate through the list of possible winning cases to determine that the game was won, because wouldn't any match win?

Upvotes: 0

Reading through your breifing and comments, get the idea that you are trying to create some slot machine, where the center row is used for the matching evaluation. Hence changed a few lines in your code to get it done. JS FIDDLE DEMO

NOTE: I have tried two approach, for a WINNER state.
1. All items of CENTER ROW should be the same.
2. All items of CENTER ROW should be laid out in the same as the PATTERN
FYI: COMMENTED LINE 21 in JS for easy testing ...

/* checks if selected items are matching the winning pattern ... */
function areItemsMatchingWinningPattern(selectedItems, winningItemsPattern) {
  return !!selectedItems && !!winningItemsPattern && (selectedItems.length == winningItemsPattern.length) && selectedItems.every(function (elm, idx) { 
    return elm === winningItemsPattern[idx]; 
  })
}

/* checks if all selected items are same ....  */
function areAllItemsMatching(source) {
  return !!source && source.length > 0 && source.every(function (elm, idx, array) { 
    return idx === 0 || array[idx - 1] == elm; 
  });
}

Upvotes: 1

zurfyx
zurfyx

Reputation: 32767

First of all, I avoided to make any major modifications to your code, so in the jsfiddle I wrote the validation exactly where you were expecting it (inside the on('click')).

What I did:

Previous to calculating anything, we need the slots data. You were already saving it inside final_score, but the function which was doing so was a callback. Is it worth it waiting for the callback? - I do not think so, because it is a simple css (fadeOut) animation.

const classVal = numbers_array[Math.floor(Math.random() * numbers_array.length)];
$(this.fadeOut(function() { // Rest of your code }
final_score.push(classVal);

Calculate the length of each row, you know that they will all be equal length and you have all of them inside an array (final_score), so a simple division by the number of lines is enough.

const lines = 3;
const lineLength = final_score.length/lines;

For each line we check whether the other line values are the same as this one. Given that your array order is not based on the display order but rather on the order you generated them, we can simply check the ones with the same index (but iterating over each line).

final_score[i] === final_score[i+lineLength] && final_score[i] === final_score[i+lineLength*2]

Resulting in:

  const lineLength = final_score.length/3;
  for(let i=0; i<lineLength; i++) {
    if (final_score[i] === final_score[i+lineLength] && final_score[i] === final_score[i+lineLength*2]) {
      console.info(`win col ${i}`);
    }
  }

If you need it, you can easily n-ify this.

  const lineLength = final_score.length/3;
  for(let i=0; i<lineLength; i++) {
    const lineOneSlot = final_score[i];
    let allEqual = true;
    for (let j=1; j<lines; j++) {
        console.info(`Comparing ${i} ${i+lineLength*j}`);
        if (lineOneSlot !== final_score[i+lineLength*j]) {
        allEqual = false;
        break;
      }
    }
    if (allEqual) {
      console.info(`win col ${i}`);
    }
  }

Since you asked for a diagonal check as well, it would look like this:

However, you have to make sure that the grid is a square to get your expected results. Otherwise, you would have to redefine what exactly to do in these cases.

final_score[i] === final_score[i+1+lineLength] && final_score[i] === final_score[i+line+lineLength*line]

https://jsfiddle.net/qjp7g0qL/3/

Upvotes: 1

Related Questions