Created
January 3, 2026 02:19
-
-
Save seki/784c839af1b392055e93806ddba3fc2a to your computer and use it in GitHub Desktop.
Ractor study. NQueen with tuplespace.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| require 'rinda/tuplespace' | |
| class TupleSpace4Ractor | |
| class Impl | |
| def initialize | |
| @ts = Rinda::TupleSpace.new #FIXME | |
| @read_waiter = [] | |
| @take_waiter = [] | |
| end | |
| def do_take(port, pattern) | |
| tuple = @ts.take(pattern, 0) | |
| port << tuple | |
| true | |
| rescue Rinda::RequestExpiredError | |
| false | |
| end | |
| def do_read(port, pattern) | |
| tuple = @ts.read(pattern, 0) | |
| port << tuple | |
| true | |
| rescue Rinda::RequestExpiredError | |
| false | |
| end | |
| def do_write(tuple) | |
| @ts.write(tuple) | |
| @read_waiter.delete_if {|port, pattern| do_read(port, pattern)} | |
| taken = false | |
| @take_waiter.delete_if {|port, pattern| | |
| break if taken | |
| taken = do_take(port, pattern) | |
| } | |
| end | |
| def main_loop | |
| while true | |
| command, tuple, port = Ractor.receive | |
| case command | |
| when :read | |
| @read_waiter << [port, tuple] unless do_read(port, tuple) | |
| when :take | |
| @take_waiter << [port, tuple] unless do_take(port, tuple) | |
| when :write | |
| do_write(tuple) | |
| end | |
| end | |
| end | |
| end | |
| def initialize | |
| @ractor = Ractor.new { Impl.new.main_loop } | |
| end | |
| def take(pattern) | |
| port = Ractor::Port.new | |
| @ractor << [:take, pattern, port] | |
| port.receive | |
| end | |
| def read(pattern) | |
| port = Ractor::Port.new | |
| @ractor << [:read, pattern, port] | |
| port.receive | |
| end | |
| def write(tuple) | |
| @ractor << [:write, tuple] | |
| nil | |
| end | |
| end | |
| module NQueen | |
| module_function | |
| def concat(board, row) | |
| board.each_with_index do |v, col| | |
| check = (v - row).abs | |
| return nil if check == 0 | |
| return nil if check == board.size - col | |
| end | |
| board + [row] | |
| end | |
| def nq(size, board=[]) | |
| found = 0 | |
| size.times do |row| | |
| fwd = concat(board, row) | |
| next unless fwd | |
| return 1 if fwd.size == size | |
| found += nq(size, fwd) | |
| end | |
| found | |
| end | |
| def nq2(size, r1, r2) | |
| board = concat([r1], r2) | |
| return 0 unless board | |
| nq(size, board) | |
| end | |
| end | |
| def invoke_engine(rinda, num) | |
| num.times do | |
| Ractor.new(rinda) do |ts| | |
| while true | |
| sym, size, r1, r2 = ts.take([:nq, Integer, Integer, Integer]) | |
| ts.write([:nq_ans, size, r1, r2, NQueen.nq2(size, r1, r2)]) | |
| end | |
| ts.write([:nq_engine]) | |
| end | |
| end | |
| end | |
| def write_q(rinda, size) | |
| size.times do |r1| | |
| size.times do |r2| | |
| rinda.write([:nq, size, r1, r2]) | |
| end | |
| end | |
| end | |
| def take_a(rinda, size) | |
| found = 0 | |
| size.times do |r1| | |
| size.times do |r2| | |
| tuple = rinda.take([:nq_ans, size, r1, r2, nil]) | |
| found += tuple[4] | |
| end | |
| end | |
| found | |
| end | |
| def resolve(rinda, size) | |
| write_q(rinda, size) | |
| take_a(rinda, size) | |
| end | |
| rinda = TupleSpace4Ractor.new | |
| size = (ARGV.shift || '5').to_i | |
| invoke_engine(rinda, 8) | |
| puts resolve(rinda, size) | |
| exit! |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment