I want my shape not to go out of the window area. for example when I press the left button the shape moves out of the window area but I want it to hit the side and stay there.
def update
if button_down?(Gosu::KbRight)
if #shape_x != (WIDTH - SHAPE_DIM)
#shape_x += 3
end
end
if button_down?(Gosu::KbLeft)
if #shape_x != (WIDTH - SHAPE_DIM)
#shape_x -= 3
end
end
if button_down?(Gosu::KbUp)
#shape_y -= 3
end
if button_down?(Gosu::KbDown)
#shape_y += 3
end
end
Assuming WIDTH is Window width, you must use < and >, instead of !=
def update
if button_down?(Gosu::KbRight)
if #shape_x < (WIDTH - SHAPE_DIM)
#shape_x += 3
end
end
if button_down?(Gosu::KbLeft)
if #shape_x > (WIDTH - SHAPE_DIM)
#shape_x -= 3
end
end
if button_down?(Gosu::KbUp)
#shape_y -= 3
end
if button_down?(Gosu::KbDown)
#shape_y += 3
end
end
Related
I'm trying to make a sort visualiser using Ruby and Gosu. When the user left clicks it will sort the numbers out using a insertion sort. When the user right clicks it will sort the numbers out using a bubble sort. So far the only the insertion sort works but the bubble sort crashes after sorting out the first number. Does anyone know why? Thanks.
require 'gosu'
module ZOrder
BACKGROUND, MIDDLE, TOP = *0..2
end
SCREEN_WIDTH = 600 # needs to be COUNT * COLUMN_WIDTH
SCREEN_HEIGHT = 200 # Should be multiple of 100
MAX_VALUE = 100 # the range of the data 1 to 100
COUNT = 30 # Number of items
COL_WIDTH = 20 # suggested at least 10
class Column
# have a pointer to the neighbouring cells
attr_accessor :height, :value
def initialize(value)
#value = value
#height = (SCREEN_HEIGHT/MAX_VALUE) * value
end
end
class GameWindow < Gosu::Window
def initialize
super SCREEN_WIDTH, SCREEN_HEIGHT, false
self.caption = "Sort Visualiser"
#path = nil
#do_insert = false
#do_bubble = false
#columns = Array.new(COUNT)
column_index = 0
while (column_index < COUNT)
col = Column.new(rand(MAX_VALUE + 1))
#columns[column_index] = col
column_index += 1
end
#text_font = Gosu::Font.new(10)
end
def needs_cursor?
true
end
def insertion_sort(loop)
j = loop
done = false
while ((j > 0) and (!done))
if (#columns[j].value < #columns[j - 1].value)
temp = #columns[j - 1]
#columns[j - 1] = #columns[j]
#columns[j] = temp
else
done = true
end
j = j - 1
end
end
def bubble_sort(loop2)
j = loop2
i = loop2 + 1
done = false
while ((j > 0) and (!done))
if (#columns[j].value > #columns[i].value)
temp = #columns[j]
#columns[j] = #columns[i]
#columns[i] = temp
else
done = true
end
j = j - 1
end
end
def button_down(id)
case id
when Gosu::MsLeft
#do_insert = true
#loop = 0
#do_bubble = false
when Gosu::MsRight
#do_bubble = true
#loop2 = 0
#do_insert = false
end
end
def update
if (#do_insert)
puts "Doing insert #{#loop}"
if #loop < (COUNT)
insertion_sort(#loop)
#loop += 1
sleep(0.5)
else
#do_insert = false
end
end
if (#do_bubble)
puts "Doing bubble #{#loop2}"
if #loop2 < (COUNT)
bubble_sort(#loop2)
#loop2 += 1
sleep(0.5)
else
#do_bubble = false
end
end
end
def draw
column_index = 0
while (column_index < #columns.length)
color = Gosu::Color::GREEN
Gosu.draw_rect((column_index * COL_WIDTH), SCREEN_HEIGHT - #columns[column_index].height, COL_WIDTH, #columns[column_index].height, color, ZOrder::MIDDLE, mode=:default)
#text_font.draw("#{#columns[column_index].value}", (column_index * COL_WIDTH) + 5, SCREEN_HEIGHT - 10, ZOrder::TOP, 1.0, 1.0, Gosu::Color::RED)
column_index += 1
end
end
end
window = GameWindow.new
window.show
EDIT: Added in the rest of the code and removed some tags
I am currently print lines 0-3 in Ruby Curses. I also created an array with animal names.
My program currently outputs
dog + 0cat + 0bird + 0rat + 0
dog + 1cat + 1bird + 1rat + 1
dog + 2cat + 2bird + 2rat + 2
dog + 3cat + 3bird + 3rat + 3
I want it to output something like
dog + 0
cat + 1
bird + 2
rat + 3
Is there a way to list each element of the array on a different line and be able to select each individual line?
Here is the function I am working on
def draw_menu(menu, active_index=nil)
4.times do |i|
menu.setpos(i + 1, 1)
menu.attrset(i == active_index ? A_STANDOUT : A_NORMAL)
arr = []
arr << "dog"
arr << "cat"
arr << "bird"
arr << "rat"
arr.each do |item|
menu.addstr "#{item} + #{i}"
end
end
end
I have tried using arr.each and arr.each_index but it gives me the same output.
Here is the complete program.
UPDATE
The below makes the menu look how I want but when pressing 'w' or 's' to scroll through the menu, it selects all 4 elements at the same time. Is there a way to make it where only 1 element can be selected at a time?
require "curses"
include Curses
init_screen
start_color
noecho
def draw_menu(menu, active_index=nil)
4.times do |i|
menu.setpos(1, 1)
menu.attrset(i == active_index ? A_STANDOUT : A_NORMAL)
arr = []
arr << "dog"
arr << "cat"
arr << "bird"
arr << "rat"
arr.each_with_index do |element, index|
menu.addstr "#{element} + #{index}\n"
end
end
end
def draw_info(menu, text)
menu.setpos(1, 10)
menu.attrset(A_NORMAL)
menu.addstr text
end
position = 0
menu = Window.new(7,40,7,2)
menu.box('|', '-')
draw_menu(menu, position)
while ch = menu.getch
case ch
when 'w'
draw_info menu, 'move up'
position -= 1
when 's'
draw_info menu, 'move down'
position += 1
when 'x'
exit
end
position = 3 if position < 0
position = 0 if position > 3
draw_menu(menu, position)
end
Not sure what that 4.times was trying to do, but I think it was setting the same text 4 times into the same position on the screen. For each of the 4, if the current set of 4 items was the same as active_index, you'd set all 4 of them to the same style (A_STANDOUT instead of A_NORMAL).
What seems to be working for me and what I assume was intended is something like:
def draw_menu(menu, active_index=nil)
%w(dog cat bird rat).each_with_index do |element, index|
menu.setpos(index + 1, 1)
menu.attrset(index == active_index ? A_STANDOUT : A_NORMAL)
menu.addstr("%-4s + #{index}" % element)
end
menu.setpos(5, 1) # set the cursor on the line after the menu items
end
and then in your draw_info I couldn't see where the text was being output, but if I changed it to setpos(5, 1) it became visible on the line after the menu:
def draw_info(menu, text)
menu.setpos(5, 1)
menu.attrset(A_NORMAL)
menu.addstr text
end
Simple question for the following set of codes:
def nearby_az(string)
idx1 = 0
while idx1 < string.length
if string[idx1] != "a"
idx1 += 1
next #<--------------
end
idx2 = idx1 + 1
while (idx2 < string.length) && (idx2 <= idx1 + 3)
if string[idx2] == "z"
return true
end
idx2 += 1
end
idx1 += 1
end
return false
end
What does the word "next" do in the line with the commented arrow? And is "next" a method? If not, what's the correct technical jargon for this? Cheers
next is not a method, it's a keyword. It applies to the outer while loop in your example, it stops current iteration and 'calls' next one.
I am triggering endless recursion when trying to make a method that pulls up tiles when they are a zero. I have been testing by entering the following in irb:
class Board
attr_accessor :size, :board
def initialize(size = gets.chomp.to_i)
#size = size
#board = (1..#size).map { |x| ["L"] * #size }
end
def print_board
#board.map { |row| puts row.join }
end
end
class Mine
attr_accessor :proxi, :row, :col
def initialize(proxi)
#proxi = proxi
#row = 0
#col = 0
#random = Random.new
check_position
end
def check_position
if #proxi.board[#row - 1][#col - 1] != "L"
#row = #random.rand(1..#proxi.board.length)
#col = #random.rand(1..#proxi.board[0].length)
check_position
else
map_position
end
end
def map_position
#proxi.board[#row - 1][#col - 1] = "*"
end
end
b = Board.new(20)
m = (1..b.size * 2).map { |i| i = Mine.new(b) }
class Detector
attr_accessor :board, :proxi, :row, :col, :value
def initialize(board, proxi)
#board = board
#proxi = proxi
#row = 0
#col = 0
#value = 0
end
def mine?
if #proxi.board[#row - 1][#col - 1] == "*"
true
else
false
end
end
def detect
(#row - 1..#row + 1).each do |r|
(#col - 1..#col + 1).each do |c|
unless (r - 1 < 0 || r - 1 > #proxi.size - 1) || (c - 1 < 0 || c - 1 > #proxi.size - 1)
#value += 1 if #proxi.board[r - 1][c - 1] == "*"
end
end
end
end
def map_position
#proxi.board[#row - 1][#col - 1] = #value
#board.board[#row - 1][#col - 1] = #value
end
def recursion
if #proxi.board[#row - 1][#col - 1] == 0
(#row - 1..#row + 1).each do |r|
(#col - 1..#col + 1).each do |c|
unless (r - 1 < 0 || r - 1 > #proxi.size - 1) || (c - 1 < 0 || c - 1 > #proxi.size - 1)
#row, #col = r, c
detect
map_position
recursion
end
end
end
end
end
def reset
#row, #col, #value = 0, 0, 0
end
end
d = Detector.new(b, b)
b.print_board
If the output has plenty of free space in the upper right corner proceed to pasting the next part, else repaste.
d.row = 1
d.col = 1
d.mine?
d.detect
d.map_position
d.recursion
b.print_board
It will error out with a stack level too deep error at the recursion method. I know this is because it is having issues ending the recursive pattern. I thought my two unless statements deterring it from searching off the board would limit it to the area in the board. Plus the mines would force it to be limited in zeros it can expose. Maybe it is somehow writing spaces off the board or overwriting things on the board?
You don’t need a recursion here. Simply check each position for mines around:
Please always use 0-based arrays to eliminate lots of #blah - 1.
In detect you need to return immediately if there is a mine and set the #value otherwise:
def detect
return if #proxi.board[#row][#col] == '*'
value = 0 # no need to be global anymore
(#row - 1..#row + 1).each do |r|
(#col - 1..#col + 1).each do |c|
unless r < 0 || r >= #proxi.size || c < 0 || c >= #proxi.size
value += 1 if #proxi.board[r][c] == "*"
end
end
end
#proxi.board[#row][#col] = value
end
Now you don’t need map_position method at all. Simply check all the cells:
def check
(0..#proxi.size - 1).each do |r|
(0..#proxi.size - 1).each do |c|
#row, #col = r, c
detect
end
end
end
Hope it helps.
Exceeding the stack size is usually an indication that your recursion does not have the correct terminating condition. In your case, what mechanism is in place to prevent recursion from being called multiple times with the same #row #col pair? Note that of the 9 pairs that (#row - 1..#row + 1) (#col - 1..#col + 1) produce, one of those pairs is #row #col itself. The function will call itself infinitely many times!
A simple way to solve this would be to have something like a revealed array that keeps track of visited cells. Then recursion would mark each cell it visits as visited and return immediately if it is called on an already visited cell.
Additionally, your use of instance variables is extremely fragile here. Recursion relies on the fact that each function call has its own scope, but every call of recursion shares the same instance variables - which you're using to pass arguments! You should be using method arguments to keep the scopes distinct.
I am implementing Game of Life in Ruby and here is what I have so far:
class Cell
attr_accessor :world, :x, :y
def initialize(world=World.new, x=0, y=0)
#world = world
#world.cells << self
#x = x
#y = y
end
def neighbours
#neighbours = []
world.cells.each do |cell|
# Detects neighbour to the north
if self.x == cell.x && self.y == cell.y - 1
#neighbours << cell
end
# Detects neighbour to the north-east
if self.x == cell.x - 1 && self.y == cell.y - 1
#neighbours << cell
end
# Detects neighbour to the east
if self.x == cell.x - 1 && self.y == cell.y
#neighbours << cell
end
# Detects neighbour to the south-east
if self.x == cell.x - 1 && self.y == cell.y + 1
#neighbours << cell
end
# Detects neighbour to the south
if self.x == cell.x && self.y == cell.y + 1
#neighbours << cell
end
# Detects neighbour to the south-west
if self.x == cell.x + 1 && self.y == cell.y + 1
#neighbours << cell
end
# Detects neighbour to the west
if self.x == cell.x + 1 && self.y == cell.y
#neighbours << cell
end
# Detects neighbour to the north-west
if self.x == cell.x + 1 && self.y == cell.y - 1
#neighbours << cell
end
end
#neighbours
end
def alive?
self.world.cells.include?(self)
end
def dead?
!self.world.cells.include?(self)
end
def die!
self.world.cells.delete(self)
end
def revive!
self.world.cells << self
end
end
class World
attr_accessor :cells
def initialize
#cells = []
end
def tick!
self.cells.each do |cell|
# Rule 1
if cell.neighbours.count < 2
cell.die!
end
end
end
end
I have been coding in Rails for a while but I am confused as to how to do the following things:
validate and make sure only one Cell object can exist on one field in the World?
How to save things to DB (postgresql for example) ? And do I have to in this case or can I just leave it as it and run it in memory?
How to make the graphical output of my Game of life so it looks something like this?
Reason for my confusion is because Rails does this right out of the box and now I just need the help of understanding how Ruby alone does this.
EDIT:
I've updated the Cell class with validation method, but I can only run it after the object is being initialized. Is there a way to run it while initializing? Here's the code:
5 def initialize(world=World.new, x=0, y=0) | 53 neighbour_cell = Cell.new(subject.world, -1, 0)
6 #world = world | 54 subject.neighbours.count.should == 1
7 #world.cells << self # if self.valid? < this after if doesn't work | 55 end
8 #x = x | 56
9 #y = y | 57 it 'Detects cell to the north-west' do
10 end | 58 neighbour_cell = Cell.new(subject.world, -1, 1)
11 | 59 subject.neighbours.count.should == 1
12 def valid? | 60 end
13 #valid = true | 61
14 self.world.cells.each do |cell| | 62 it 'Creates a live cell' do
15 if self.x == cell.x && self.y == cell.y | 63 cell.should be_alive
16 #valid = false | 64 end
17 self.world.cells.delete(self) | 65
18 end | 66 it 'Kills a cell' do
19 end | 67 cell.die!
20 #valid | 68 cell.should be_dead
21 end
It's good that you're breaking out of Rails and trying something different, especially a classic challenge like the Game of Life.
As for your questions, they all depend on the system design that you choose. But for a simple implementation here's a few pointers.
How about using the Set class? This is an array of objects that allows no duplicates.
You only need a DB if you want to maintain the state between separate runs of the application. If you don't need that, just keep it all in memory.
This is too big a question to answer here, but you have many options. The extremes are:
managing screen updates pixel rendering yourself, printing characters to the terminal as the cells change
using something like rubygame, which has a concept of sprites, GUIs and drawing
You are asking some big, general questions here, and each of them have many answers. I'll give my initial take on each:
1: Validation - It seems like (coming from rails) you want to have some kind of method like valid? that you can call on your objects. In pure ruby, though, you have to define explicitly what a "valid" object really is. You also have to decide where your validation should take place, i.e. which object is doing the validation and which object is being validated.
From the code presented above, I'd suggest that you need at least one more class, call it Game for example, which controls the world and all of the cells in it. Currently, you've loaded a lot of logic into the Cell class, and you might want to review the single responsibility principle to see if this is a valid (ha ha) design choice.
2. Persistence - There's nothing stopping you from using ActiveRecord in pure ruby as your ORM. You could check out this SO question for an example implementation: how-to-use-active-record-without-rails.
3. Graphics - There are a number of game libraries for ruby which have built-in graphics APIs for whichever platform you are on. I've not worked with them much personally, but gosu seems like a good option.
I have done it! But not with the approach taken here. Here is my code below, the only thing left to do is implement some graphic output. Also, here is the whole code on Github, check it out and comment and help me improve it and stuff. Thank you both for helping me :)
I could refactor this 'live_neighbours_around_cell(cell)' method, but don't know how. Can you help with that? Also, it would be useful to add 'Cell.new' immediately to 'cells' array and not like I do now where I have separate function for that.
class Game
attr_accessor :world
def initialize(world=World.new, seeds=[[1, 1]])
#world = world
seeds.each do |seed|
world.cell_board[seed[0]][seed[1]].alive = true
end
end
def tick!
next_round_live_cells = []
next_round_dead_cells = []
world.cells.each do |cell|
# Rule 1:
# Any live cell with fewer than two live neighbours dies
if world.live_neighbours_around_cell(cell).count < 2
next_round_dead_cells << cell
end
# Rule 2:
# Any live cell with two or three live neighbours lives on to the next generation
if cell.alive? && world.live_neighbours_around_cell(cell).count == (2 || 3)
next_round_live_cells << cell
end
# Rule 3:
# Any live cell with more than three live neighbours dies
if cell.alive? && world.live_neighbours_around_cell(cell).count > 3
next_round_dead_cells << cell
end
# Rule 4:
# Any dead cell with exactly three live neighbours becomes a live cell
if cell.dead? && world.live_neighbours_around_cell(cell).count == 3
next_round_live_cells << cell
end
end
next_round_live_cells.each do |cell|
cell.revive!
end
next_round_dead_cells.each do |cell|
cell.die!
end
end
end
class World
attr_accessor :rows, :cols, :cell_board, :cells
# Scheme of default initialized world matrix
#------------------------
# 0 1 2
# 0 [ dead, dead, dead ]
# 1 [ dead, alive, dead ]
# 2 [ dead, dead, dead ]
#-----------------------
def initialize(rows=3, cols=3)
#rows = rows
#cols = cols
#cells = []
#cell_board = Array.new(rows) do |row|
Array.new(cols) do |col|
Cell.new(row, col)
end
end
cell_board.each do |row|
row.each do |element|
if element.is_a?(Cell)
cells << element
end
end
end
end
def live_cells
cells.select { |cell| cell.alive }
end
def live_neighbours_around_cell(cell)
live_neighbours = []
live_cells.each do |live_cell|
# Neighbour to the North
if live_cell.x == cell.x - 1 && live_cell.y == cell.y
live_neighbours << live_cell
end
# Neighbour to the North-East
if live_cell.x == cell.x - 1 && live_cell.y == cell.y + 1
live_neighbours << live_cell
end
# Neighbour to the East
if live_cell.x == cell.x && live_cell.y == cell.y + 1
live_neighbours << live_cell
end
# Neighbour to the South-East
if live_cell.x == cell.x + 1 && live_cell.y == cell.y + 1
live_neighbours << live_cell
end
# Neighbour to the South
if live_cell.x == cell.x + 1 && live_cell.y == cell.y
live_neighbours << live_cell
end
# Neighbour to the South-West
if live_cell.x == cell.x + 1 && live_cell.y == cell.y - 1
live_neighbours << live_cell
end
# Neighbour to the West
if live_cell.x == cell.x && live_cell.y == cell.y - 1
live_neighbours << live_cell
end
# Neighbour to the North-West
if live_cell.x == cell.x - 1 && live_cell.y == cell.y - 1
live_neighbours << live_cell
end
end
live_neighbours
end
end
class Cell
attr_accessor :x, :y, :alive
def initialize(x=0, y=0)
#x = x
#y = y
#alive = false
end
def alive?
alive
end
def dead?
!alive
end
def die!
#alive = false
end
def revive!
#alive = true # same as > self.alive = true
end
end