sudokuhandler 0.1.2 → 0.1.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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
  /* ############################################ */