Advertisement
Guest User

Рексудо

a guest
Jun 26th, 2017
66
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Ruby 5.32 KB | None | 0 0
  1. class Game_Player #Эти методы дергать в Вызов скрипта
  2.   attr_reader :puzzle
  3.   def sudoku_new_puzzle(level = 3)#Сложность генератора, от 1 до 5
  4.     @puzzle = Game_Sudoku.new
  5.     p "Created!"
  6.     @puzzle.generate_puzzle(level)
  7.     p "Generated!"
  8.   end
  9.  
  10.   def sudoku_state #сутус судоку
  11.     @puzzle.current_state
  12.   end
  13.  
  14.   def sudoku_solve #решить судоку
  15.     @puzzle.solve
  16.   end
  17.  
  18.   def sudoku_solved? #решено ли судоку?
  19.     @puzzle.solved?
  20.   end
  21.  
  22.   def sudoku_set(x, y, num)
  23.     #str = @puzzle.get_str
  24.     #str[y*9 + x] = num.to_s
  25.     #@puzzle.upload(str)
  26.     @puzzle.sudarr[x*9 + y] = num
  27.   end
  28.  
  29.  
  30.   def sudoku_debug#Вывод в консоль
  31.     p @puzzle.sudarr
  32.     p @puzzle.get_str
  33.     puts @puzzle.sudoku_print
  34.   end
  35. end
  36.  
  37. class Game_Sudoku
  38.  
  39.   attr_accessor :sudarr
  40.  
  41.   def initialize(puzzle_str = '0' * 81)  
  42.     valid?(puzzle_str) ? upload(puzzle_str) : raise(ArgumentError, error_m)
  43.   end
  44.   def get_str
  45.     retstr = ""
  46.     @sudarr.each{ |num|
  47.       retstr << num.to_s
  48.     }
  49.     return retstr
  50.   end
  51.   def upload(puzzle_str)#конвертация строки
  52.     @sudarr = puzzle_str.chars.map(&:to_i)
  53.   end
  54.  
  55.   def rows
  56.     @sudarr.each_slice(9).to_a
  57.   end
  58.  
  59.   def columns
  60.     rows.transpose
  61.   end
  62.  
  63.   def peers_of(index)
  64.     peers = [rows[index/9], columns[index%9], boxes[box_of(index)]]
  65.     peers.flatten.uniq.reject { |value| value == (0 || value_of(index)) }
  66.   end
  67.  
  68.   def boxes(values = rows)
  69.     (0..2).inject([]) do |boxes, index|
  70.       boxes + values.slice(3 * index, 3).transpose.each_slice(3).map(&:flatten)
  71.     end
  72.   end
  73.  
  74.   def box_of(index)
  75.     boxes(indexed).map { |boxes| boxes & [index] }.index([index])
  76.   end
  77.  
  78.   def indexed
  79.     @sudarr.map.with_index { |_, index| index }.each_slice(9).to_a
  80.   end
  81.  
  82.   def current_state
  83.     @sudarr.join
  84.   end
  85.  
  86.   def sudoku_print #Форматирует для вывода в коноль или в файл, для теста
  87.     separator = '-' * 21 + "\n"
  88.     squares = rows.each { |row| row.insert(3, '|').insert(7, '|').insert(11, "\n").join(' ') }
  89.     squares.insert(3, separator).insert(7, separator).join(' ').prepend("\n ").concat("\n")
  90.   end
  91.  
  92.   def valid?(puzzle_str) #Если стрка судоки валидная
  93.     (/^\d{81}$/) === puzzle_str ? true : false
  94.   end
  95.  
  96.   def str_err_msg
  97.     'Argument must be String of 81 digits'
  98.   end
  99.  
  100.   #Логика генератора
  101.  
  102.   def generate_puzzle(level = 3)
  103.     raise(ArgumentError, lev_err) unless (1..5).include?(level)
  104.     p "Good!"
  105.     delete_puzzle
  106.     create_seed
  107.     p "Seed generated!"
  108.     solve ? punch_to(level) : generate_puzzle(level)
  109.   end
  110.  
  111.   def delete_puzzle
  112.     @sudarr = Array.new(81, 0)
  113.   end
  114.  
  115.   def create_seed
  116.     for sead_box in seed_indices
  117.       seed_values = (1..9).to_a.shuffle
  118.       sead_box.each_with_index { |seed, index| @sudarr[seed] = seed_values[index] }
  119.     end
  120.   end
  121.  
  122.   def seed_indices
  123.     boxes(indexed).select.with_index { |box, index| box if [0, 4, 8].include?(index) }
  124.   end
  125.  
  126.   def punch_to(level)
  127.     num_of_punches = level * 10 + 21
  128.     p num_of_punches
  129.     while num_of_punches > 0
  130.       rnd = Random.new(Time.new.usec)#Генератор случайнх ческл с семенеем
  131.       random_square = rnd.rand(0..80)
  132.       p random_square
  133.       (sudarr[random_square] = 0 and num_of_punches -= 1) if solved_at?(random_square)
  134.     end
  135.     p "Punched!"
  136.   end
  137.  
  138.   def lev_err
  139.     'Argument must be Fixnum between 1-5'
  140.   end
  141.  
  142.   #Логика решателя
  143.   attr_reader :solution_arr
  144.  
  145.   def solve #Пытаемся решить
  146.     first_try
  147.     second_try unless solved?
  148.     solved? ? (set_solution and return true) : false
  149.   end
  150.  
  151.   def first_try#Первый способ
  152.     current_puzzle_state, stop_looping = 81, false
  153.     until solved? || stop_looping
  154.       solve_all_squares
  155.       stop_looping = true if current_puzzle_state == solved_squares_count
  156.       current_puzzle_state = solved_squares_count
  157.     end
  158.   end
  159.  
  160.   def second_try#Второй, если первый не помог
  161.     unsolved_index = first_unsolved_square
  162.     candidates_for(unsolved_index).each do |candidate|
  163.       sudarr[unsolved_index] = candidate
  164.       puzzle_clone = self.class.new(current_state)
  165.       self.upload(puzzle_clone.current_state) and return if puzzle_clone.solve
  166.     end
  167.   end
  168.  
  169.   def solve_all_squares
  170.     sudarr.each_index { |index| solve_at(index) }
  171.   end
  172.  
  173.   def solve_at(index)
  174.     solutions = candidates_for(index) || []
  175.     sudarr[index] = solutions.first if solutions.count == 1
  176.   end
  177.  
  178.   def solved_squares_count
  179.     sudarr.count { |square| square != 0 }
  180.   end
  181.  
  182.   def first_unsolved_square
  183.     sudarr.index(0)
  184.   end
  185.  
  186.   def candidates_for(index)
  187.     candidates = (1..9).to_a - peers_of(index)
  188.     candidates.sort unless solved_at?(index)
  189.   end
  190.  
  191.   def solved_at?(index)
  192.     sudarr[index] != 0
  193.   end
  194.  
  195.   def solved?
  196.     (rows + columns + boxes).map { |values| values.sort == (1..9).to_a }.all?
  197.   end
  198.  
  199.   def set_solution
  200.     @solution_arr = sudarr.join.chars.map(&:to_i)
  201.   end
  202.  
  203.   def solution_str
  204.     solution_arr ? solution_arr.join : ''
  205.   end
  206. end
  207. class String #в ргсс3 руби 1.9.2, метода препенд нет(
  208.   def prepend(str)
  209.     str + self
  210.   end
  211. end
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement