一些ruby代码片段2 趣味代码
一些琐碎的代码片段,没有固定的主题。
部分代码有问题,注意检查一下。
算 24
def calc24(nums, expr = nums)
if nums.length == 1
nums[0] == 24? expr[0] : false
else
nums.length.times do |i|
nums.length.times do |j|
next if i == j
new_nums = nums.select_with_index{|_, idx| idx!=i && idx!=j}
new_expr = expr.select_with_index{|_, idx| idx!=i && idx!=j}
['+', '-', '*', '/'].each do |op|
next if op==:'/' && nums[j]==0
next if (op==:'+' || op==:'*') && i>j
new_nums.push nums[i].to_r.send(op, nums[j])
new_expr.push "(#{expr[i]})#{op}(#{expr[j]})"
end
x = calc24(new_nums, new_expr) and return x
new_nums.pop
new_expr.pop
end
end
end
nil
end
p calc24([6, 6, 8, 8]) # "((6*8)/(9-7))"
数独
TODO: 代码有问题,检查一下。
def is_valid(board, row, col, num)
# 检查行
(0..8).each do |i|
return false if board[row][i] == num
end
# 检查列
(0..8).each do |i|
return false if board[i][col] == num
end
# 检查3x3子网格
start_row = (row / 3) * 3
start_col = (col / 3) * 3
(0..2).each do |i|
(0..2).each do |j|
return false if board[start_row + i][start_col + j] == num
end
end
true
end
def solve_sudoku(board)
(0..8).each do |row|
(0..8).each do |col|
if board[row][col] == 0
(1..9).each do |num|
if is_valid(board, row, col, num)
board[row][col] = num
if solve_sudoku(board)
return true
else
board[row][col] = 0
end
end
end
return false
end
end
end
true
end
# 示例数独棋盘,0表示空白单元格
sudoku_board = [
[5, 3, 0, 0, 7, 0, 0, 0, 0],
[6, 0, 0, 1, 9, 5, 0, 0, 0],
[0, 9, 8, 0, 0, 0, 0, 6, 0],
[8, 0, 0, 0, 6, 0, 0, 0, 3],
[4, 0, 0, 8, 0, 3, 0, 0, 1],
[7, 0, 0, 0, 2, 0, 0, 0, 6],
[0, 6, 0, 0, 0, 0, 2, 8, 0],
[0, 0, 0, 4, 1, 9, 0, 0, 5],
[0, 0, 0, 0, 8, 0, 0, 7, 9]
]
if solve_sudoku(sudoku_board)
sudoku_board.each do |row|
puts row.join(' ')
end
else
puts "该数独无解"
end
黑白棋
TODO: 代码有问题,检查一下。
# 初始化棋盘
def init_board
board = Array.new(8) { Array.new(8, 0) }
board[3][3] = 1
board[3][4] = -1
board[4][3] = -1
board[4][4] = 1
board
end
# 打印棋盘,标记可用移动的编号
def print_board(board, moves)
puts "="*18
puts "| X: #{board.flatten.select(&:positive?).size} O: #{board.flatten.select(&:negative?).size}"
puts "+"+("-"*17)+"+"
move_index = 1
8.times do |i|
row = "|"
8.times do |j|
if moves.include?([i, j])
row += "%2d"%move_index
move_index += 1
else
case board[i][j]
when 1
row += ' X'
when -1
row += ' O'
else
row += ' '
end
end
end
row += ' |'
puts row
end
puts "+"+("-"*17)+"+"
end
# 判断是否在棋盘内
def is_on_board(x, y)
x >= 0 && x < 8 && y >= 0 && y < 8
end
# 获取有效落子位置
def get_valid_moves(board, player)
moves = []
8.times do |x|
8.times do |y|
if board[x][y] == 0 && is_valid_move(board, player, x, y)
moves << [x, y]
end
end
end
moves
end
# 判断落子是否有效
def is_valid_move(board, player, x, y)
return false if board[x][y] != 0
opponent = -player
directions = [[0, 1], [1, 1], [1, 0], [1, -1], [0, -1], [-1, -1], [-1, 0], [-1, 1]]
directions.each do |dx, dy|
new_x, new_y = x + dx, y + dy
if is_on_board(new_x, new_y) && board[new_x][new_y] == opponent
new_x += dx
new_y += dy
while is_on_board(new_x, new_y) && board[new_x][new_y] != 0
if board[new_x][new_y] == player
return true
end
new_x += dx
new_y += dy
end
end
end
false
end
# 执行落子
def make_move(board, player, x, y)
board[x][y] = player
opponent = -player
directions = [[0, 1], [1, 1], [1, 0], [1, -1], [0, -1], [-1, -1], [-1, 0], [-1, 1]]
directions.each do |dx, dy|
# p [dx, dy]
new_x, new_y = x + dx, y + dy
# tiles_to_flip = []
if is_on_board(new_x, new_y) && board[new_x][new_y] == opponent
tiles_to_flip = [[new_x, new_y]]
new_x += dx
new_y += dy
while is_on_board(new_x, new_y) && board[new_x][new_y] != 0
#p [:a,tiles_to_flip,[x,y],[new_x,new_y],player]
if board[new_x][new_y] == player
#p x: tiles_to_flip # , board:board
tiles_to_flip.each do |tx, ty|
#p tx:tx,ty:ty
board[tx][ty] = player
end
break
end
tiles_to_flip << [new_x, new_y]
new_x += dx
new_y += dy
end
end
end
end
# 位置权重矩阵
WEIGHT_MATRIX = [
[120, -20, 20, 5, 5, 20, -20, 120],
[-20, -40, -5, -5, -5, -5, -40, -20],
[20, -5, 15, 3, 3, 15, -5, 20],
[5, -5, 3, 3, 3, 3, -5, 5],
[5, -5, 3, 3, 3, 3, -5, 5],
[20, -5, 15, 3, 3, 15, -5, 20],
[-20, -40, -5, -5, -5, -5, -40, -20],
[120, -20, 20, 5, 5, 20, -20, 120]
]
# 计算得分,加上位置权重
def calculate_score(board)
score = 0
8.times do |i|
8.times do |j|
cell = board[i][j]
score += cell * WEIGHT_MATRIX[i][j]
end
end
score
end
# Minimax 算法 with Alpha - Beta 剪枝
def minimax(board, depth, alpha, beta, maximizing_player)
current_player = maximizing_player ? 1 : -1
if depth == 0 || get_valid_moves(board, 1).empty? && get_valid_moves(board, -1).empty?
return current_player*calculate_score(board)
end
best_eval = -Float::INFINITY
get_valid_moves(board, current_player).each do |move|
new_board = board.map(&:dup)
make_move(new_board, current_player, move[0], move[1])
eval_score = -minimax(new_board, depth - 1, -beta, -alpha, !maximizing_player)
best_eval = [best_eval, eval_score].max
alpha = [alpha, eval_score].max
break if beta <= alpha
end
return best_eval
end
# 获取最佳移动
def get_best_move(board, depth)
best_score = -Float::INFINITY
best_move = nil
get_valid_moves(board, 1).shuffle.each do |move|
new_board = board.map(&:dup)
make_move(new_board, 1, move[0], move[1])
score = -minimax(new_board, depth, -Float::INFINITY, Float::INFINITY, false)
# puts "位置 #{move} 打分 #{score}"
if score > best_score
best_score = score
best_move = move
end
end
best_move
end
# 游戏主循环
def play_game
board = init_board
loop do
player_moves = get_valid_moves(board, -1)
print_board(board, player_moves)
if player_moves.empty?
puts "玩家无可用移动,电脑继续。"
else
loop do
puts "请输入你的移动编号 (1 - #{player_moves.size}): "
# input = gets.chomp.to_i
input = rand(1..player_moves.size)
puts "> #{input}"
if (1..player_moves.size).include?(input)
x, y = player_moves[input-1]
make_move(board, -1, x, y)
break
else
puts "无效编号,请重新输入。"
end
end
end
computer_moves = get_valid_moves(board, 1)
print_board(board, computer_moves)
if computer_moves.empty?
puts "电脑无可用移动,游戏结束。"
break
end
computer_move = get_best_move(board, 3+1-1 )
make_move(board, 1, computer_move[0], computer_move[1])
puts "电脑移动\n> #{computer_moves.index(computer_move)+1}"
end
end
play_game if __FILE__ == $PROGRAM_NAME
八皇后
TODO: 代码有问题,检查一下。
class EightQueens
def initialize(n = 8)
@n = n
@solutions = []
end
def solve
board = Array.new(@n) { Array.new(@n, 0) }
backtrack(board, 0)
@solutions
end
end
private
def backtrack(board, col)
if col == @n
solution = []
board.each_with_index do |row, i|
row.each_with_index do |cell, j|
solution << [i, j] if cell == 1
end
end
@solutions << solution
return
end
(0...@n).each do |row|
if is_safe(board, row, col)
board[row][col] = 1
backtrack(board, col + 1)
board[row][col] = 0
end
end
end
def is_safe(board, row, col)
(0...col).each do |i|
return false if board[row][i] == 1
end
(row - 1).downto(0).zip((col - 1).downto(0)) do |i, j|
return false if board[i][j] == 1
end
((row + 1)...@n).zip((col - 1).downto(0)) do |i, j|
return false if board[i][j] == 1
end
true
end
end
# 使用示例
queens = EightQueens.new
solutions = queens.solve
puts "找到 #{solutions.length} 种解决方案:"
solutions.each_with_index do |solution, index|
puts "解决方案 #{index + 1}:"
solution.each do |queen|
puts "皇后位置: (#{queen[0]}, #{queen[1]})"
end
puts
end
汉诺塔
走迷宫
推箱子
参考
- Ruby Quiz https://rubyquiz.com/
- Rosetta Code https://rosettacode.org/wiki/Category:Ruby
- LeetCode https://leetcode.com/