1.class      # => Fixnum: liczba 1 jest typu Fixnum.
0.0.class    # => Float: liczby zmiennoprzecinkowe nale do klasy Float.
true.class   # => TrueClass: true to instancja singleton klasy TrueClass.
false.class  # => FalseClass.
nil.class    # => NilClass.

3.times { print "Ruby! " }   # Drukuje napis "Ruby! Ruby! Ruby!"
1.upto(9) {|x| print x }     # Drukuje "123456789"

a = [3, 2, 1]     # To jest litera tablicowy.
a[3] = a[2] - 1   # Aby pobra i ustawia elementy tablicy, naley uywa nawiasw kwadratowych.
a.each do |elt|   # Metoda each jest iteratorem. Niniejszy blok posiada parametr elt.
  print elt+1     # Drukuje "4321".
end               # Niniejszy blok jest ograniczony sowami kluczowymi do i end zamiast nawiasw {}.

a = [1,2,3,4]                # Tablica.
b = a.map {|x| x*x }         # Podnoszenie elementw do kwadratu. b = [1,4,9,16].
c = a.select {|x| x%2==0 }   # Wybieranie liczb parzystych. c = [2,4].
a.inject do |sum,x|          # Obliczanie sumy wszystkich elementw => 10.
  sum + x
end


h = {                         # Tablica asocjacyjna wica nazwy liczb z cyframi.
  :jeden => 1,                # Strzaki pokazuj odwzorowania klucz => warto.
  :dwa => 2                   # Dwukropek oznacza litera typu Symbol.
}
h[:jeden]                     # => 1.  Dostp do wartoci poprzez klucz.
h[:trzy] = 3                  # Dodanie nowej pary klucz-warto.
h.each do |key,value|         # Iteracja przez pary klucz-warto.
  print "#{value}:#{key}; "   # Zmienne zastpowane s acuchami.
end                           # Drukuje "1:jeden; 2:dwa; 3:trzy; "


File.open("data.txt") do |f| # Otwrz podany plik i przeka strumie do bloku.
  line = f.readline          # Uyj strumienia do odczytu pliku.
end                          # Strumie jest automatycznie zamykany w chwili napotkania sowa kluczowego end.
t = Thread.new do       # Wykonanie tego bloku w nowym wtku.
  File.read("data.txt") # Odczyt pliku w tle.
end                     # Zawarto pliku dostpna jako warto wtku.


print "#{value}:#{key}; "    # Zmienne zastpowane s acuchami.


minimum = if x < y then x else y end


1 + 2                    # => 3: dodawanie.
1 * 2                    # => 2: mnoenie.
1 + 2 == 3               # => true: == porwnywanie.
2 ** 1024                # 2 do potgi 1024: w jzyku Ruby liczby cakowite mog by dowolnej wielkoci.
"Ruby" + " rzdzi!"      # => "Ruby rzdzi!": konkatenacja acuchw.
"Ruby! " * 3             # => "Ruby! Ruby! Ruby! ": powtarzanie acuchw.
"%d %s" % [3, "rubiny"]  # => "3 rubiny": formatowanie w stylu metody printf Pythona.
max = x > y ? x : y      # Operator warunkowy.



def square(x)   # Definicja metody o nazwie square z jednym parametrem x.
  x*x           # Zwraca warto parametru x podniesionego do kwadratu.
end             # Koniec metody.



def Math.square(x)  # Definicja metody klasowej moduu Math.
  x*x
end



x = 1


x += 1          # Zwikszenie x: warto zauway, e w jzyku Ruby nie ma operatora ++.
y -= 1          # Zmniejszenie y: operatora -- rwnie nie ma.



x, y = 1, 2     # To samo co x = 1; y = 2.
a, b = b, a     # Zamiana wartoci dwch zmiennych.
x,y,z = [1,2,3] # Elementy tablic automatycznie przypisywane do zmiennych.


# Definicja metody konwertujcej wsprzdne ukadu kartezjaskiego (x, y) na wsprzdne biegunowe.
def polar(x,y)
  theta = Math.atan2(y,x)   # Obliczanie kta.
  r = Math.hypot(x,y)       # Obliczanie odlegoci.
  [r, theta]                # Ostatnie wyraenie okrela warto zwrotn.
end
# Uycie powyszej metody z przypisaniem rwnolegym.
distance, angle = polar(2,2)



o.x=(1)         # Normalna skadnia wywoania metody.
o.x = 1         # Wywoanie metody przez przypisanie.



/[Rr]uby/        # Pasuje do acucha "Ruby" i "ruby".
/\d{5}/          # Pasuje do piciu kolejnych cyfr.
1..3             # Wszystkie x, gdzie 1 <= x <= 3.
1...3            # Wszystkie x, gdzie 1 <= x < 3.



# Okrela nazw pokolenia w USA na podstawie daty urodzenia.
# Wyraenie case testuje zakresy za pomoc operatora ===.
generation = case birthyear
             when 1946..1963: "Baby Boomer"
             when 1964..1976: "Pokolenie X"
             when 1978..2000: "Pokolenie Y"
             else nil
             end
# Metoda proszca uytkownika o potwierdzenie czego.
def are_you_sure?                  # Definicja metody. Zwr uwag na znak zapytania!
  while true                       # Powtarzanie, a zostanie zwrcona warto.
    print "Na pewno? [t/n]: "      # Zadanie uytkownikowi pytania.
    response = gets                # Odbir odpowiedzi.
    case response                  # Pocztek instrukcji warunkowej case.
    when /^[tT]/                   # Jeli odpowied zaczyna si od litery t lub T,
      return true                  # zwrot wartoci true przez metod.
    when /^[nN]/, /^$/             # Jeli odpowied zaczyna si od n, N lub jest pusta,
      return false                 # zwrot wartoci false.
    end
  end
end



#
# Niniejsza klasa reprezentuje szereg liczb charakteryzowanych przez trzy
# parametry: from, to i by. Liczby x w szeregu podlegaj nastpujcym
# dwm ograniczeniom:
#
#    from <= x <= to
#    x = from + n*by, gdzie n jest liczb cakowit
#
class Sequence
  # Jest to klasa wyliczeniowa. Poniej znajduje si definicja iteratora each.
  include Enumerable   # Docza metody wymienionego moduu do tej klasy.
  # Metoda initialize jest wyjtkowa. Jest automatycznie wywoywana w celu
  # inicjacji nowo utworzonych egzemplarzy klasy.
  def initialize(from, to, by)
    # Zapisanie parametrw w zmiennych obiektowych do pniejszego uycia.
    @from, @to, @by = from, to, by  # Przypisanie rwnolege i przedrostek @.
  end
  # Iterator wymagany przez modu Enumerable.
  def each
    x = @from       # Rozpoczcie w punkcie startowym.
    while x <= @to  # Jeli nie osignito jeszcze koca,
      yield x       # przekazanie x do bloku zwizanego z iteratorem.
      x += @by      # Zwikszenie x.
    end
  end
  # Definicja metody length (tak jak tablice) zwracajcej liczb
  # wartoci w szeregu.
  def length
    return 0 if @from > @to       # if uyte jako modyfikator instrukcji.
    Integer((@to-@from)/@by) + 1  # Obliczenie i zwrcenie dugoci szeregu.
  end
  # Definicja innej nazwy dla tej samej metody.
  # W jzyku Ruby metody czsto maj po kilka nazw.
  alias size length  # size jest od tej pory synonimem nazwy length.
  # Przesonicie operatora dostpu do tablicy w celu umoliwienia dostpu swobodnego do szeregu.
  def[](index)
    return nil if index < 0 # Zwrot wartoci nil dla indeksw ujemnych.
    v = @from + index*@by   # Obliczenie wartoci.
    if v <= @to             # Jeli naley do szeregu,
      v                     # jest zwracana.
    else                    # W przeciwnym przypadku
      nil                   # zwrot wartoci nil.
    end
  end
  # Przesonicie operatorw arytmetycznych, aby zwracay nowe obiekty typu Sequence.
  def *(factor)
    Sequence.new(@from*factor, @to*factor, @by*factor)
  end
  def +(offset)
    Sequence.new(@from+offset, @to+offset, @by)
  end
end



s = Sequence.new(1, 10, 2)  # Od 1 do 10 co 2.
s.each {|x| print x }       # Drukuje "13579".
print s[s.size-1]           # Drukuje 9.
t = (s+1)*2                 # Od 4 do 22 co 4.



module Sequences                   # Nowy modu.
  def self.fromtoby(from, to, by)  # Metoda singleton moduu.
    x = from
    while x <= to
      yield x
      x += by
    end
  end
end



Sequences.fromtoby(1, 10, 2) {|x| print x }  # Drukuje "13579".


class Range                  # Otwarcie istniejcej klasy w celu jej rozszerzenia.
  def by(step)               # Definicja iteratora o nazwie by.
    x = self.begin           # Rozpoczcie w jednym punkcie kocowym zakresu.
    if exclude_end?          # Dla... zakresw, ktre nie wliczaj koca.
      while x < self.end     # Test przy uyciu operatora <.
        yield x
        x += step
      end
    else                     # W przeciwnym przypadku dla... zakresw, ktre zawieraj end.
      while x <= self.end    # Test przy uyciu operatora <=.
        yield x
        x += step
      end
    end
  end                        # Koniec definicji metody.
end                          # Koniec modyfikacji klasy.
# Przykady:
(0..10).by(2) {|x| print x}  # Drukuje "0246810".
(0...10).by(2) {|x| print x} # Drukuje "02468".



% ruby -e 'puts "witaj!"'
witaj!



% ruby hello.rb
hello world!



9.downto(1) {|n| print n }   # Brak znaku nowego wiersza pomidzy liczbami.
puts " start!"               # Zakoczenie znakiem nowego wiersza.



$ irb --simple-prompt       # Uruchomienie irb w terminalu.
>> 2**3                     # Prba potgowania.
=> 8                        # Wynik.
>> "Ruby! " * 3             # Prba powtarzania acuchw.
=> "Ruby! Ruby! Ruby! "     # Wynik.
>> 1.upto(3){|x| puts x }   # Prba iteratora.
1                           # Trzy wiersze danych wyjciowych,
2                           # poniewa funkcja puts zostaa wywoana trzy razy.
3
=> 1                        # Warto zwrotna wywoania 1.upto(3).
>> quit                     # Koniec dziaania irb.
$                           # Powrt do wiersza polece.



ri Array
ri Array.sort
ri Hash#each
ri Math::sqrt



# gem install rails
Successfully installed activesupport-1.4.4
Successfully installed activerecord-1.15.5
Successfully installed actionpack-1.13.5
Successfully installed actionmailer-1.3.5
Successfully installed actionwebservice-1.2.5
Successfully installed rails-1.2.5
6 gems installed
Installing ri documentation for activesupport-1.4.4...
Installing ri documentation for activerecord-1.15.5...
...itd...



gem list               # Wywietla list zainstalowanych gemw.
gem enviroment         # Wywietla informacj o konfiguracji RubyGems.
gem update rails       # Aktualizuje podany gem.
gem update             # Aktualizuje wszystkie zainstalowane gemy.
gem update --system    # Aktualizuje narzdzie RubyGems.
gem uninstall rails    # Usuwa zainstalowany gem.



require 'rubygems'               # Niepotrzebne w Ruby 1.9.
gem 'RedCloth', '> 2.0', '< 4.0' # Aktywacja gemu RedCloth w wersji 2.x lub 3.x.
require 'RedCloth'               # Zaadowanie powyszego gemu.



#
# Niniejszy modu definiuje klas Sudoku::Puzzle reprezentujc siatk 9x9
# oraz klasy wyjtkw zgaszanych w wyniku podania nieprawidowych danych i
# zbyt restrykcyjnych ogranicze amigwki. Modu ten definiuje take metod
# Sudoku.solve rozwizujc amigwk. Metoda solve uywa metody
# Sudoku.scan, ktra rwnie jest tutaj zdefiniowana.
#
# Aby uy tego moduu do rozwizywania sudoku, potrzebny jest kod jak poniej:
#
#  require 'Sudoku'
#  puts Sudoku.solve(Sudoku::Puzzle.new(ARGF.readlines))
#
module Sudoku
  #
  # Klasa Sudoku::Puzzle reprezentuje stan amigwki sudoku 9x9.
  #
  # Niektre definicje i terminy uywane w tej implementacji:
  #
  # - Kady element amigwki nazywany jest komrk.
  # - Numery wierszy i kolumn nale do przedziau od 0 do 8. Wsprzdne [0,0]
  #   odnosz si do komrki w lewym grnym rogu.
  # - Dziewi komrek 3x3 nazywa si blokami. Ich numery rwnie
  #   nale do przedziau od 0 do 8 w kolejnoci od lewej do prawej i z gry do dou.
  #   Blok w lewym grnym rogu ma numer 0. Blok w prawym grnym rogu ma numer 2.
  #   Blok znajdujcy si na rodku ma numer 4. Blok znajdujcy si w prawym dolnym
  #   rogu ma numer 8.
  #
  # Do tworzenia nowego sudoku suy metoda Sudoku::Puzzle.new. Naley okreli
  # stan pocztkowy za pomoc acucha lub tablicy acuchw. acuch ten (lub acuchy)
  # powinien zawiera znaki od 1 do 9 okrelajce wartoci i znak . dla pustych komrek.
  # Biae znaki s ignorowane.
  #
  # Zapis i odczyt poszczeglnych komrek odbywa si za porednictwem operatorw
  # [] i []=, ktre wymagaj indeksw dwuwymiarowych [wiersz, kolumna].
  # Metody te uywaj liczb (nie znakw) od 0 do 9 w komrkach.
  # 0 reprezentuje nieznan warto.
  #
  # Predykat has_duplicates? zwraca warto true, jeli amigwka jest nieprawidowa
  # ze wzgldu na dwukrotne wystpienie jakiej cyfry w ktrejkolwiek kolumnie albo
  # ktrymkolwiek wierszu lub bloku.
  #
  # Metoda each_unknown jest iteratorem przechodzcym przez komrki
  # i wywoujcym zwizany z nim blok dla kadej komrki, ktrej warto nie jest znana.
  #
  # Metoda possible zwraca tablic liczb cakowitych z przedziau 1...9.
  # Tylko elementy tej tablicy s dozwolonymi wartociami w okrelonej komrce.
  # Jeli tablica ta jest pusta, amigwka nie moe zosta rozwizana
  # Jeli tablica ta ma tylko jeden element, musi on by
  # wartoci tej komrki.
  #
  class Puzzle
    # Niniejsze stae su do translacji midzy zewntrzn reprezentacj
    # acuchw amigwki a reprezentacj wewntrzn.
    ASCII = ".123456789"
    BIN = "\000\001\002\003\004\005\006\007\010\011"
    # Metoda inicjujca klasy. Jest automatycznie wywoywana na rzecz
    # nowych egzemplarzy klasy Puzzle tworzonych za pomoc metody Puzzle.new.
    # Wejciowa amigwka jest przekazywana jako tablica wierszy lub pojedynczy acuch.
    # Mona uywa cyfr ASCII od 1 do 9. Znak . oznacza niewiadom komrk.
    # Biae znaki, wliczajc znaki nowego wiersza, s usuwane.
    def initialize(lines)
      if (lines.respond_to? :join)  # Jeli argument przypomina tablic wierszy,
        s = lines.join              # zostan one poczone w jeden acuch.
      else                          # W przeciwnym razie naley zaoy, e istnieje acuch,
        s = lines.dup               # i zrobi jego prywatn kopi.
      end
      # Biae znaki w danych musz zosta usunite.
      # Znak ! w nazwie metody gsub! oznacza, e jest to metoda mutacyjna, ktra
      # bezporednio modyfikuje acuch, zamiast robi jego kopi.
      s.gsub!(/\s/, "")  # /\s/ to wyraenie regularne, ktre pasuje do kadego biaego znaku.
      # Jeli dane wejciowe maj nieprawidowy rozmiar, zgaszany jest wyjtek.
      # Naley zauway, e uyto sowa unless w formie modyfikatora zamiast if.
      raise Invalid, "Nieprawidowy rozmiar siatki." unless s.size == 81
     
      # Szukanie nieprawidowych znakw i zapis lokalizacji pierwszego z nich.
      # Naley zauway, e przypisanie i sprawdzenie wartoci odbywa si jednoczenie.
      if i = s.index(/[^123456789\.]/)
        # Doczenie nieprawidowego znaku do komunikatu o bdzie.
        # Zauwa wyraenie w literale acuchowym #{}.
        raise Invalid, "Niedozwolony znak #{s[i,1]} "
      end
      # Ponisze dwa wiersze kodu konwertuj acuch znakw ASCII
      # na tablic liczb cakowitych za pomoc dwch metod String.
      # Powstaa w wyniku tego tablica zostaje zapisana w zmiennej obiektowej @grid.
      # Zero reprezentuje nieznan warto.
      s.tr!(ASCII, BIN)      # Translacja znakw ASCII na bajty.
      @grid = s.unpack('c*') # Wypakowanie bajtw do tablicy liczb.
      # Upewnienie si, e wiersze, kolumny i bloki nie zawieraj duplikatw.
      raise Invalid, "W amigwce wystpuj duplikaty" if has_duplicates?
    end
    # Zwr stan amigwki jako acuch dziewiciu wierszy z dziewicioma
    # znakami w kadym (plus znak nowego wiersza).
    def to_s
      # Niniejsza metoda zostaa zaimplementowana w jednym wierszu, ktry odwraca
      # dziaanie metody initialize(). Pisanie tak zagszczonego kodu raczej
      # nie naley do dobrego stylu programowania, ale demonstruje si
      # i ekspresj jzyka.
      #
      # Dziaanie tego kodu jest nastpujce:
      # (0..8).collect wywouje kod w klamrach 9 razy - po jednym dla
      # kadego wiersza - i zapisuje warto zwrotn tego kodu w tablicy.
      # Kod w klamrach pobiera podtablic siatki reprezentujc
      # pojedynczy wiersz i wstawia jego liczby do acucha.
      # Metoda join() czy elementy tablicy w pojedynczy acuch
      # ze znakami nowego wiersza midzy poszczeglnymi cyframi. Metoda
      # tr() dokonuje translacji binarnej reprezentacji acucha na cyfry ASCII.
      (0..8).collect{|r| @grid[r*9,9].pack('c9')}.join("\n").tr(BIN,ASCII)
    end
    # Zwrot duplikatu obiektu Puzzle.
    # Ta metoda przesania Object.dup i kopiuje tablic @grid.
    def dup
      copy = super       # Utworzenie pytkiej kopii za pomoc metody Object.dup.
      @grid = @grid.dup  # Utworzenie nowej kopii danych wewntrznych.
      copy               # Zwrcenie skopiowanego obiektu.
    end
    # Przeso operator dostpu do tablicy, aby umoliwi dostp do
    # poszczeglnych komrek. amigwki s dwuwymiarowe, a wic musz by
    # indeksowane wsprzdnymi wiersza i kolumny.
    def [](row, col)
      # Konwersja dwuwymiarowych wsprzdnych (row, col) na indeksy tablicy
      # jednowymiarowej oraz pobranie i zwrcenie wartoci w komrce o takim indeksie.
      @grid[row*9 + col]
    end
    # Niniejsza metoda pozwala na uycie operatora dostpu do tablicy po lewej
    # stronie operacji przypisania. Ustawia warto komrki o wsprzdnych
    # (row, col) na warto newvalue.
    def []=(row, col, newvalue)
      # Jeli nowa warto nie mieci si w przedziale 09, zgaszany jest wyjtek.
      unless (0..9).include? newvalue
        raise Invalid, "Nieprawidowa warto w komrce"
      end
      # Ustawienie odpowiedniego elementu wewntrznej tablicy na t warto.
      @grid[row*9 + col] = newvalue
    end
    # Ta tablica odwzorowuje jednowymiarowy indeks siatki na numer bloku.
    # Jest on uywany w poniszej metodzie. Nazwa BoxOfIndex zaczyna si od wielkiej litery,
    # a wic jest to staa. Ponadto tablica zostaa zamroona, przez co nie
    # mona jej modyfikowa.
    BoxOfIndex = [
      0,0,0,1,1,1,2,2,2,0,0,0,1,1,1,2,2,2,0,0,0,1,1,1,2,2,2,
      3,3,3,4,4,4,5,5,5,3,3,3,4,4,4,5,5,5,3,3,3,4,4,4,5,5,5,
      6,6,6,7,7,7,8,8,8,6,6,6,7,7,7,8,8,8,6,6,6,7,7,7,8,8,8
    ].freeze
    # Niniejsza metoda jest iteratorem amigwek sudoku.
    # Dla kadej komrki z nieznan wartoci metoda ta przekazuje
    #  numery wiersza, kolumny i bloku do bloku kodu
    # zwizanego z tym iteratorem.
    def each_unknown
      0.upto 8 do |row|             # Kady wiersz.
        0.upto 8 do |col|           # Kada kolumna.
          index = row*9+col         # Indeks komrki dla (row, col).
          next if @grid[index] != 0 # Kontynuuj, jeli znana jest warto komrki.
          box = BoxOfIndex[index]   # Sprawd blok tej komrki.
          yield row, col, box       # Wywoaj odpowiedni blok kodu.
        end
      end
    end
    # Zwraca warto true, jeli ktry wiersz, kolumna lub blok zawiera duplikaty.
    # W przeciwnym przypadku zwraca warto false. W sudoku w wierszu, kolumnie
    # ani bloku nie moe by duplikatw. Dlatego warto true oznacza z amigwk.
    def has_duplicates?
      # Metoda uniq! zwraca warto nil, jeli wszystkie elementy tablicy s unikatowe.
      # Jeli metoda uniq! zwraca jak warto, amigwka zawiera duplikaty.
      0.upto(8) {|row| return true if rowdigits(row).uniq! }
      0.upto(8) {|col| return true if coldigits(col).uniq! }
      0.upto(8) {|box| return true if boxdigits(box).uniq! }
     
      false  # Jeli wszystkie testy zakoczyy si powodzeniem, amigwka nie zawiera duplikatw.
    end
    # Ta tablica zawiera zestaw wszystkich cyfr sudoku. Jest uywana poniej.
    AllDigits = [1, 2, 3, 4, 5, 6, 7, 8, 9].freeze
    # Zwraca tablic wszystkich wartoci, ktre mog znale si w komrce
    # o wsprzdnych (row, col), nie duplikujc wartoci w wierszu, kolumnie i bloku.
    # Zauwa, e operator + w tablicach oznacza konkatenacj, natomiast operator -
    # wykonuje operacj rnicy zbiorw.
    def possible(row, col, box)
      AllDigits - (rowdigits(row) + coldigits(col) + boxdigits(box))
    end
    private  # Wszystkie metody za tym wierszem s prywatne dla klasy.
    # Zwraca tablic wszystkich znanych wartoci w okrelonym wierszu.
    def rowdigits(row)
      # Wydobywa podtablic reprezentujc ten wiersz i usuwa wszystkie zera.
      # Odejmowanie tablic jest operacj rnicy zbiorw z usuwaniem duplikatw.
      @grid[row*9,9] - [0]
    end
    # Zwraca tablic wszystkich znanych wartoci w okrelonej kolumnie.
    def coldigits(col)
      result = []                # Na pocztku jest pusta tablica.
      col.step(80, 9) {|i|       # Ptla zaczyna dziaanie od col w krokach co 9 do 80.
        v = @grid[i]             # Pobranie wartoci komrki pod tym indeksem.
        result << v if (v != 0)  # Jeli jest rna od 0, zostaje dodana do tablicy.
      }
      result                     # Zwrcenie tablicy.
    end
    # Odwzorowanie numeru bloku na indeks lewego grnego rogu tego bloku.
    BoxToIndex = [0, 3, 6, 27, 30, 33, 54, 57, 60].freeze
    # Zwraca tablic wszystkich znanych wartoci w okrelonym bloku.
    def boxdigits(b)
      # Konwersja numeru bloku na indeks lewego grnego rogu tego bloku.
      i = BoxToIndex[b]
      # Zwraca tablic wartoci z usuniciem zer.
      [
        @grid[i],    @grid[i+1],  @grid[i+2],
        @grid[i+9],  @grid[i+10], @grid[i+11],
        @grid[i+18], @grid[i+19], @grid[i+20]
      ] - [0]
    end
  end  # Koniec klasy Puzzle.
  # Wyjtek tej klasy oznacza nieprawidowe dane na wejciu.
  class Invalid < StandardError
  end
  # Wyjtek tej klasy oznacza, e ograniczenia s zbyt restrykcyjne, przez co nie ma
  # adnego rozwizania.
  class Impossible < StandardError
  end
  #
  # Niniejsza metoda skanuje amigwk w poszukiwaniu nieznanych komrek, ktre
  # mog przyj tylko jedn z wartoci. Jeli zostan takie znalezione, wstawia do nich wartoci.
  # Poniewa ustawienie wartoci w jednej komrce ma wpyw na moliwe wartoci w innych
  # komrkach, metoda ta kontynuuje skanowanie, a przeskanuje ca amigwk i nie
  # znajdzie adnej komrki, ktrej warto mona ustawi.
  #
  # Niniejsza metoda zwraca trzy wartoci. Jeli rozwie amigwk,
  # zwraca trzy razy nil. W przeciwnym przypadku dwie pierwsze wartoci okrelaj wiersz
  # i kolumn, ktrych komrka nie ma wartoci. Trzecia warto to zbir
  # wartoci, ktre mog znale si w tej kolumnie i tym wierszu. Jest to minimalny
  # zbir moliwych wartoci  nie ma nieznanej komrki w amigwce, ktra ma mniej
  # moliwych wartoci. Ta zoona warto zwrotna pozwala na przydatn heurystyk
  # w metodzie solve()  metoda ta moe zgadywa wartoci w komrkach, gdzie
  # jest najwiksze prawdopodobiestwo trafienia.
  #
  # Niniejsza metoda generuje wyjtek Impossible, jeli znajdzie komrk, dla ktrej
  # nie istnieje moliwa warto. Moe si to zdarzy, kiedy ograniczenia s zbyt surowe
  # lub jeli znajdujca si niej metoda solve() le zgada.
  #
  # Metoda ta modyfikuje okrelony obiekt Puzzle w miejscu.
  # Jeli has_duplicates? ma warto false na wejciu, bdzie mie warto false take na wyjciu.
  #
  def Sudoku.scan(puzzle)
    unchanged = false  # Zmienna ptlowa.
    # Powtarzanie dotd, dopki po przeskanowaniu caej planszy nie zostanie dokonana adna zmiana.
    until unchanged
      unchanged = true      # Zaoenie, e tym razem nie bdzie zmian.
      rmin,cmin,pmin = nil  # ledzenie komrki z minimalnym zbiorem moliwoci.
      min = 10              # Wicej ni maksymalna liczba moliwoci.
      # Iterowanie po komrkach, ktrych wartoci s nieznane.
      puzzle.each_unknown do |row, col, box|
        # Znalezienie zbioru wartoci, ktre mog by w tej komrce.
        p = puzzle.possible(row, col, box)
       
        # Rozgazienie na podstawie rozmiaru zbioru p.
        # Interesuj Ci trzy przypadki: p.size==0, p.size==1 i p.size > 1.
        case p.size
        when 0  # Brak moliwoci - zbyt surowe ograniczenia.
          raise Impossible
        when 1  # Unikatowa warto  wstawienie jej do siatki.
          puzzle[row,col] = p[0] # Ustawienie wartoci.
          unchanged = false      # Zaznaczenie, e dokonano zmiany.
        else    # Dla dowolnej innej liczby moliwoci.
          # ledzenie najmniejszego zbioru moliwoci.
          # Nie ma problemu, jeli ptla musi zosta powtrzona.
          if unchanged && p.size < min
            min = p.size                    # Aktualna najmniejsza warto size.
            rmin, cmin, pmin = row, col, p  # Przypisanie rwnolege.
          end
        end
      end
    end
     
    # Zwrot komrki z minimalnym zbiorem moliwoci.
    # Kilka wartoci zwrotnych.
    return rmin, cmin, pmin
  end
  # amigwka sudoku powinna by rozwizywana w miar moliwoci 
  # przy uyciu prostej logiki. Jeli zajdzie potrzeba, zostanie zastosowana metoda na si.
  # Polega ona na uyciu rekursji. Zwraca rozwizanie
  # albo zgasza wyjtek. Rozwizanie jest zwracane w postaci nowego obiektu
  # Puzzle bez nieznanych komrek. Metoda ta nie modyfikuje obiektu Puzzle,
  # ktry jest do niej przekazywany. Naley zauway, e metoda ta nie potrafi
  # wykry amigwek o zbyt mao surowych ograniczeniach.
  def Sudoku.solve(puzzle)
    # Tworzenie prywatnej kopii amigwki, ktr mona modyfikowa.
    puzzle = puzzle.dup
    # Wstaw tyle liczb, ile jest moliwe za pomoc logiki.
    # Ta metoda modyfikuje amigwk, ale zawsze pozostawia j nieuszkodzon.
    # Zwraca numer wiersza, kolumny i zbir moliwych wartoci w tej komrce.
    # Warto zauway przypisanie rwnolege tych wartoci zwrotnych do trzech zmiennych.
    r,c,p = scan(puzzle)
    # Jeli rozwizanie wyszo przy zastosowaniu logiki, zwr rozwizan amigwk.
    return puzzle if r == nil
   
    # W przeciwnym przypadku sprbuj wstawi kad z wartoci w p dla komrki [r, c].
    # Poniewa wartoci wybierane s ze zbioru moliwych wartoci, amigwka
    # pozostaje poprawna. Zgadywanie doprowadzi do rozwizania albo
    # do powstania amigwki niemoliwej do rozwizania. e amigwka nie ma
    # rozwizania, wiadomo, poniewa rekursywne wywoanie spowoduje wyjtek. Jeli tak
    # si stanie, naley zgadywa ponownie lub ponownie wygenerowa wyjtek, jeli
    # wyprbowae wszystkie dostpne opcje.
    p.each do |guess|        # Dla kadej wartoci w zbiorze moliwych wartoci.
      puzzle[r,c] = guess    # Zgadywanie wartoci.
     
      begin
        # Teraz sprbuj (rekursywnie) rozwiza zmodyfikowan amigwk.
        # To rekursywne wywoanie ponownie uruchomi metod scan() w celu prby rozwizania
        # zmodyfikowanej amigwki przy uyciu logiki.
        # W razie potrzeby nastpi kolejne prby zgadywania.
        # Pamitaj, e metoda solve() zwraca rozwizanie lub
        # generuje wyjtek.
        return solve(puzzle)  # Jeli zwraca warto, to jest ona rozwizaniem.
      rescue Impossible
        next                  # Jeli generuje wyjtek, naley kontynuowa zgadywanie.
      end
    end
    # Jeli dotare do tego miejsca, zgadywanie nic nie dao.
    # Jedna z wczeniej zgadywanych wartoci musiaa by za.
    raise Impossible
  end
end

