重构战舰游戏
我正在用 Ruby 创建战舰游戏。 让我解释一下它是如何工作的:
- 游戏在 5x5 网格上进行(每个玩家一个)。
- 玩家各有 2 艘船放置在自己的网格上。一艘小船(3x1 边)和一艘大船(4x1 尺寸)。
- 玩家被要求依次将他们的船只放置在棋盘上。一艘船不能放置在界限之外,也不能与另一艘船放置在同一空间内。
- 玩家通过选择坐标轮流向对方网格射击。
- 第一个达到 7 分(所有船只都沉没)的玩家获胜。
正如您所看到的,我的代码的某些部分非常重复:
- 我要求每个玩家放置其 2 艘船,因此我有 4 次“相同”代码(
--- PLACMENT OF THE SIZE 3 SHIP OF #{ name_p1.upcase} ---
)。 - 我要求玩家轮流向对手的网格射击(这样做两次)。
- 当我打印射击结果时,同样的问题。
我正在努力重构我的代码以使其更简单、更短。 怎样才能简化呢?
# Board for player 1
board1 = []
for i in 0..4
board1[i] = []
(0..4).each do
board1[i].append('O')
end
end
# Board for player 2
board2 = []
for i in 0..4
board2[i] = []
(0..4).each do
board2[i].append('O')
end
end
# Display the boards
def display_board(board)
for row in board
puts row.map { |k| "#{k}" }.join(' ')
end
end
def check_obstacle(ship_size, player_array, posX, posY, direction)
check = 0
@ship_present = 0
@space_available = 0
@ship_present += 1 if player_array[posX][posY] == 1
@space_available += 1 if player_array[posX][posY] == 0
while check < ship_size && @space_available < ship_size
case direction
when 'north' then posX -= 1
when 'east' then posY += 1
when 'south' then posX += 1
when 'west' then posY -= 1
end
@space_available += 1 if posX.between?(0, 4) && posY.between?(0, 4)
@ship_present += 1 if posX.between?(0, 4) && posY.between?(0, 4) && player_array[posX][posY] == 1
check += 1
end
@space_available == ship_size && @ship_present == 0
end
def ship_placement(ship_size, player_array, posX, posY, direction)
steps = 0
while steps < ship_size && @ship_present == 0 && @space_available == ship_size
player_array[posX][posY] = 1
case direction
when 'north' then posX -= 1
when 'east' then posY += 1
when 'south' then posX += 1
when 'west' then posY -= 1
end
steps += 1
end
puts "The ship of size #{ship_size} is placed."
end
# Generation of the player boards
array1 = [[0, 0, 0, 0, 0], [0, 0, 0, 0, 0], [0, 0, 0, 0, 0], [0, 0, 0, 0, 0], [0, 0, 0, 0, 0]]
array2 = [[0, 0, 0, 0, 0], [0, 0, 0, 0, 0], [0, 0, 0, 0, 0], [0, 0, 0, 0, 0], [0, 0, 0, 0, 0]]
# A player wins when he/she reaches 7 points (2 ships each to place on their grid : a small ship (3x1 side) and a large one (4x1 size))
solution = 7
# We set the number of points at 0 at the start of the game
points_p1 = 0
points_p2 = 0
#Starting of the game and printing the board
while true do
puts 'Welcome soldiers!'
puts 'To start the game, enter "start". To quit, enter "stop":'
starting = gets.chomp
puts "\n"
case starting.downcase
when 'start'
puts 'Enter the first name of the first player:'
name_p1 = gets.chomp.to_s
puts "\n"
puts 'Enter the first name of the second player:'
name_p2 = gets.chomp.to_s
puts "\n"
puts "--- PLACEMENT OF THE SIZE 3 SHIP OF #{name_p1.upcase} ---"
while true
while true
puts 'Enter LINE number (between 1 and 5):'
placement_row = gets.chomp.to_i-1
break if placement_row.between?(0, 4)
end
while true
puts 'Enter COLUMN number (between 1 and 5):'
placement_column = gets.chomp.to_i-1
break if placement_column.between?(0, 4)
end
while true
puts "Enter ship direction (north, east, south ou west)"
orientation = gets.chomp.downcase
break if %w(north east south west).include? orientation
end
if check_obstacle(3, array1, placement_row, placement_column, orientation)
ship_placement(3, array1, placement_row, placement_column, orientation)
break
else
puts "Unable to place. Please try again."
end
end
puts "--- PLACEMENT OF THE SIZE 4 SHIP OF #{name_p1.upcase} ---"
while true
while true
puts 'Enter LINE number (between 1 and 5):'
placement_row = gets.chomp.to_i-1
break if placement_row.between?(0, 4)
end
while true
puts 'Enter COLUMN number (between 1 and 5):'
placement_column = gets.chomp.to_i-1
break if placement_column.between?(0, 4)
end
while true
puts "Enter ship direction (north, east, south ou west)"
orientation = gets.chomp.downcase
break if %w(north east south west).include? orientation
end
if check_obstacle(4, array1, placement_row, placement_column, orientation)
ship_placement(4, array1, placement_row, placement_column, orientation)
break
else
puts "Unable to place. Please try again."
end
end
###############################################################
puts "--- PLACEMENT OF THE SIZE 3 SHIP OF #{name_p2.upcase} ---"
while true
while true
puts 'Enter LINE number (between 1 and 5):'
placement_row = gets.chomp.to_i-1
break if placement_row.between?(0, 4)
end
while true
puts 'Enter COLUMN number (between 1 and 5):'
placement_column = gets.chomp.to_i-1
break if placement_column.between?(0, 4)
end
while true
puts "Enter ship direction (north, east, south ou west)"
orientation = gets.chomp.downcase
break if %w(north east south west).include? orientation
end
if check_obstacle(3, array2, placement_row, placement_column, orientation)
ship_placement(3, array2, placement_row, placement_column, orientation)
break
else
puts "Unable to place. Please try again."
end
end
puts "--- PLACEMENT OF THE SIZE 4 SHIP OF #{name_p2.upcase} ---"
while true
while true
puts 'Enter LINE number (between 1 and 5):'
placement_row = gets.chomp.to_i-1
break if placement_row.between?(0, 4)
end
while true
puts 'Enter COLUMN number (between 1 and 5):'
placement_column = gets.chomp.to_i-1
break if placement_column.between?(0, 4)
end
while true
puts "Enter ship direction (north, east, south ou west)"
orientation = gets.chomp.downcase
break if %w(north east south west).include? orientation
end
if check_obstacle(4, array2, placement_row, placement_column, orientation)
ship_placement(4, array2, placement_row, placement_column, orientation)
break
else
puts "Unable to place. Please try again."
end
end
while points_p1 < solution || points_p2 < solution
puts "--- #{name_p1.upcase}'S TURN ---"
while true
puts 'Enter LINE number (between 1 and 5):'
row_p1 = gets.chomp.to_i-1
break if row_p1.between?(0, 4)
end
while true
puts 'Enter COLUMN number (between 1 and 5):'
column_p1 = gets.chomp.to_i-1
break if column_p1.between?(0, 4)
end
# Shot fired!
case array1[row_p1][column_p1]
when 1
board1[row_p1][column_p1] = 'X'
array1[row_p1][column_p1] = 'X'
points_p1 += 1
when 0
board1[row_p1][column_p1] = '-'
array1[row_p1][column_p1] = '-'
when 'X', '-'
puts 'Square already played.'
next
end
puts "\n"
puts '--------------'
display_board(board1)
puts '--------------'
puts '----------------------'
puts "#{name_p1} has #{points_p1} point#{"s" if points_p1 > 1}."
puts '----------------------'
puts "\n"
break if points_p1 == solution
puts "--- #{name_p2.upcase}'S TURN ---"
while true
puts 'Enter LINE number (between 1 and 5):'
row_p2 = gets.chomp.to_i-1
break if row_p2.between?(0, 4)
end
while true
puts 'Enter COLUMN number (between 1 and 5):'
column_p2 = gets.chomp.to_i-1
break if column_p2.between?(0, 4)
end
# Shot fired!
case array2[row_p2][column_p2]
when 1
board2[row_p2][column_p2] = 'X'
array2[row_p1][column_p1] = 'X'
points_p2 += 1
when 0
board2[row_p2][column_p2] = '-'
when 'X', '-'
next
end
puts "\n"
puts '--------------'
display_board(board2)
puts '--------------'
puts '----------------------'
puts "#{name_p2} has #{points_p2} point#{"s" if points_p2 > 1}."
puts '----------------------'
puts "\n"
break if points_p2 == solution
end
puts "Congratulations #{name_p1}, you have destroyed all the enemy ships!" if points_p1 == solution
puts "Congratulations #{name_p2}, you have destroyed all the enemy ships!" if points_p2 == solution
puts "\n"
break
when 'stop'
puts 'See you soon!'
break
else
puts 'Please make a choice between "start". To exit, enter "stop".'
puts "\n"
end
end
I'm creating a battleship game in Ruby.
Let me explain how it works:
- The game is played on 5x5 grids (one per player).
- Players have 2 ships each to place on their grid. A small ship (3x1 side) and a large one (4x1 size).
- Players are asked in turn to place their ships on their board. A ship can't be placed out of bounds nor on the same space as another ship.
- Players take turns to shoot at the opponent grid one after the other by selecting coordinates.
- The first player to reach 7 points (all boats sinked) wins the game.
As you can see, some parts of my code are very repetitive:
- I ask to each player to place its 2 ships so I have the "same" code 4 times (
--- PLACEMENT OF THE SIZE 3 SHIP OF #{name_p1.upcase} ---
). - I ask players to take turns to shoot at the opponent grid one after the other (this is done twice).
- Same problem when I print the result of a shot.
I'm very struggling to refactor my code to make it simpler and shorter.
How can it be simplified?
# Board for player 1
board1 = []
for i in 0..4
board1[i] = []
(0..4).each do
board1[i].append('O')
end
end
# Board for player 2
board2 = []
for i in 0..4
board2[i] = []
(0..4).each do
board2[i].append('O')
end
end
# Display the boards
def display_board(board)
for row in board
puts row.map { |k| "#{k}" }.join(' ')
end
end
def check_obstacle(ship_size, player_array, posX, posY, direction)
check = 0
@ship_present = 0
@space_available = 0
@ship_present += 1 if player_array[posX][posY] == 1
@space_available += 1 if player_array[posX][posY] == 0
while check < ship_size && @space_available < ship_size
case direction
when 'north' then posX -= 1
when 'east' then posY += 1
when 'south' then posX += 1
when 'west' then posY -= 1
end
@space_available += 1 if posX.between?(0, 4) && posY.between?(0, 4)
@ship_present += 1 if posX.between?(0, 4) && posY.between?(0, 4) && player_array[posX][posY] == 1
check += 1
end
@space_available == ship_size && @ship_present == 0
end
def ship_placement(ship_size, player_array, posX, posY, direction)
steps = 0
while steps < ship_size && @ship_present == 0 && @space_available == ship_size
player_array[posX][posY] = 1
case direction
when 'north' then posX -= 1
when 'east' then posY += 1
when 'south' then posX += 1
when 'west' then posY -= 1
end
steps += 1
end
puts "The ship of size #{ship_size} is placed."
end
# Generation of the player boards
array1 = [[0, 0, 0, 0, 0], [0, 0, 0, 0, 0], [0, 0, 0, 0, 0], [0, 0, 0, 0, 0], [0, 0, 0, 0, 0]]
array2 = [[0, 0, 0, 0, 0], [0, 0, 0, 0, 0], [0, 0, 0, 0, 0], [0, 0, 0, 0, 0], [0, 0, 0, 0, 0]]
# A player wins when he/she reaches 7 points (2 ships each to place on their grid : a small ship (3x1 side) and a large one (4x1 size))
solution = 7
# We set the number of points at 0 at the start of the game
points_p1 = 0
points_p2 = 0
#Starting of the game and printing the board
while true do
puts 'Welcome soldiers!'
puts 'To start the game, enter "start". To quit, enter "stop":'
starting = gets.chomp
puts "\n"
case starting.downcase
when 'start'
puts 'Enter the first name of the first player:'
name_p1 = gets.chomp.to_s
puts "\n"
puts 'Enter the first name of the second player:'
name_p2 = gets.chomp.to_s
puts "\n"
puts "--- PLACEMENT OF THE SIZE 3 SHIP OF #{name_p1.upcase} ---"
while true
while true
puts 'Enter LINE number (between 1 and 5):'
placement_row = gets.chomp.to_i-1
break if placement_row.between?(0, 4)
end
while true
puts 'Enter COLUMN number (between 1 and 5):'
placement_column = gets.chomp.to_i-1
break if placement_column.between?(0, 4)
end
while true
puts "Enter ship direction (north, east, south ou west)"
orientation = gets.chomp.downcase
break if %w(north east south west).include? orientation
end
if check_obstacle(3, array1, placement_row, placement_column, orientation)
ship_placement(3, array1, placement_row, placement_column, orientation)
break
else
puts "Unable to place. Please try again."
end
end
puts "--- PLACEMENT OF THE SIZE 4 SHIP OF #{name_p1.upcase} ---"
while true
while true
puts 'Enter LINE number (between 1 and 5):'
placement_row = gets.chomp.to_i-1
break if placement_row.between?(0, 4)
end
while true
puts 'Enter COLUMN number (between 1 and 5):'
placement_column = gets.chomp.to_i-1
break if placement_column.between?(0, 4)
end
while true
puts "Enter ship direction (north, east, south ou west)"
orientation = gets.chomp.downcase
break if %w(north east south west).include? orientation
end
if check_obstacle(4, array1, placement_row, placement_column, orientation)
ship_placement(4, array1, placement_row, placement_column, orientation)
break
else
puts "Unable to place. Please try again."
end
end
###############################################################
puts "--- PLACEMENT OF THE SIZE 3 SHIP OF #{name_p2.upcase} ---"
while true
while true
puts 'Enter LINE number (between 1 and 5):'
placement_row = gets.chomp.to_i-1
break if placement_row.between?(0, 4)
end
while true
puts 'Enter COLUMN number (between 1 and 5):'
placement_column = gets.chomp.to_i-1
break if placement_column.between?(0, 4)
end
while true
puts "Enter ship direction (north, east, south ou west)"
orientation = gets.chomp.downcase
break if %w(north east south west).include? orientation
end
if check_obstacle(3, array2, placement_row, placement_column, orientation)
ship_placement(3, array2, placement_row, placement_column, orientation)
break
else
puts "Unable to place. Please try again."
end
end
puts "--- PLACEMENT OF THE SIZE 4 SHIP OF #{name_p2.upcase} ---"
while true
while true
puts 'Enter LINE number (between 1 and 5):'
placement_row = gets.chomp.to_i-1
break if placement_row.between?(0, 4)
end
while true
puts 'Enter COLUMN number (between 1 and 5):'
placement_column = gets.chomp.to_i-1
break if placement_column.between?(0, 4)
end
while true
puts "Enter ship direction (north, east, south ou west)"
orientation = gets.chomp.downcase
break if %w(north east south west).include? orientation
end
if check_obstacle(4, array2, placement_row, placement_column, orientation)
ship_placement(4, array2, placement_row, placement_column, orientation)
break
else
puts "Unable to place. Please try again."
end
end
while points_p1 < solution || points_p2 < solution
puts "--- #{name_p1.upcase}'S TURN ---"
while true
puts 'Enter LINE number (between 1 and 5):'
row_p1 = gets.chomp.to_i-1
break if row_p1.between?(0, 4)
end
while true
puts 'Enter COLUMN number (between 1 and 5):'
column_p1 = gets.chomp.to_i-1
break if column_p1.between?(0, 4)
end
# Shot fired!
case array1[row_p1][column_p1]
when 1
board1[row_p1][column_p1] = 'X'
array1[row_p1][column_p1] = 'X'
points_p1 += 1
when 0
board1[row_p1][column_p1] = '-'
array1[row_p1][column_p1] = '-'
when 'X', '-'
puts 'Square already played.'
next
end
puts "\n"
puts '--------------'
display_board(board1)
puts '--------------'
puts '----------------------'
puts "#{name_p1} has #{points_p1} point#{"s" if points_p1 > 1}."
puts '----------------------'
puts "\n"
break if points_p1 == solution
puts "--- #{name_p2.upcase}'S TURN ---"
while true
puts 'Enter LINE number (between 1 and 5):'
row_p2 = gets.chomp.to_i-1
break if row_p2.between?(0, 4)
end
while true
puts 'Enter COLUMN number (between 1 and 5):'
column_p2 = gets.chomp.to_i-1
break if column_p2.between?(0, 4)
end
# Shot fired!
case array2[row_p2][column_p2]
when 1
board2[row_p2][column_p2] = 'X'
array2[row_p1][column_p1] = 'X'
points_p2 += 1
when 0
board2[row_p2][column_p2] = '-'
when 'X', '-'
next
end
puts "\n"
puts '--------------'
display_board(board2)
puts '--------------'
puts '----------------------'
puts "#{name_p2} has #{points_p2} point#{"s" if points_p2 > 1}."
puts '----------------------'
puts "\n"
break if points_p2 == solution
end
puts "Congratulations #{name_p1}, you have destroyed all the enemy ships!" if points_p1 == solution
puts "Congratulations #{name_p2}, you have destroyed all the enemy ships!" if points_p2 == solution
puts "\n"
break
when 'stop'
puts 'See you soon!'
break
else
puts 'Please make a choice between "start". To exit, enter "stop".'
puts "\n"
end
end
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
正如 David 在评论中提到的,您确实想利用 Ruby 的面向对象功能。
以下是我整理的一些组件和一些示例用法。 (看起来像是一个有趣的练习......我想我得意忘形了。)
As David mentions in his comment, you really want to make use of Ruby's object oriented features.
Here are some components I put together and some example usage. (Seemed like a fun exercise ... I guess I got carried away.)