오픈 소스 모험: 에피소드 69: 수족관 퍼즐용 Crystal Z3 솔버
퍼즐에 익숙해지려면 몇 번 플레이하는 것이 좋습니다. 그러면 게시물을 더 쉽게 따라갈 수 있습니다.
수입자
늘 그렇듯이 큰 퍼즐의 모든 문자를 수동으로 입력하는 데 인내심이 없고 오류가 발생하기 쉬울 것이므로 Puzzle Team의 내부 형식에서 변환하는 임포터를 작성했습니다.
#!/usr/bin/env crystal
hints, board = ARGV[0].split(";", 2)
hints = hints.split("_")
size = hints.size // 2
top = hints[0, size]
left = hints[size, size]
board = board.split(",").map{|c| (96+c.to_i).chr}.join.scan(/.{#{size}}/).map(&.[0])
puts ["  #{top.join}\n\n", left.zip(board).map{|a,b| "#{a} #{b}\n"}.join].join
$ ./import_puzzle '5_3_1_3_3_5_5_3_4_4_2_3_4_4_4_6_3_2_2_6;1,1,1,1,2,3,3,4,4,5,1,6,6,6,2,7,4,4,5,5,1,8,8,2,2,7,4,4,5,9,10,10,10,11,2,7,12,12,9,9,13,13,10,11,11,11,12,14,14,9,15,13,10,10,16,12,12,12,12,12,15,13,10,10,16,12,17,17,17,17,15,13,10,10,16,18,18,18,18,17,19,10,10,16,16,20,18,17,17,17,19,10,10,16,20,20,18,18,18,17' > 1.txt
일반 텍스트 입력
결과는 다음과 같습니다.
  5313355344
2 aaaabccdde
3 afffbgddee
4 ahhbbgddei
4 jjjkbgllii
4 mmjkkklnni
6 omjjplllll
3 omjjplqqqq
2 omjjprrrrq
2 sjjpptrqqq
6 sjjpttrrrq
조금 덜 바쁘게 하기 위해 힌트와 보드 사이에 여분의 열과 행을 추가했습니다.
솔버
솔버는 다음과 같습니다.
#!/usr/bin/env crystal
require "z3"
class AquariumSolver
  @col_hints : Array(Int32)
  @row_hints : Array(Int32)
  @board : Array(Array(Char))
  @containers : Set(Char)
  def initialize(path)
    lines = File.read_lines(path)
    @col_hints = lines[0][2..].chars.map(&.to_i)
    @xsize = @col_hints.size
    @row_hints = lines[2..].map(&.[0].to_i)
    @ysize = @row_hints.size
    @board = lines[2..].map{|l| l[2..].chars}
    @containers = @board.flatten.to_set
    @solver = Z3::Solver.new
    @cells = {} of Tuple(Int32, Int32) => Z3::BoolExpr
    @water_levels = {} of Char => Z3::IntExpr
  end
  def each_coord
    @xsize.times do |x|
      @ysize.times do |y|
        yield(x, y)
      end
    end
  end
  def row_cell_count(y)
    (0...@xsize).map{|x| @cells[{x,y}].ite(1, 0)}.reduce{|a,b| a+b}
  end
  def col_cell_count(x)
    (0...@ysize).map{|y| @cells[{x,y}].ite(1, 0)}.reduce{|a,b| a+b}
  end
  def call
    # Initialize cell variables
    each_coord do |x, y|
      @cells[{x,y}] = Z3.bool("cell #{x},#{y}")
    end
    # Initialize water level variables
    # We could restrict it more tightly to make solution unambiguous
    # Right now container at levels 4-6 can have any level 0-10
    # even though 0-4 means same (all full), and 6-10 means same (all empty)
    @containers.each do |c|
      @water_levels[c] = v = Z3.int("level #{c}")
      @solver.assert v >= 0
      @solver.assert v <= @ysize
    end
    # All cells in each container have correct water level
    each_coord do |x, y|
      c = @board[y][x]
      @solver.assert @cells[{x,y}] == (y >= @water_levels[c])
    end
    # Row hints are correct
    @ysize.times do |y|
      @solver.assert row_cell_count(y) == @row_hints[y]
    end
    # Col hints are correct
    @xsize.times do |x|
      @solver.assert col_cell_count(x) == @col_hints[x]
    end
    # Print the solution
    if @solver.satisfiable?
      model = @solver.model
      @ysize.times do |y|
        @xsize.times do |x|
          v = (model[@cells[{x, y}]].to_s == "true")
          if v
            print "#"
          else
            print "."
          end
        end
        print "\n"
      end
    else
      puts "No solution"
    end
  end
end
AquariumSolver.new(ARGV[0]).call
솔버는 일반적으로 이전 솔버에서 이미 다룬 기술을 사용합니다.
결과
$ ./aquarium 1.txt
.....##...
.###......
......####
...##...##
...###...#
#....#####
##...#....
##........
#.....#...
#...#####.
지금까지의 이야기
All the code is on GitHub .
다음에 온다
다음 몇 개의 에피소드에 걸쳐 Crystal 및 Z3에서 몇 가지 더 많은 퍼즐 게임 해결사를 코딩할 것입니다.
Reference
이 문제에 관하여(오픈 소스 모험: 에피소드 69: 수족관 퍼즐용 Crystal Z3 솔버), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://dev.to/taw/open-source-adventures-episode-69-crystal-z3-solver-for-aquarium-puzzle-224j텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
                                
                                
                                
                                
                                
                                우수한 개발자 콘텐츠 발견에 전념
                                (Collection and Share based on the CC Protocol.)