stuartambient
stuartambient

Reputation: 134

How to get my method to return it's resulting values to a 3rd method

I'm not sure if the topic title is specific enough but here goes. I have two methods - one that iterates through some arrays along with conditionals in the block to push the correct data out.

Here is that code

def iterate_lines
  WIN_COMBINATIONS.each_with_index do |line,index|
    lines = @board[line[0]] + @board[line[1]] + @board[line[2]]
      if lines.include?("X") && !lines.include?("O")
        scores = tally_scores(lines.count("X"),"X",index)
          elsif lines.include?("O") && !lines.include?("X")
        scores = tally_scores(lines.count("O"),"O",index)
          elsif lines.include?("X") && lines.include?("O")
        scores = tally_scores(0,"",index)
          elsif !lines.include?("X") && !lines.include?("O")
        scores = tally_scores(0,"",index)
      end
      p scores
  end
end

The other method is the one calculating those scores according to my chosen heuristics.

def tally_scores(score,player,index)
  score =    1 if score == 1 && player == "X"
  score =   -1 if score == 1 && player == "O"
  score =   10 if score == 2 && player == "X"
  score =  -10 if score == 2 && player == "O"
  score =  100 if score == 3 && player == "X"
  score = -100 if score == 3 && player == "O"  
  score
end

Calling 'iterate_lines I can print the correct values out from either 'tally_scores', or as I have shown here, by setting the variables 'scores' to the calls in 'iterate_lines', which allows me to just print them out from 'iterate_lines'.

Naturally the return values from 'iterate_lines' is the array (WIN_COMBINATIONS). Hard-coding a return scores obviously would give me just the last value.

My problem is I have a 3rd method that needs to get what comes out of 'tally_scores' yet I can't pass it over as a regular argument, aka my_method(scores). The reason being is that the 3rd method has it's own list of arguments it gets passed for other reasons. Plus it would be nil until the method was called.

def get_scores
  # other code
  #: something like this:
  score = iterate_lines 
  # or
  score = tally_scores
  # or
  # ?
end

So I feel like maybe I backed myself into a corner and should trash what I have and restart. I will say I tried taking 'tally_scores' and putting the scores into a instance variable array. I found though when I passed it, all but the last value remained.

Upvotes: 0

Views: 47

Answers (1)

max pleaner
max pleaner

Reputation: 26788

There are a couple issues here. First of all, as you've seen when you use each_with_index nothing that happens in that block has an effect outside, unless you use side effects. If you a set a variable in that block it will be reset each iteration.

You can change it to map.with_index so that the result is an array of the results produced by the iterations.

Also it seems like scores should be score here and in lines similar to it, since tally_scores returns a single score:

scores = tally_scores(lines.count("X"),"X",index)

If you're using map.with_index, then the return value of the block should be score, that way the result will be an array of scores. However you can't use return score from the block, which will return from the parent method and not the single iteration of the block. You can use next score instead or simply score as the last line.

After making these changes, you can say scores = iterate_lines.

It would look something like this:

def iterate_lines
  WIN_COMBINATIONS.map.with_index do |line, index|
    # set score according to your conditional logic
    score # or alternatively, "next score"
  end
end

It's better to extract the printing logic to elsewhere, for example:

scores = iterate_lines
scores.each { |score| p score }

Upvotes: 1

Related Questions