sudokuhandler 0.1.2 → 0.1.3

Sign up to get free protection for your applications and to get access to all the features.
data/README.md CHANGED
@@ -7,143 +7,134 @@ Le Sudoku "classique" (9x9) est optimisé au maximum en temps et en mémoire (41
7
7
 
8
8
  ### Création d'un sudoku de 9x9 en diagonale
9
9
 
10
- $ irb -r sudoku
11
- ruby-1.9.2-p290 :000 > s = Sudoku.new 3
12
- => #<Sudoku::S3 9x9 0,0, ... , 0, 0>
13
- ruby-1.9.2-p290 :001 > s = Sudoku[3].new
14
- => #<Sudoku::S3 9x9 0,0, ... , 0, 0>
15
- ruby-1.9.2-p290 :002 > s.each{|x,y,v| s.set x, x, x+1 if x == y}
16
- => #<Sudoku::S3 9x9 1,0, ... , 0, 9>
17
- ruby-1.9.2-p290 :003 > puts s
10
+ $ irb -r sudoku
11
+ ruby-1.9.2-p290 :000 > s = Sudoku.new 3
12
+ => #<Sudoku::S3 9x9 0,0, ... , 0, 0>
13
+ ruby-1.9.2-p290 :001 > s = Sudoku[3].new
14
+ => #<Sudoku::S3 9x9 0,0, ... , 0, 0>
15
+ ruby-1.9.2-p290 :002 > s.each{|x,y,v| s.set x, x, x+1 if x == y}
16
+ => #<Sudoku::S3 9x9 1,0, ... , 0, 9>
17
+ ruby-1.9.2-p290 :003 > puts s
18
18
 
19
- 1 . . . . . . . .
20
- . 2 . . . . . . .
21
- . . 3 . . . . . .
22
-
23
- . . . 4 . . . . .
24
- . . . . 5 . . . .
25
- . . . . . 6 . . .
26
-
27
- . . . . . . 7 . .
28
- . . . . . . . 8 .
29
- . . . . . . . . 9
30
- => nil
19
+ 1 . . . . . . . .
20
+ . 2 . . . . . . .
21
+ . . 3 . . . . . .
22
+
23
+ . . . 4 . . . . .
24
+ . . . . 5 . . . .
25
+ . . . . . 6 . . .
26
+
27
+ . . . . . . 7 . .
28
+ . . . . . . . 8 .
29
+ . . . . . . . . 9
30
+ => nil
31
31
 
32
32
  ###Exportation du sudoku
33
33
 
34
- ruby-1.9.2-p290 :004 > s.to_sutxt
35
- => "3: 1 0 0 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 0 0 7 0 0 0 0 0 0 0 0 0 8 0 0 0 0 0 0 0 0 0 9;"
36
- ruby-1.9.2-p290 :005 > s2 = Sudoku.parse s.to_sutxt
37
- => #<Sudoku::S3 9x9 1,0, ... , 0, 9>
34
+ ruby-1.9.2-p290 :004 > s.to_sutxt
35
+ => "3: 1 0 0 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 0 0 7 0 0 0 0 0 0 0 0 0 8 0 0 0 0 0 0 0 0 0 9;"
36
+ ruby-1.9.2-p290 :005 > s2 = Sudoku.parse s.to_sutxt
37
+ => #<Sudoku::S3 9x9 1,0, ... , 0, 9>
38
38
 
39
39
  ### Un peu de logique
40
40
 
41
- ruby-1.9.2-p290 :006 > s.possibilities 0, 1
42
- => [4, 5, 6, 7, 8, 9]
43
- ruby-1.9.2-p290 :007 > s.valid? 1, 0, 3
44
- => false
45
- ruby-1.9.2-p290 :008 > s.valid? 1, 0, 5
46
- => true
47
- ruby-1.9.2-p290 :009 > s.col 2
48
- => [3]
49
- ruby-1.9.2-p290 :010 > s.row 3
50
- => [4]
51
- ruby-1.9.2-p290 :011 > s.square 3,3
52
- => [4, 5, 6]
41
+ ruby-1.9.2-p290 :006 > s.possibilities 0, 1
42
+ => [4, 5, 6, 7, 8, 9]
43
+ ruby-1.9.2-p290 :007 > s.valid? 1, 0, 3
44
+ => false
45
+ ruby-1.9.2-p290 :008 > s.valid? 1, 0, 5
46
+ => true
47
+ ruby-1.9.2-p290 :009 > s.col 2
48
+ => [3]
49
+ ruby-1.9.2-p290 :010 > s.row 3
50
+ => [4]
51
+ ruby-1.9.2-p290 :011 > s.square 3,3
52
+ => [4, 5, 6]
53
53
 
54
54
  ### Generateur
55
55
 
56
- class MySudoku < Sudoku::S4_15
57
- include Sudoku::Generator
58
- end
59
-
60
- s = MySudoku.new 5
61
- s.make_valid
62
- puts s
63
-
64
- =begin =>>
65
- 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
66
- 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 1 2 3 4 5
67
- 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 1 2 3 4 5 6 7 8 9 10
68
- 16 17 18 19 20 21 22 23 24 25 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
69
- 21 22 23 24 25 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
70
-
71
- 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 1
72
- 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 1 2 3 4 5 6
73
- 12 13 14 15 16 17 18 19 20 21 22 23 24 25 1 2 3 4 5 6 7 8 9 10 11
74
- 17 18 19 20 21 22 23 24 25 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
75
- 22 23 24 25 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
56
+ Sudoku.new(5).make_valid
76
57
 
77
- 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 1 2
78
- 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 1 2 3 4 5 6 7
79
- 13 14 15 16 17 18 19 20 21 22 23 24 25 1 2 3 4 5 6 7 8 9 10 11 12
80
- 18 19 20 21 22 23 24 25 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
81
- 23 24 25 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
58
+ donne (par exemple)
82
59
 
83
- 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 1 2 3
84
- 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 1 2 3 4 5 6 7 8
85
- 14 15 16 17 18 19 20 21 22 23 24 25 1 2 3 4 5 6 7 8 9 10 11 12 13
86
- 19 20 21 22 23 24 25 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
87
- 24 25 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
88
-
89
- 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 1 2 3 4
90
- 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 1 2 3 4 5 6 7 8 9
91
- 15 16 17 18 19 20 21 22 23 24 25 1 2 3 4 5 6 7 8 9 10 11 12 13 14
92
- 20 21 22 23 24 25 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
93
- 25 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
94
- =end
95
60
 
96
- s.valid? # => true
97
- s.complete? # => true
98
- s.completable? # => true
61
+ 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
62
+ 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 1 2 3 4 5
63
+ 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 1 2 3 4 5 6 7 8 9 10
64
+ 16 17 18 19 20 21 22 23 24 25 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
65
+ 21 22 23 24 25 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
66
+
67
+ 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 1
68
+ 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 1 2 3 4 5 6
69
+ 12 13 14 15 16 17 18 19 20 21 22 23 24 25 1 2 3 4 5 6 7 8 9 10 11
70
+ 17 18 19 20 21 22 23 24 25 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
71
+ 22 23 24 25 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
72
+
73
+ 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 1 2
74
+ 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 1 2 3 4 5 6 7
75
+ 13 14 15 16 17 18 19 20 21 22 23 24 25 1 2 3 4 5 6 7 8 9 10 11 12
76
+ 18 19 20 21 22 23 24 25 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
77
+ 23 24 25 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
78
+
79
+ 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 1 2 3
80
+ 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 1 2 3 4 5 6 7 8
81
+ 14 15 16 17 18 19 20 21 22 23 24 25 1 2 3 4 5 6 7 8 9 10 11 12 13
82
+ 19 20 21 22 23 24 25 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
83
+ 24 25 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
84
+
85
+ 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 1 2 3 4
86
+ 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 1 2 3 4 5 6 7 8 9
87
+ 15 16 17 18 19 20 21 22 23 24 25 1 2 3 4 5 6 7 8 9 10 11 12 13 14
88
+ 20 21 22 23 24 25 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
89
+ 25 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
99
90
 
100
91
  ### Utiliser son propre adapteur
101
92
 
102
- #### Un adapteur doit au moins définir les méthodes suivantes:
93
+ #### Interface minimale d'un adapteur
103
94
 
104
- * get(x, y)
105
- * set(x, y, val)
106
- * each(){|x, y, val| ... }
107
- * size()
108
- * initialize(base)
95
+ * get(x, y) => Fixnum
96
+ * set(x, y, val) => Fixnum
97
+ * each(){|x, y, val| ... } => self
98
+ * size() => Fixnum
99
+ * initialize(base) => self
109
100
  * initialize_copy(parent) (automatique si on n'utilise que des objets ruby)
110
101
 
111
102
  #### Exemple:
112
103
 
113
104
  NB: cet exemple ne tient pas compte de la gestion des erreurs
114
105
 
115
- class MonSuperAdapteur
116
- attr_reader :size
117
-
118
- include Sudoku::Generator #methodes de generation automatique
119
- include Sudoku::Grid #methodes communes a tous les sudokus
120
-
121
- def initialize base
122
- @size = base*base
123
- @data = Array.new(@size*@size){0}
124
- end
125
-
126
- def get x, y
127
- @data[x+y*size]
128
- end
129
-
130
- def set x, y, val
131
- @data[x+y*size] = val
132
- end
133
-
134
- def each
135
- @data.each_with_index do |val, i|
136
- yield i%size, i/size, val
137
- end
138
- self
139
- end
106
+ class MonSuperAdapteur
107
+ attr_reader :size
108
+
109
+ include Sudoku::Generator #methodes de generation automatique
110
+ include Sudoku::Grid #methodes communes a tous les sudokus
111
+
112
+ def initialize base
113
+ @size = base*base
114
+ @data = Array.new(@size*@size){0}
115
+ end
116
+
117
+ def get x, y
118
+ @data[x+y*size]
119
+ end
120
+
121
+ def set x, y, val
122
+ @data[x+y*size] = val
140
123
  end
141
124
 
142
- Sudoku[4..7] = MonSuperAdapteur #Tous les sudokus de base 4 à 7 créés automatiquement
143
- #seront des MonSuperAdapteur
144
- Sudoku.new(3).class # => Sudoku::S3
145
- Sudoku.new(4).class # => MonSuperAdapteur
125
+ def each
126
+ @data.each_with_index do |val, i|
127
+ yield i%size, i/size, val
128
+ end
129
+ self
130
+ end
131
+ end
146
132
 
147
- Sudoku[0] = MonSuperAdapteur #Tous les sudokus, par defaut
133
+ Sudoku[4..7] = MonSuperAdapteur #Tous les sudokus de base 4 à 7 créés automatiquement
134
+ #seront des MonSuperAdapteur
135
+ Sudoku.new(3).class # => Sudoku::S3
136
+ Sudoku.new(4).class # => MonSuperAdapteur
137
+
138
+ Sudoku[0] = MonSuperAdapteur #Tous les sudokus, par defaut
148
139
 
149
- Sudoku.new(3).class # => MonSuperAdapteur
140
+ Sudoku.new(3).class # => MonSuperAdapteur
data/Rakefile CHANGED
@@ -1,22 +1,30 @@
1
1
  require 'rubygems'
2
2
  require 'rake/gempackagetask'
3
- require 'rake/extensiontask'
3
+ begin
4
+ require 'rake/extensiontask'
5
+ rescue LoadError => e
6
+ sh "gem install rake-compiler"
7
+ exec %{rake "#{ARGV*'" "'}"}
8
+ end
4
9
  require 'rake/testtask.rb'
5
10
  require './lib/sudoku/version'
6
11
 
7
12
  spec = Gem::Specification.new do |s|
8
- s.name = 'sudokuhandler'
9
- s.version = Sudoku::VERSION
10
- s.platform = Gem::Platform::RUBY
11
- s.summary = "Ruby Sudoku handler"
12
- s.description = "Highly optimised Sudoku objects and mixins for Ruby"
13
- s.author = "Titouan Christophe"
14
- s.email = 'titouanchristophe@gmail.com'
15
- s.files = FileList["lib/*.rb", "lib/sudoku/*.rb", "ext/sudoku.c", "Rakefile", "README.md"]
16
- s.homepage = 'http://github.com/titouanc/rb-sudoku'
17
- s.extensions << 'ext/extconf.rb'
18
- s.license = 'Creative Commons BY-NC-SA 3.0'
19
- s.test_files = FileList["tests/*"]
13
+ s.name = 'sudokuhandler'
14
+ s.version = Sudoku::VERSION
15
+ s.platform = Gem::Platform::RUBY
16
+ s.summary = "Ruby Sudoku handler"
17
+ s.description = "Highly optimised Sudoku objects and mixins for Ruby"
18
+ s.author = "Titouan Christophe"
19
+ s.email = 'titouanchristophe@gmail.com'
20
+ s.files = FileList["lib/*.rb", "lib/sudoku/*.rb", "ext/sudoku.c", "Rakefile", "README.md"]
21
+ s.homepage = 'http://github.com/titouanc/rb-sudoku'
22
+ s.extensions << 'ext/extconf.rb'
23
+ s.license = 'Creative Commons BY-NC-SA 3.0'
24
+ s.test_files = FileList["tests/*"]
25
+ s.rdoc_options += ['--title', 'Sudoku for Ruby', '--main', 'README']
26
+ s.add_development_dependency 'rake-compiler'
27
+ s.add_development_dependency 'yard'
20
28
  end
21
29
 
22
30
  Rake::GemPackageTask.new(spec) do |pkg|
@@ -34,6 +42,16 @@ Rake::TestTask.new do |t|
34
42
  t.verbose = true
35
43
  end
36
44
 
45
+ begin
46
+ require 'yard'
47
+ YARD::Rake::YardocTask.new do |t|
48
+ t.files = FileList["lib/sudoku.rb", "lib/sudoku/*.rb"]
49
+ t.options = ['--readme', 'README.md', '--charset', 'UTF-8']
50
+ end
51
+ rescue LoadError => e
52
+ puts "No doc task (YARD required)"
53
+ end
54
+
37
55
  desc "Build gem & install"
38
56
  task :install => FileList["pkg/#{spec.full_name}.gem"] do |t|
39
57
  sh "gem install #{t.prerequisites.first}"
@@ -54,4 +72,6 @@ task :console => :compile do |t|
54
72
  sh "irb -I ./lib -r sudoku"
55
73
  end
56
74
 
57
- task :default => [:clobber, :repackage, :compile, :test]
75
+ task :doc => :yard
76
+
77
+ task :default => [:clobber, :repackage, :compile, :test, :yard]
data/ext/sudoku.c CHANGED
@@ -74,13 +74,17 @@ static VALUE S4_15_initCopy(VALUE copy, VALUE orig){
74
74
  S4_15 *this, *parent;
75
75
  int len;
76
76
 
77
+ if (copy == orig)
78
+ return copy;
79
+
77
80
  Data_Get_Struct(copy, S4_15, this);
78
81
  Data_Get_Struct(orig, S4_15, parent);
79
82
 
80
83
  this->size = parent->size;
84
+ len = this->size * this->size;
81
85
 
82
86
  S4_15_alloc_data(this);
83
- memcpy(this->ptr, parent->ptr, parent->size*sizeof(char));
87
+ memcpy(this->ptr, parent->ptr, len*sizeof(char));
84
88
 
85
89
  return copy;
86
90
  }
@@ -94,7 +98,7 @@ static VALUE S4_15_get(VALUE self, VALUE col, VALUE row){
94
98
  if (x<0 || x>=this->size || y<0 || y>=this->size)
95
99
  rb_raise(rb_eArgError, "Are you sure thre's a %d,%d cell in a %dx%d Sudoku ?", x, y, this->size, this->size);
96
100
 
97
- return INT2NUM(this->ptr[x+y*this->size]);
101
+ return INT2FIX(this->ptr[x+y*this->size]);
98
102
  }
99
103
 
100
104
  static VALUE S4_15_set(VALUE self, VALUE col, VALUE row, VALUE value){
@@ -150,6 +154,9 @@ static void Init_S4_15(VALUE module){
150
154
 
151
155
  /* ############################################ */
152
156
 
157
+ #define S3_offset(x, y) ((size_t) (x)+((y)*9))
158
+ #define S3_valAtOffset(ptr, i) (((i)%2 == 0) ? (((ptr)[(i)/2] >> 4) & 0x0f) : ((ptr)[(i)/2] & 0x0f))
159
+
153
160
  static void S3_dealloc(void *ptr){
154
161
  free(ptr);
155
162
  }
@@ -179,6 +186,9 @@ static VALUE S3_initCopy(VALUE copy, VALUE orig){
179
186
  unsigned char *this, *parent;
180
187
  char i;
181
188
 
189
+ if (copy == orig)
190
+ return copy;
191
+
182
192
  Data_Get_Struct(copy, unsigned char, this);
183
193
  Data_Get_Struct(orig, unsigned char, parent);
184
194
  if (this == parent)
@@ -190,7 +200,7 @@ static VALUE S3_initCopy(VALUE copy, VALUE orig){
190
200
  }
191
201
 
192
202
  static VALUE S3_get(VALUE self, VALUE col, VALUE row){
193
- unsigned char *this, x, y, i;
203
+ unsigned char *this, x, y;
194
204
 
195
205
  Data_Get_Struct(self, unsigned char, this);
196
206
  x = NUM2UINT(col)&0xff;
@@ -199,11 +209,7 @@ static VALUE S3_get(VALUE self, VALUE col, VALUE row){
199
209
  if (x>=9 || y>=9)
200
210
  rb_raise(rb_eArgError, "Are you sure thre's a %d,%d cell in a 9x9 Sudoku ?", x, y);
201
211
 
202
- i = x + y*9;
203
- if (i%2 == 0)
204
- return INT2FIX((this[i/2] >> 4) & 0x0f);
205
- else
206
- return INT2FIX(this[i/2] & 0x0f);
212
+ return INT2FIX(S3_valAtOffset(this, S3_offset(x, y)));
207
213
  }
208
214
 
209
215
  static VALUE S3_set(VALUE self, VALUE col, VALUE row, VALUE value){
@@ -218,7 +224,7 @@ static VALUE S3_set(VALUE self, VALUE col, VALUE row, VALUE value){
218
224
  if (x>=9 || y>=9 || val > 9)
219
225
  rb_raise(rb_eArgError, "%d,%d => %d not allowed in a 9x9 Sudoku", x, y, val);
220
226
 
221
- i = x + y*9;
227
+ i = S3_offset(x, y);
222
228
  if (i%2 == 0)
223
229
  this[i/2] = (this[i/2]&0x0f) | (val<<4);
224
230
  else
@@ -248,6 +254,48 @@ static VALUE S3_each(VALUE self){
248
254
  return self;
249
255
  }
250
256
 
257
+ static VALUE S3_column(VALUE self, VALUE col){
258
+ unsigned char x = NUM2UINT(col)&0xff, y, val;
259
+ unsigned char i = x;
260
+ VALUE res;
261
+ unsigned char *this;
262
+
263
+ if (x>=9)
264
+ rb_raise(rb_eArgError, "Are you sure thre's a %d column in a 9x9 Sudoku ?", x);
265
+
266
+ Data_Get_Struct(self, unsigned char, this);
267
+ res = rb_ary_new();
268
+ for (y=0; y<9; y++){
269
+ val = S3_valAtOffset(this, i);
270
+ if (val != 0)
271
+ rb_ary_push(res, INT2FIX(val));
272
+ i += 9;
273
+ }
274
+
275
+ return res;
276
+ }
277
+
278
+ static VALUE S3_line(VALUE self, VALUE row){
279
+ unsigned char y = NUM2UINT(row)&0xff, x, val;
280
+ unsigned char i = 9*y;
281
+ VALUE res;
282
+ unsigned char *this;
283
+
284
+ if (y>=9)
285
+ rb_raise(rb_eArgError, "Are you sure thre's a %d row in a 9x9 Sudoku ?", y);
286
+
287
+ Data_Get_Struct(self, unsigned char, this);
288
+ res = rb_ary_new();
289
+ for (x=0; x<9; x++){
290
+ val = S3_valAtOffset(this, i);
291
+ if (val != 0)
292
+ rb_ary_push(res, INT2FIX(val));
293
+ i ++;
294
+ }
295
+
296
+ return res;
297
+ }
298
+
251
299
  static VALUE S3_isComplete(VALUE self){
252
300
  char i, val;
253
301
  unsigned char *this;
@@ -260,6 +308,31 @@ static VALUE S3_isComplete(VALUE self){
260
308
  return Qtrue;
261
309
  }
262
310
 
311
+ static VALUE S3_isValidCell(VALUE self, VALUE col, VALUE row, VALUE val){
312
+ unsigned char x = NUM2UINT(col)&0xff, xx;
313
+ unsigned char y = NUM2UINT(row)&0xff, yy;
314
+ unsigned char v = NUM2UINT(val)&0xff;
315
+ unsigned char i;
316
+ unsigned char *this;
317
+
318
+ if (x>=9 || y>=9 || v>9)
319
+ rb_raise(rb_eArgError, "%d,%d => %d not allowed in a 9x9 Sudoku", x, y, v);
320
+
321
+ if (v==0)
322
+ return Qtrue;
323
+
324
+ Data_Get_Struct(self, unsigned char, this);
325
+ for (i=0; i<9; i++){
326
+ if (S3_valAtOffset(this, S3_offset(x, i)) == v && i != y) return Qfalse;
327
+ if (S3_valAtOffset(this, S3_offset(i, y)) == v && i != x) return Qfalse;
328
+ xx = 3*(x/3) + (i%3);
329
+ yy = 3*(y/3) + (i/3);
330
+ if (S3_valAtOffset(this, S3_offset(xx, yy))==v && xx!=x && yy!=y) return Qfalse;
331
+ }
332
+
333
+ return Qtrue;
334
+ }
335
+
263
336
  static VALUE S3_dump(VALUE self){
264
337
  char string[83] = {'\0'};
265
338
  int i;
@@ -283,8 +356,11 @@ static void Init_S3(VALUE module){
283
356
  rb_define_method(class_S3, "get", S3_get, 2);
284
357
  rb_define_method(class_S3, "set", S3_set, 3);
285
358
  rb_define_method(class_S3, "each", S3_each, 0);
359
+ rb_define_method(class_S3, "col", S3_column, 1);
360
+ rb_define_method(class_S3, "row", S3_line, 1);
286
361
  rb_define_method(class_S3, "complete?", S3_isComplete, 0);
287
362
  rb_define_method(class_S3, "dump", S3_dump, 0);
363
+ rb_define_method(class_S3, "valid_cell?", S3_isValidCell, 3);
288
364
  }
289
365
 
290
366
  /* ############################################ */