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 +104 -113
- data/Rakefile +34 -14
- data/ext/sudoku.c +85 -9
- data/lib/sudoku.rb +33 -197
- data/lib/sudoku/generator.rb +40 -0
- data/lib/sudoku/grid.rb +14 -0
- data/lib/sudoku/logic.rb +242 -0
- data/lib/sudoku/solver.rb +176 -0
- data/lib/sudoku/version.rb +1 -1
- data/tests/test_sudoku.rb +144 -41
- metadata +35 -5
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
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
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
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
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
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
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
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
97
|
-
|
98
|
-
|
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
|
-
####
|
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
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
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
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
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
|
-
|
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
|
-
|
140
|
+
Sudoku.new(3).class # => MonSuperAdapteur
|
data/Rakefile
CHANGED
@@ -1,22 +1,30 @@
|
|
1
1
|
require 'rubygems'
|
2
2
|
require 'rake/gempackagetask'
|
3
|
-
|
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
|
9
|
-
s.version
|
10
|
-
s.platform
|
11
|
-
s.summary
|
12
|
-
s.description
|
13
|
-
s.author
|
14
|
-
s.email
|
15
|
-
s.files
|
16
|
-
s.homepage
|
17
|
-
s.extensions
|
18
|
-
s.license
|
19
|
-
s.test_files
|
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 :
|
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,
|
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
|
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
|
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
|
-
|
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
|
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
|
/* ############################################ */
|