-1

So I am creating a minesweeper game in ruby, for fun. I have completed most of it however my detector object is having issues handling the edges of the board. The board object consists of a size int and a 3d array consisting of row..col. My detector object must ignore out of range indexes which I have set an unless conditional to deal with. The issue is then when it checks around for mines so it can total the number it will count stuff on the top or bottom array. If its on the bottom of the board it will count from the top etc. etc. Also some mines to the right boarder seem to not detect anything. The mines in the middle arrays of the board seem to work fine. I have been trying a lot of different configurations and am at a loss for ideas. Here is the board and detector objects:

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 Detector
  attr_accessor :proxi, :row, :col, :value

  def initialize(proxi)
    @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
    unless (@row < 0 || @row > @proxi.size - 1) || (@col < 0 || @col > @proxi.size - 1)
      @value += 1 if @proxi.board[@row - 2][@col - 1] == "*"
      @value += 1 if @proxi.board[@row - 2][@col - 2] == "*"
      @value += 1 if @proxi.board[@row - 1][@col - 2] == "*"
      @value += 1 if @proxi.board[@row][@col - 2] == "*"
      @value += 1 if @proxi.board[@row][@col - 1] == "*"
      @value += 1 if @proxi.board[@row][@col] == "*"
      @value += 1 if @proxi.board[@row - 1][@col] == "*"
      @value += 1 if @proxi.board[@row - 2][@col] == "*"
    end
  end

  def map_position
    @proxi.board[@row - 1][@col - 1] = @value
    @row = 0
    @col = 0
    @value = 0
  end
end

I have been keeping testing to small boards for sake of time. I am noticing the bottom panel is giving out 0 when it should be saying 5. The 6's in the top are reflecting the mines around them as well as to the bottom of the board. So something with how I am managing my 3d arrays. On larger boards I notice the middle objects detect fine, its when they are on the edges they either detect the other sides or they are duds and false 0.

Here is the output from a game with debug:

Minefield size:
3
Lets play minesweeper!
LL*
***
*L*
LLL
LLL
LLL
pick a row:
1
pick a col:
1
flag position? (y/n)
n
6L*
***
*L*
6LL
LLL
LLL
pick a row:
1
pick a col:
2
flag position? (y/n)
n
66*
***
*L*
66L
LLL
LLL
pick a row:
1
pick a col:
3
flag position? (y/n)
y
66*
***
*L*
66!
LLL
LLL
pick a row:
2
pick a col:
1
flag position? (y/n)
y
66*
***
*L*
66!
!LL
LLL
pick a row:
2
pick a col:
2
flag position? (y/n)
y
66*
***
*L*
66!
!!L
LLL
pick a row:
2
pick a col:
3
flag position? (y/n)
y
66*
***
*L*
66!
!!!
LLL
pick a row:
3
pick a col:
1
flag position? (y/n)
y
66*
***
*L*
66!
!!!
!LL
pick a row:
3
pick a col:
2
flag position? (y/n)
n
66*
***
*0*
66!
!!!
!0L
pick a row:
3
pick a col:
3
flag position? (y/n)
y
66*
***
*0*
you win
continue? (y/n)

Thank you for any advice and help!

1 Answers1

0

Why don't you think about making your board class a little smarter.

I would suggest first creating a function to test if any location is valid. Eg:

  def valid?(row,col)
    !(row < 1 || row > @size - 1) || (col < 1 || col > @size - 1)
  end

I would also suggest adding a function to get or set any cell. Eg:

def get (row,col)
   @board[row -1][col-1] if valid?(row,col)
end

def set (row,col,val)
   @board[row -1][col -1] = val if valid?(row,col)
end

Then you don't have to worry anymore about where things go.

You can add an iterator function which lets you look at all the cells 'around' a point. Notice how it just blindly loops through a range of cells and lets the valid? function worry about the edges..

Eg:

 def around(row,col)
   (row-1 .. row+1).each do |r|
     (col-1 .. col+1).each do |c|
       if valid?(r,c)
         yield r,c
       end
     end
   end
 end

Then if you want to implement something like 'detect' you only have to worry about what to do with each cell, e.g.:

def detect(row,col)
  around(row,col) do |r,c|
    puts "boom at #{r},#{c}" if get(r,c) == '*'
  end
end

You could change this logic to add up scores or whatever you need to do.

John C
  • 4,276
  • 2
  • 17
  • 28