Class: ConnectNGame::Rack

Inherits:
Object
  • Object
show all
Defined in:
lib/connect_n_game/game/rack.rb,
lib/cli/cli_rack.rb

Overview

The class of game racks. That is a matrix of cells

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(order) ⇒ Rack

Create a rack of the appropriate order.
Parameters

  • order - The order of the game, that is the winning

number of pieces in a row.


30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
# File 'lib/connect_n_game/game/rack.rb', line 30

def initialize(order)
  unless (4..8).include?(order)
    fail "Invalid game dimension #{order} not (4 .. 8)"
  end

  @order = order
  @depth = @order + (order >> 1)
  @width = @depth + (@depth.odd? ? 2 : 1)

  @weights = [0.5]
  weight = 4

  (@width/2).times do
    @weights << 1.0/weight
    weight *= 2
    @weights.insert(0, 1.0/weight)
    weight *= 2
  end

  @channel_names = %w(A B C D E F G H I J K L M).first(width)

  @rack = Array.new(@width) { [ ] }
end

Instance Attribute Details

#channel_namesObject (readonly)

The names of the channels



21
22
23
# File 'lib/connect_n_game/game/rack.rb', line 21

def channel_names
  @channel_names
end

#depthObject (readonly)

The depth of the playable area.



12
13
14
# File 'lib/connect_n_game/game/rack.rb', line 12

def depth
  @depth
end

#orderObject (readonly)

The number in a row needed for victory.



9
10
11
# File 'lib/connect_n_game/game/rack.rb', line 9

def order
  @order
end

#rackObject (readonly)

The raw playable area.



18
19
20
# File 'lib/connect_n_game/game/rack.rb', line 18

def rack
  @rack
end

#weightsObject (readonly)

The column weight values.



24
25
26
# File 'lib/connect_n_game/game/rack.rb', line 24

def weights
  @weights
end

#widthObject (readonly)

The width of the playable area.



15
16
17
# File 'lib/connect_n_game/game/rack.rb', line 15

def width
  @width
end

Instance Method Details

#channel_full?(channel) ⇒ Boolean

Is the selected channel full?
Parameters

  • channel - The channel number 1 .. width


Returns

  • true if full else false.

Returns:

  • (Boolean)


68
69
70
# File 'lib/connect_n_game/game/rack.rb', line 68

def channel_full?(channel)
  get_channel(channel).length >= depth
end

#channel_to_row(channel) ⇒ Object

Get the free row for the specified channel.
Parameters

  • channel - The channel number 1 .. width


Returns

  • The row number or nil.



154
155
156
# File 'lib/connect_n_game/game/rack.rb', line 154

def channel_to_row(channel)
  channel_full?(channel) ? nil : rack[channel-1].length + 1
end

#cli_displayObject

Display the rack via a command line interface.



12
13
14
15
16
17
18
19
20
21
22
23
24
# File 'lib/cli/cli_rack.rb', line 12

def cli_display
  #Show the title line.
  puts " " + channel_names.join(" ")

  #Show the body
  (1..depth).reverse_each do |row|
    (1..width).each do |channel|
      print "|#{CLI_MAP[get_cell(channel,row)]}"
    end

    puts "|"
  end
end

#count_pieces(channel, row, dx, dy, piece) ⇒ Object

Count the pieces along the designated path.
Parameters

  • channel - The starting channel

  • row - The starting row

  • dx - The channel step value

  • dy - The row step value

  • piece - The piece we are looking for.


Returns

  • The score for that play 0 .. n



135
136
137
138
139
140
141
142
143
144
145
146
147
# File 'lib/connect_n_game/game/rack.rb', line 135

def count_pieces(channel, row, dx, dy, piece)
  result = 0

  while result < width
    channel, row = channel+dx, row+dy

    return result unless piece == get_cell(channel, row)

    result += 1
  end

  fail "Looping error"
end

#deep_cloneObject

Clone the internal array.



169
170
171
172
173
174
175
176
177
# File 'lib/connect_n_game/game/rack.rb', line 169

def deep_clone
  @rack = @rack.clone

  (0...@width).each do |index|
    @rack[index] = @rack[index].clone
  end

  self
end

#get_cell(channel, row) ⇒ Object

Get the specified cell.
Parameters

  • channel - The channel number 1 .. width

  • row - The row number 1 .. depth


Returns

  • The contents of the cell or nil



89
90
91
92
93
94
# File 'lib/connect_n_game/game/rack.rb', line 89

def get_cell(channel, row)
  return nil unless valid_channel?(channel)
  return nil unless valid_row?(row)

  rack[channel-1][row-1]
end

#get_channel(channel) ⇒ Object

Get the required play channel
Parameters

  • channel - The channel number 1 .. width


Returns

  • The requested channel (array) or nil for invalid channels.



59
60
61
# File 'lib/connect_n_game/game/rack.rb', line 59

def get_channel(channel)
  rack[channel-1]
end

#play_channel(channel, piece) ⇒ Object

Play a specified channel.
Parameters

  • channel - The channel number 1 .. width

  • piece - The piece to be played.


Returns

  • The score of the move or raises GameInvalidMove exception.



102
103
104
105
106
# File 'lib/connect_n_game/game/rack.rb', line 102

def play_channel(channel, piece)
  score = score_move(channel, piece)
  rack[channel-1] << piece if score > 0
  score
end

#rack_full?Boolean

Is the rack full?
Returns

  • true if full (or invalid) else false.

Returns:

  • (Boolean)


75
76
77
78
79
80
81
# File 'lib/connect_n_game/game/rack.rb', line 75

def rack_full?
  rack.each do |channel|
    return false if channel.length < depth
  end

  true
end

#score_move(channel, piece) ⇒ Object

Determine the score obtained for moving to a specified channel
Parameters

  • channel - The channel number 1 .. width

  • piece - The piece to be played.


Returns

  • The score for that play 0 .. n



114
115
116
117
118
119
120
121
122
123
124
# File 'lib/connect_n_game/game/rack.rb', line 114

def score_move(channel, piece)
  return -9 if channel_full?(channel)

  row = channel_to_row(channel)

  ([[0,1], [1,1], [1,0], [1,-1]].map do |delta|
    dx, dy = delta
    count_pieces(channel, row,  dx,  dy, piece) + 1 +
    count_pieces(channel, row, -dx, -dy, piece)
  end).max
end

#valid_channel?(channel) ⇒ Boolean

Is this a valid channel?

Returns:

  • (Boolean)


159
160
161
# File 'lib/connect_n_game/game/rack.rb', line 159

def valid_channel?(channel)
  (1..width).include?(channel)
end

#valid_row?(row) ⇒ Boolean

Is this a valid row?

Returns:

  • (Boolean)


164
165
166
# File 'lib/connect_n_game/game/rack.rb', line 164

def valid_row?(row)
  (1..depth).include?(row)
end