The program below is a substantial simplification of one that worked but in spite of hours of effort I can't identify why the following bug occurs:
Everything works as expected except that when the line "if behavior[2,0] > t then goright(brain,stimulus) end" is executed, the line "stimulus.each {|n| stimulus[n,0]=0 }" does NOT reset all of the elements of the stimulus vector to 0 as it does otherwise. Instead the "1" placed there by the previous trip through the "for c in (0..$Choices)" remains thereby generating double behaviors (both a left and right turn) when only one is expected. I've commented out everything that I believe is irrelevant yet it still happens.
class Matrix
def []=(i, j, x)
#rows[i][j] = x
end
end #code to allow putting individual elements in matrix at i,j
brain= Matrix[ [90,0,0,0,0,0,0,0,0,0,0],
[0,90,0,10,10,10,10,0,0,0,0],
[0,0,90,10,10,10,10,0,0,0,0] ]
longmem=Matrix[ [90,0,0,0,0,0,0,0,0,0,0],
[0,90,0,10,10,10,10,0,0,0,0],
[0,0,90,10,10,10,10,0,0,0,0] ]
stimulus=Matrix.column_vector([0,0,0,0,0,0,0,0,0,0,0])
behavior=Matrix.column_vector([0,0,0])
t=89 # t=threshold
# decay_rate=2
$Stimmax=10
$Behavmax=2
$Choices=2
# begin defining behavioral methods
def learn(ix, brain, stimulus)
psp=20
for j in (8..$Stimmax)
if brain[ix,j] > 0 then brain[ix,j]+= 20 end #modified hunting for bug
end # for j
end # learn
#def positive_fixer(brain,stimulus,longmem,energy)
# reinf=0.9
# for i in (0..$Behavmax)
# for j in (7..$Stimmax)
# if longmem[i,j]>0 then longmem[i,j]+=(reinf*(brain[i,j]-longmem[i,j])).round end
# end
# end
# learn(0, brain, stimulus)
#end #positive fixer comment out in bug hunt
def goleft(brain,stimulus)
puts " Left Turn"
learn(1,brain,stimulus)
end # def left
def goright(brain,stimulus)
puts " Right Turn"
learn(2,brain,stimulus)
end # def right
# end defining behavioral methods
# begin MAIN PROGRAM
for c in (0..$Choices)
stimulus.each {|n| stimulus[n,0]=0 }
# SET ALL STIMS TO O
puts "Should by all 0s"
stimulus.to_a.each {|r| puts r.inspect} # aid in bug hunt
stimulus[rand(1..2),0]= 1
#add print stimulus vector for debugging
puts "Should by just a single 1"
stimulus.to_a.each {|r| puts r.inspect} # aid in bug hunt
# memory decay
#for i in (0..$Behavmax)
#for j in (7..$Stimmax)
# if brain[i,j]>longmem[i,j] then brain[i,j]+=-(brain[i,j]-longmem[i,j])/decay_rate end
# if brain[i,j]<longmem[i,j] then brain[i,j]+=-1*((brain[i,j]+longmem[i,j])/decay_rate) end
#end #for j
#end #for i
# memory decay commented out in search for bug
behavior=brain*stimulus
if behavior[0,0] > t then positive_fixer(brain, stimulus, longmem, energy) end
if behavior[1,0] > t then goleft(brain,stimulus) end
if behavior[2,0] > t then goright(brain,stimulus) end
end #for c
puts
brain.to_a.each {|r| puts r.inspect}
# end main program```
the line "stimulus.each {|n| stimulus[n,0]=0 }" does NOT reset all of the elements of the stimulus vector to 0 as it does otherwise
One of the way how to reset vector:
require 'matrix'
vector = Matrix.column_vector([1, 2, 3])
# => Matrix[[1], [2], [3]]
vector.each_with_index { |_, i| vector[i, 0] = 0 }
# => Matrix[[0], [0], [0]]
So you need to use each_with_index instead of each
I can play the game. Switch the player all working fine but not getting result who won the game.
def initialize_board
#count = 9
#player = PLAYER_ONE #current_player
#board = Array.new(3){ Array.new(3, " ") }
end
def play
inputs = get_inputs
return false if !inputs
update_board(inputs)
print_board
end
def switch_player
if(#player == PLAYER_ONE)
#player = PLAYER_TWO
else
#player = PLAYER_ONE
end
end
def game_over?
# #count = #count - 1
# #count <= 0
if check_winner
puts "#{#player} won "
end
end
def check_winner
WIN_COMBINATIONS.find do |indices|
binding.pry
values = #board.values_at(*indices)
values.all?('X') || values.all?('O')
end
end
Here I am getting indices [0,1,2] in all cases while debugging.
The main reason why you're not getting the winner is because your 'values = #board.values_at(*indices)' statement returns an array of arrays. And values.all?('X') || values.all?('O') checks not an 'X' or 'O' pattern but an array object. So you need to flatten an array first.
values.flatten!
Stefan already answered similar question , but his board was one-dimensional because of %w expression, you can read about it here
I'm trying to program the AI for a Mastermind game in ruby using Donal Knuth's 5 guess algorithm. The game consists of a codemaker, who uses 8 different colored pegs to create a set of 4, and a codebreaker, who guesses at the code and receives feedback (a red square for a peg which is both the right color and in the right spot, and a white square for a peg which is the right color but in the wrong spot).
I've created a set for all possible codes. My goal is to compare feedback from the guess to feedback from all codes in the set, then delete the ones that don't match. It seems to delete the entire set though.
class ComputerPlayer < Player
def initialize(game)
super(game)
#all_possible_codes = create_codes
#turn = 1
end
def get_code
Array.new(4){rand(1..6)}
end
def get_guess
puts #all_possible_codes.length
if #turn == 0
#turn += 1
cull_set([1, 1, 2, 2])
#all_possible_codes.delete("1122")
return [1, 1, 2, 2]
else
random_sample = #all_possible_codes.to_a.sample.split('').map{|str| str.to_i}
#all_possible_codes.delete(random_sample.join(''))
cull_set(random_sample)
random_sample
end
end
def cull_set(guess)
feedback = #game.feedback_on_guess(guess)
puts feedback
#all_possible_codes.delete_if { |str| #game.feedback_on_guess(str.split.map{|num| num.to_i}) != feedback }
end
def create_codes
set = Set.new
(1..8).each do |i|
(1..8).each do |j|
(1..8).each do |k|
(1..8).each do |l|
set << [i, j, k, l].join('')
end
end
end
end
set
end
end
#this is the feedback_on_guess method used by the above class
def feedback_on_guess(code_guess)
code_duplicate = #code
feedback = []
code_duplicate.map.with_index do |entry, i|
if entry == code_guess[i]
feedback.push('r')
code_guess[i] = -1
-2
else
entry
end
end.each do |entry|
found_index = code_guess.find_index(entry)
if found_index
feedback.push('g')
code_guess[found_index] = -1
end
end
puts feedback
feedback
end
Try
copy = something.dup
because after just
copy = something
copy and something are pointing to the same object. You can confirm this by checking the object_id of the object referenced by the variable. If it is the same, then it is the same object.
When you dup an object, you will cretae a copy. Depending on what you want to dup you might need to implement/override the logic to create a copy. For built in Classes like String, Hash and so on it will work out of the box.
Be aware that nested constructs (eq. Hash containing other Hashes) are not duplicated.
h1 = {"a" => {"b" => 2}}
h2 = h1.dup
puts h1.object_id # 70199597610060
puts h2.object_id # 70199597627020
puts h1["a"].object_id # 70199597610080
puts h2["a"].object_id # 70199597610080
I'm not worried about what happens if my key will go past Z right now, or capital letters. All I want is my outcome to be something like. text=abc key=2 and it print "cde". Where am I going wrong?
puts "What would you like to cipher?"
text = gets.chomp
puts " what number key would you like?"
key = gets.chomp.to_i
def casear_cipher(text,key)
ciphered_text = []
text.chars.each do |letter|
ciphered_text = letter
ciphered_text = ciphered_text.next
end
end
puts casear_cipher(text,key)
You're not using the key yet, so it will always just do abc -> bcd. If you're really not concerned about "Z" going to "AA", you can try this:
def cipher(text, key)
text.chars.map { |c| (c.ord + key).chr }.join
end
Since 'Z'.next => 'AA' and 'z'.next #=> 'aa', we can use [-1] to select the last letter.
In the code below we perform next! on each character n times using the times method. next! modifies the character whereas next does not.
def casear_cipher(text, n)
text.chars.map do |c| n.times { c.next! }
c[-1]
end.join
end
p casear_cipher('abc',2) #=> "cde"
p casear_cipher('xyz',2) #=> "zab"
p casear_cipher('ZEBRA',2) #=> "BGDTC"
More information about these methods can be found at http://www.ruby-doc.org/core-2.4.1/
I need a chunk of Ruby code to combine an array of contents like such:
[{:dim_location=>[{:dim_city=>:dim_state}]},
:dim_marital_status,
{:dim_location=>[:dim_zip, :dim_business]}]
into:
[{:dim_location => [:dim_business, {:dim_city=>:dim_state}, :dim_zip]},
:dim_marital_status]
It needs to support an arbitrary level of depth, though the depth will rarely be beyond 8 levels deep.
Revised after comment:
source = [{:dim_location=>[{:dim_city=>:dim_state}]}, :dim_marital_status, {:dim_location=>[:dim_zip, :dim_business]}]
expected = [{:dim_location => [:dim_business, {:dim_city=>:dim_state}, :dim_zip]}, :dim_marital_status]
source2 = [{:dim_location=>{:dim_city=>:dim_state}}, {:dim_location=>:dim_city}]
def merge_dim_locations(array)
return array unless array.is_a?(Array)
values = array.dup
dim_locations = values.select {|x| x.is_a?(Hash) && x.has_key?(:dim_location)}
old_index = values.index(dim_locations[0]) unless dim_locations.empty?
merged = dim_locations.inject({}) do |memo, obj|
values.delete(obj)
x = merge_dim_locations(obj[:dim_location])
if x.is_a?(Array)
memo[:dim_location] = (memo[:dim_location] || []) + x
else
memo[:dim_location] ||= []
memo[:dim_location] << x
end
memo
end
unless merged.empty?
values.insert(old_index, merged)
end
values
end
puts "source1:"
puts source.inspect
puts "result1:"
puts merge_dim_locations(source).inspect
puts "expected1:"
puts expected.inspect
puts "\nsource2:"
puts source2.inspect
puts "result2:"
puts merge_dim_locations(source2).inspect
I don't think there's enough detail in your question to give you a complete answer, but this might get you started:
class Hash
def recursive_merge!(other)
other.keys.each do |k|
if self[k].is_a?(Array) && other[k].is_a?(Array)
self[k] += other[k]
elsif self[k].is_a?(Hash) && other[k].is_a?(Hash)
self[k].recursive_merge!(other[k])
else
self[k] = other[k]
end
end
self
end
end