Lisp ライクで immutable (書き換え不可) な連結リスト (imlist.rb) です。Ruby で immutable な連結リストを使う必要性はあまりないと思いますが、Ruby のお勉強ということで作ってみました。実用性はほとんどありませんが、興味のある方はいろいろ試してみてください。
irb> load "imlist.rb" => true irb> a = ImList.create(1, ImList.null) => (1) irb> b = ImList.create(2, a) => (2 1) irb> c = ImList.create(3, b) => (3 2 1) irb> ImList.list(1,2,3,4,5) => (1 2 3 4 5) irb> ImList.list(*[1,2,3,4,5]) => (1 2 3 4 5) irb> ImList.fill(10, 0) => (0 0 0 0 0 0 0 0 0 0) irb> ImList.iota(1, 10) => (1 2 3 4 5 6 7 8 9 10) irb> ImList.iterate(10, 1){|x| x + 2} => (1 3 5 7 9 11 13 15 17 19) irb> ImList.tabulate(10){|x| x * x} => (0 1 4 9 16 25 36 49 64 81)
irb> a = ImList.null.cons(1).cons(2).cons(3) => (3 2 1) irb> a.first => 3 irb> a.rest => (2 1) irb> a.rest.rest.first => 1 irb> a.rest.rest.null? => false irb> a.rest.rest.rest.null? => true irb> b = ImList.iota(1, 10) => (1 2 3 4 5 6 7 8 9 10) irb> b.get(0) => 1 irb> b.get(9) => 10 irb> b[1] => 2 irb> b[8] => 9 irb> b.last => 10 irb> a.length => 3 irb> b.length => 10 irb> a.reverse => (1 2 3) irb> b.reverse => (10 9 8 7 6 5 4 3 2 1) irb> a.append(b) => (3 2 1 1 2 3 4 5 6 7 8 9 10) irb> a + b => (3 2 1 1 2 3 4 5 6 7 8 9 10) irb> a * 10 => (3 2 1 3 2 1 3 2 1 3 2 1 3 2 1 3 2 1 3 2 1 3 2 1 3 2 1 3 2 1) irb> b.take(5) => (1 2 3 4 5) irb> b.drop(5) => (6 7 8 9 10) irb> c = ImList.iota(11, 20) => (11 12 13 14 15 16 17 18 19 20) irb> b.zip(c) => ((1 11) (2 12) (3 13) (4 14) (5 15) (6 16) (7 17) (8 18) (9 19) (10 20))
irb> a = ImList.iota(1,8) => (1 2 3 4 5 6 7 8) irb> a.map{|x| x * x} => (1 4 9 16 25 36 49 64) irb> a.flat_map{|x| ImList.fill(x, x)} => (1 2 2 3 3 3 4 4 4 4 5 5 5 5 5 6 6 6 6 6 6 7 7 7 7 7 7 7 8 8 8 8 8 8 8 8) irb> b = ImList.iota(11, 18) => (11 12 13 14 15 16 17 18) irb> a.zip_with(b){|x, y| x + y} => (12 14 16 18 20 22 24 26) irb> a.zip_with(b){|x, y| x + y} => (12 14 16 18 20 22 24 26) irb> a.filter{|x| x.even?} => (2 4 6 8) irb> a.reduce(0){|x, y| x + y} => 36 irb> a.reduce_right(0){|x, y| x + y} => 36 irb> a.reduce(ImList.null){|x, y| x.cons(y)} => (8 7 6 5 4 3 2 1) irb> a.reduce_right(ImList.null){|x, y| y.cons(x)} => (1 2 3 4 5 6 7 8) irb> a.each{|x| puts x} 1 2 3 4 5 6 7 8 => (1 2 3 4 5 6 7 8) irb> a.each_with_index{|x, i| print x, " ", i, "\n"} 1 0 2 1 3 2 4 3 5 4 6 5 7 6 8 7 => (1 2 3 4 5 6 7 8) irb> ImList.list(2,4,6,8,10).all?(&:even?) => true irb> ImList.list(2,4,6,8,11).all?(&:even?) => false irb> ImList.list(2,4,6,8,10).any?(&:odd?) => false irb> ImList.list(2,4,6,8,11).any?(&:odd?) => true irb> a.take_while{|x| x < 6} => (1 2 3 4 5) irb> a.drop_while{|x| x < 6} => (6 7 8)
irb> a = ImList.iota(1, 8) => (1 2 3 4 5 6 7 8) irb> a.member?(1) => (1 2 3 4 5 6 7 8) irb> a.member?(5) => (5 6 7 8) irb> a.member?(8) => (8) irb> a.member?(9) => () irb> a.include?(1) => true irb> a.include?(8) => true irb> a.include?(9) => false irb> a.find{|x| x > 5} => 6 irb> a.find{|x| x > 8} => false irb> a.find_index{|x| x > 5} => 5 irb> a.find_index{|x| x > 8} => false irb> b = ImList.list(1,1,2,1,2,3,1,2,3,4) => (1 1 2 1 2 3 1 2 3 4) irb> b.count{|x| x == 1} => 4 irb> b.count{|x| x == 4} => 1 irb> b.count{|x| x == 5} => 0
# coding: utf-8 # # imlist.rb : immutable な連結リスト # # Copyright (C) 2017-2023 Makoto Hiroi # # エラー class ImListError < StandardError end # 連結リスト class ImList def initialize(item, link) @item = item @link = link end def set_link(link) @link = link end protected :set_link # 終端 Null = ImList.new(nil, nil) private_class_method :new def self.create(item, link) raise TypeError if !link.instance_of?(ImList) new(item, link) end def self.null Null end # 基本的な関数 def cons(x) ImList.create(x, self) end def first raise ImListError, "Empty List" if null? @item end def rest raise ImListError, "Empty List" if null? @link end def null? self == Null end # 表示 def to_s s = "(" xs = self while !xs.null? s += xs.first.to_s s += " " if !xs.rest.null? xs = xs.rest end s += ")" end def inspect to_s end # 配列に変換 def to_a xs = self ys = [] while !xs.null? ys.push xs.first xs = xs.rest end ys end # 生成 def self.list(*args) xs = Null args.reverse_each{|x| xs = xs.cons(x)} xs end def self.fill(n, x) xs = Null n.times { xs = xs.cons(x) } xs end def self.iota(n, m) list(*(n .. m).to_a) end def self.iterate(n, a, &func) xs = [] n.times { xs.push(a) a = func.call(a) } list(*xs) end def self.tabulate(n, &func) xs = Null (n - 1).downto(0) {|x| xs = xs.cons(func.call(x)) } xs end # # リスト操作関数 # def get(n) xs = self n.times { xs = xs.rest } xs.first end def [](n) get(n) end def last xs = self while !xs.rest.null? xs = xs.rest end xs.first end def length xs = self n = 0 while !xs.null? n += 1 xs = xs.rest end n end def reverse xs = self ys = Null while !xs.null? ys = ys.cons(xs.first) xs = xs.rest end ys end def reverse! xs = self ys = Null while !xs.null? zs = xs.rest() xs.set_link(ys) ys = xs xs = zs end ys end protected :reverse! def append(ys) return ys if null? xs = self zs = Null while !xs.null? zs = zs.cons(xs.first) xs = xs.rest end xs = zs.reverse! zs.set_link(ys) xs end def +(other) raise TypeError if !other.instance_of?(ImList) append(other) end def *(n) xs = Null n.times { xs = self.append(xs) } xs end def take(n) xs = self ys = Null while n > 0 && !xs.null? ys = ys.cons(xs.first) xs = xs.rest n -= 1 end ys.reverse! end def drop(n) xs = self while n > 0 && !xs.null? xs = xs.rest n -= 1 end xs end def zip(ys) xs = self zs = Null while !xs.null? && !ys.null? zs = zs.cons(ImList.list(xs.first, ys.first)) xs = xs.rest ys = ys.rest end zs.reverse! end # # 高階関数 # def map(&func) xs = self ys = Null while !xs.null? ys = ys.cons(func.call(xs.first)) xs = xs.rest end ys.reverse! end def flat_map(&func) xs = self ys = Null zs = Null while !xs.null? ys = ys.cons(func.call(xs.first)) xs = xs.rest end while !ys.null? zs = ys.first.append(zs) ys = ys.rest end zs end def zip_with(ys, &func) xs = self zs = Null while !xs.null? && !ys.null? zs = zs.cons(func.call(xs.first, ys.first)) xs = xs.rest ys = ys.rest end zs.reverse! end def filter(&pred) xs = self ys = Null while !xs.null? ys = ys.cons(xs.first) if pred.call(xs.first) xs = xs.rest end ys.reverse! end def reduce(a, &func) xs = self while !xs.null? a = func.call(a, xs.first) xs = xs.rest end a end def reduce_right(a, &func) xs = reverse while !xs.null? a = func.call(xs.first, a) xs = xs.rest end a end def each(&func) xs = self while !xs.null? func.call(xs.first) xs = xs.rest end self end def each_with_index(&func) xs = self i = 0 while !xs.null? func.call(xs.first, i) xs = xs.rest i += 1 end self end def all?(&pred) each{|x| return false if !pred.call(x)} true end def any?(&pred) each{|x| return true if pred.call(x)} false end def take_while(&func) xs = self ys = Null while !xs.null? && func.call(xs.first) ys = ys.cons(xs.first) xs = xs.rest end ys.reverse! end def drop_while(&func) xs = self while !xs.null? && func.call(xs.first) xs = xs.rest end xs end # # 線形探索 # def member?(x) xs = self while !xs.null? return xs if xs.first == x xs = xs.rest end Null end def include?(x) xs = self while !xs.null? return true if xs.first == x xs = xs.rest end false end def find(&pred) each{|x| return x if pred.call(x)} false end def find_index(&pred) each_with_index{|x, i| return i if pred.call(x) } false end def count(&pred) reduce(0){|c, x| pred.call(x) ? c + 1 : c} end end
immutable な連結リストを使った簡単な問題集です。
リスト : 「リストで遊ぼう」の解答 load "imlist.rb" # Q01 総和, 最大値, 最小値 def sum(xs) xs.reduce(0){|m, x| m + x} end def maximum(xs) xs.rest.reduce(xs.first){|m, x| m < x ? x : m} end def minimum(xs) xs.rest.reduce(xs.first){|m, x| m > x ? x : m} end puts "----- Q01 -----" a = ImList.list(5, 6, 4, 7, 3, 8, 2, 9, 1, 10) puts a puts sum(a) puts maximum(a) puts minimum(a) # Q02 FizzBuzz def change(x) return "FizzBuzz" if x % 15 == 0 return "Fizz" if x % 3 == 0 return "Buzz" if x % 5 == 0 x.to_s end puts "----- Q02 -----" puts ImList.iota(1, 100).map{|x| change(x)} # Q03 def butlast(xs, n) xs.reverse.drop(n).reverse end puts "----- Q03 -----" q03 = ImList.iota(1, 8) puts q03 puts butlast(q03, 1) puts butlast(q03, 4) puts butlast(q03, 8) # Q04 def group(xs, n) if xs.null? ImList.null else group(xs.drop(n), n).cons(xs.take(n)) end end puts "----- Q04 -----" q04 = ImList.iota(1, 10) puts q04 puts group(q04, 2) puts group(q04, 3) puts group(q04, 4) puts group(q04, 5) # Q05 def sublist(xs, n, m) xs.drop(n).take(m - n) end puts "----- Q05 -----" q05 = ImList.iota(1, 10) puts q05 puts sublist(q05, 0, 1) puts sublist(q05, 2, 8) puts sublist(q05, 3, 10) # Q06 リストの分割 def partition(xs, &pred) if xs.null? return ImList.null, ImList.null else a, b = partition(xs.rest, &pred) if pred.call(xs.first) return a.cons(xs.first), b else return a, b.cons(xs.first) end end end puts "----- Q06 -----" q06 = ImList.iota(1, 10) puts partition(q06, &:even?) puts partition(q06, &:odd?) # Q07 クイックソート def quick_sort(xs) if xs.null? ImList.null else a, b = partition(xs.rest){|x| x < xs.first} quick_sort(a).append(quick_sort(b).cons(xs.first)) end end puts "----- Q07 -----" puts quick_sort(ImList.list(5,6,4,7,3,8,2,9,1,0)) puts quick_sort(ImList.iota(0, 9)) puts quick_sort(ImList.iota(0, 9).reverse) # Q08 マージ def merge_list(xs, ys) if xs.null? ys elsif ys.null? xs else if xs.first <= ys.first merge_list(xs.rest, ys).cons(xs.first) else merge_list(xs, ys.rest).cons(ys.first) end end end puts "----- Q08 -----" q081 = ImList.list(0,2,4,6,8,10) q082 = ImList.list(1,3,5,7,9) puts q081 puts q082 puts merge_list(q081, q082) puts merge_list(q082, q081) # Q09 マージソート def merge_sort(xs, n) if n == 1 ImList.list(xs.first) else m = n / 2 merge_list(merge_sort(xs, m), merge_sort(xs.drop(m), n - m)) end end puts "----- Q09 -----" puts merge_sort(ImList.list(5,6,4,7,3,8,2,9,1,0), 10) puts merge_sort(ImList.iota(0, 9), 10) puts merge_sort(ImList.iota(0, 9).reverse, 10) # Q10 def permutation(n, xs) if n == 0 ImList.list(ImList.null) else xs.flat_map{|x| permutation(n - 1, xs.filter{|y| x != y}).map{|zs| zs.cons(x)}} end end puts "----- Q10 -----" puts permutation(2, ImList.list(1,2,3,4)) puts permutation(4, ImList.list(1,2,3,4)) # Q11 def combination(n, xs) if n == 0 ImList.list(ImList.null) elsif xs.null? ImList.null else combination(n - 1, xs.rest).map{|ys| ys.cons(xs.first)}.append(combination(n, xs.rest)) end end puts "----- Q11 -----" puts combination(2, ImList.iota(1, 5)) puts combination(3, ImList.iota(1, 5)) puts combination(4, ImList.iota(1, 5)) # Q12 def distinct(xs) xs.reduce_right(ImList.null) {|x, ys| ys.include?(x) ? ys : ys.cons(x)} #ys = ImList.null #xs.each{|x| ys = ys.cons(x) if !ys.include?(x)} #ys.reverse end puts "----- Q12 -----" puts distinct(ImList.list(1,1,2,1,2,3,1,2,3,4,1,2,3,4,5)) # Q13 def union(xs, ys) if xs.null? ys elsif ys.include?(xs.first) union(xs.rest, ys) else union(xs.rest, ys).cons(xs.first) end end def intersection(xs, ys) if xs.null? ImList.null elsif ys.include?(xs.first) intersection(xs.rest, ys).cons(xs.first) else intersection(xs.rest, ys) end end def difference(xs, ys) if xs.null? ImList.null elsif ys.include?(xs.first) difference(xs.rest, ys) else difference(xs.rest, ys).cons(xs.first) end end puts "----- Q13 -----" q13a = ImList.list(1,2,3,4,5,6) q13b = ImList.list(1,3,5,7,9,11) puts q13a puts q13b puts union(q13a, q13b) puts intersection(q13a, q13b) puts difference(q13a, q13b) # Q14 def subset?(xs, ys) xs.all?{|x| ys.include?(x)} end puts "----- Q14 -----" puts subset?(ImList.list(1,2,3,4), ImList.iota(1, 5)) puts subset?(ImList.list(1,2,3,4,5), ImList.iota(1, 5)) puts subset?(ImList.list(1,2,3,4,6), ImList.iota(1, 5)) # Q15 def power_set(xs) if xs.null? ImList.list(ImList.null) else ys = power_set(xs.rest) ys.append(ys.map{|zs| zs.cons(xs.first)}) end end puts "----- Q15 -----" puts power_set(ImList.iota(1, 3)) puts power_set(ImList.iota(1, 4)) # Q16 def rev_append(xs, ys) xs.reduce(ys){|zs, x| zs.cons(x)} end def sieve(n) xs = ImList.iota(2, n) ps = ImList.null while xs.first * xs.first <= n ps = ps.cons(xs.first) xs = xs.rest.filter{|x| x % xs.first != 0} end rev_append(ps, xs) end puts "----- Q16 -----" puts sieve(100) puts sieve(500) # Q17 (mastermind) def count_bulls(xs, ys) xs.zip_with(ys){|x, y| x == y}.count(&:itself) end def count_same_number(xs, ys) xs.reduce(0){|a, x| ys.include?(x) ? a + 1 : a} end class Query def initialize(code, bulls, cows) @code = code @bulls = bulls @cows = cows end attr_reader :code, :bulls, :cows end def check_query(qs, code) qs.each{|q| b = count_bulls(q.code, code) c = count_same_number(q.code, code) - b return false if b != q.bulls || c != q.cows } true end def mastermind(answer) perms = permutation(4, ImList.iota(0, 9)) query = ImList.null perms.each{|code| if check_query(query, code) b = count_bulls(code, answer) c = count_same_number(code, answer) - b query = query.cons(Query.new(code, b, c)) printf("%d: %s, bulls = %d, cows = %d\n", query.length, code, b, c) if b == 4 puts "Good Job!!" return end end } end puts "----- Q17 -----" mastermind(ImList.list(9,8,7,6)) mastermind(ImList.list(9,4,3,1))
----- Q01 ----- (5 6 4 7 3 8 2 9 1 10) 55 10 1 ----- Q02 ----- (1 2 Fizz 4 Buzz Fizz 7 8 Fizz Buzz 11 Fizz 13 14 FizzBuzz 16 17 Fizz 19 Buzz Fizz 22 23 Fizz Buzz 26 Fizz 28 29 FizzBuzz 31 32 Fizz 34 Buzz Fizz 37 38 Fizz Buzz 41 Fizz 43 44 FizzBuzz 46 47 Fizz 49 Buzz Fizz 52 53 Fizz Buzz 56 Fizz 58 59 FizzBuzz 61 62 Fizz 64 Buzz Fizz 67 68 Fizz Buzz 71 Fizz 73 74 FizzBuzz 76 77 Fizz 79 Buzz Fizz 82 83 Fizz Buzz 86 Fizz 88 89 FizzBuzz 91 92 Fizz 94 Buzz Fizz 97 98 Fizz Buzz) ----- Q03 ----- (1 2 3 4 5 6 7 8) (1 2 3 4 5 6 7) (1 2 3 4) () ----- Q04 ----- (1 2 3 4 5 6 7 8 9 10) ((1 2) (3 4) (5 6) (7 8) (9 10)) ((1 2 3) (4 5 6) (7 8 9) (10)) ((1 2 3 4) (5 6 7 8) (9 10)) ((1 2 3 4 5) (6 7 8 9 10)) ----- Q05 ----- (1 2 3 4 5 6 7 8 9 10) (1) (3 4 5 6 7 8) (4 5 6 7 8 9 10) ----- Q06 ----- (2 4 6 8 10) (1 3 5 7 9) (1 3 5 7 9) (2 4 6 8 10) ----- Q07 ----- (0 1 2 3 4 5 6 7 8 9) (0 1 2 3 4 5 6 7 8 9) (0 1 2 3 4 5 6 7 8 9) ----- Q08 ----- (0 2 4 6 8 10) (1 3 5 7 9) (0 1 2 3 4 5 6 7 8 9 10) (0 1 2 3 4 5 6 7 8 9 10) ----- Q09 ----- (0 1 2 3 4 5 6 7 8 9) (0 1 2 3 4 5 6 7 8 9) (0 1 2 3 4 5 6 7 8 9) ----- Q10 ----- ((1 2) (1 3) (1 4) (2 1) (2 3) (2 4) (3 1) (3 2) (3 4) (4 1) (4 2) (4 3)) ((1 2 3 4) (1 2 4 3) (1 3 2 4) (1 3 4 2) (1 4 2 3) (1 4 3 2) (2 1 3 4) (2 1 4 3) (2 3 1 4) (2 3 4 1) (2 4 1 3) (2 4 3 1) (3 1 2 4) (3 1 4 2) (3 2 1 4) (3 2 4 1) (3 4 1 2) (3 4 2 1) (4 1 2 3) (4 1 3 2) (4 2 1 3) (4 2 3 1) (4 3 1 2) (4 3 2 1)) ----- Q11 ----- ((1 2) (1 3) (1 4) (1 5) (2 3) (2 4) (2 5) (3 4) (3 5) (4 5)) ((1 2 3) (1 2 4) (1 2 5) (1 3 4) (1 3 5) (1 4 5) (2 3 4) (2 3 5) (2 4 5) (3 4 5)) ((1 2 3 4) (1 2 3 5) (1 2 4 5) (1 3 4 5) (2 3 4 5)) ----- Q12 ----- (1 2 3 4 5) ----- Q13 ----- (1 2 3 4 5 6) (1 3 5 7 9 11) (2 4 6 1 3 5 7 9 11) (1 3 5) (2 4 6) ----- Q14 ----- true true false ----- Q15 ----- (() (3) (2) (2 3) (1) (1 3) (1 2) (1 2 3)) (() (4) (3) (3 4) (2) (2 4) (2 3) (2 3 4) (1) (1 4) (1 3) (1 3 4) (1 2) (1 2 4) (1 2 3) (1 2 3 4)) ----- Q16 ----- (2 3 5 7 11 13 17 19 23 29 31 37 41 43 47 53 59 61 67 71 73 79 83 89 97) (2 3 5 7 11 13 17 19 23 29 31 37 41 43 47 53 59 61 67 71 73 79 83 89 97 101 103 107 109 113 127 131 137 139 149 151 157 163 167 173 179 181 191 193 197 199 211 223 227 229 233 239 241 251 257 263 269 271 277 281 283 293 307 311 313 317 331 337 347 349 353 359 367 373 379 383 389 397 401 409 419 421 431 433 439 443 449 457 461 463 467 479 487 491 499) ----- Q17 ----- 1: (0 1 2 3), bulls = 0, cows = 0 2: (4 5 6 7), bulls = 0, cows = 2 3: (5 4 8 9), bulls = 0, cows = 2 4: (6 7 9 8), bulls = 0, cows = 4 5: (8 9 7 6), bulls = 2, cows = 2 6: (9 8 7 6), bulls = 4, cows = 0 Good Job!! 1: (0 1 2 3), bulls = 0, cows = 2 2: (1 0 4 5), bulls = 0, cows = 2 3: (2 3 5 4), bulls = 0, cows = 2 4: (3 4 0 6), bulls = 1, cows = 1 5: (3 5 6 1), bulls = 1, cows = 1 6: (6 5 0 2), bulls = 0, cows = 0 7: (7 4 3 1), bulls = 3, cows = 0 8: (8 4 3 1), bulls = 3, cows = 0 9: (9 4 3 1), bulls = 4, cows = 0 Good Job!!
マスターマインドは、0 から 9 までの重複しない 4 つの数字からなる隠しコードを当てるゲームです。数字は合っているが位置が間違っている個数を cows で表し、数字も位置も合っている個数を bulls で表します。bulls が 4 になると正解です。
(6 2 8 1) : 正解 --------------------------------- 1. (0 1 2 3) : cows 2 : bulls 0 2. (1 0 4 5) : cows 1 : bulls 0 3. (2 3 5 6) : cows 2 : bulls 0 4. (3 2 7 4) : cows 0 : bulls 1 5. (3 6 0 8) : cows 2 : bulls 0 6. (6 2 8 1) : cows 0 : bulls 4 図 : マスターマインドの動作例
今回は、私達が出した問題をコンピュータに答えてもらうことにします。それはちょっと難しいのではないか、と思った人もいるかもしれませんね。ところが、とても簡単な方法があるのです。このゲームでは、10 個の数字の中から 4 個選ぶわけですから、全体では 10 * 9 * 8 * 7 = 5040 通りのコードしかありません。コードを生成する処理は順列と同じですから、簡単にプログラムできます。
次に、この中から正解を見つける方法ですが、質問したコードとその結果を覚えておいて、それと矛盾しないコードを作るようにします。具体的には、4 つの数字の順列を生成し、それが今まで質問したコードと矛盾しないことを確かめます。これは生成検定法と同じですね。
矛盾しているかチェックする方法も簡単で、以前に質問したコードと比較して、bulls と cows が等しいときは矛盾していません。たとえば、下図の例を考えてみてください。
(0 1 2 3) で bulls が 0 ですから、その位置にその数字は当てはまりません。したがって、(0 X X X) というコードは (0 1 2 3) と比較すると bulls が 1 となるので、矛盾していることがわかります。
次に (1 0 3 4) というコードを考えてみます。(0 1 2 3) の結果は cows が 2 ですから、その中で合っている数字は 2 つしかないわけです。ところが、(1 0 3 4) と (0 1 2 3) と比較すると cows が 3 になります。当たっている数字が 2 つしかないのに、同じ数字を 3 つ使うのでは矛盾していることになりますね。
次に (1 0 4 5) というコードと比較すると、bulls が 0 で cows が 2 となります。これは矛盾していないので、このコードを質問することにします。その結果が bulls = 0, cows = 1 となり、今度は (0 1 2 3) と (1 0 4 5) に矛盾しないコードを選択すればいいわけです。
(6 2 8 1) が正解の場合 (0 1 2 3) => bulls = 0, cows = 2 (0 1 2 3) と比較する -------------------------------------------------------- (0 X X X) 0 から始まるコードは bulls = 1 になるので矛盾する。 ・・・・ (1 0 3 4) cows = 3, bulls = 0 になるので矛盾する ・・・・ (1 0 4 5) cows = 2, bulls = 0 で矛盾しない。 -------------------------------------------------------- (1 0 4 5) => bulls = 0, cows = 1 次は、(0 1 2 3) と (1 0 4 5) に矛盾しない数字を選ぶ 図 : マスターマインドの推測アルゴリズム