From: Wolfgang Seeberg <wolfgang.seeberg@yahoo.com>
Date: April 17, 2007 11:53:11 AM CDT
To: submission@rubyquiz.com
Subject: Please Forward: Ruby Quiz Submission# Usage: ruby -s q120.rb [-maxfinger=7] [-depth=50]
# works for maxfinger<=9.
# finds a forced loss for maxfinger=4 at "1111".
# uses complete retroanalysis, i.e. one can in principle
# play "as good as God" (K. Thompson) with its output.
class Finger
Maxscore = 99999
Thresh = (0.9 * Maxscore).to_idef initialize(mf = nil, d = nil)
@maxfinger = (mf || 4).to_i
@depth = (d || 30).to_i
@movehash = {}
@scorehash = {}
enddef main()
scanall()
condense()
@depth.times do
findbadnews()
findgoodnews()
end
showresults()
enddef showresults()
puts <<EOSThe two leftmost digits always belong to the player who is to make
a move. The "Moves" columns show the resulting positions after
that player has moved. All positions are "normalized", i.e. the
left hand has never more fingers up than the right hand.EOS
printf "Pos. Score Moves\n"
list = @scorehash.sort
list.each do | k, v |
if (v == @movehash[k])
printf "%04d %s ", k, "=" * 6
else
printf "%04d %6d ", k, v
end
@movehash[k].each do |item|
printf " %04d", item
end
printf "\n"
end
enddef d1(x, n)
if x < 100
s = sprintf("%02d", x)
else
s = sprintf("%04d", x)
end
return s[n - 1, 1].to_i
enddef left(x)
return x / 100
enddef right(x)
return x % 100
enddef n2(x)
if (d1(x, 2) < d1(x, 1))
return 10 * d1(x, 2) + d1(x, 1)
else
return x
end
end# in many places the code requires normalized positions.
def normalize(x)
return n2(left(x)) * 100 + n2(right(x))
enddef add(a, b)
if (a <= 0 || b <= 0)
return nil
elsif (a + b > @maxfinger)
return 0
else
return a + b
end
enddef pushadd(x, i, j, k, hash, list)
a = add(d1(x, i), d1(x, j))
return list if a == nil
mv = normalize(a * 1000 + 100 * d1(x, k) + left(x))
if (!(hash.has_key? mv))
hash[mv] = 1
list << mv
end
return list
end# allowed: 11->02
# forbidden: 12->21
def clap(a, b, n)
if (a + n <= @maxfinger && b >= n)
r = n2(10 * (a + n) + b - n)
if r != (10 * a + b) then
return r
end
end
return nil
enddef pushclap(normalpos, n, hash, list)
c = clap(d1(normalpos, 1), d1(normalpos, 2), n)
return list if c == nil
mv = right(normalpos) * 100 + c
if (mv != right(normalpos) * 100 && !(hash.has_key? mv))
list << mv
hash[mv] = 1
end
return list
enddef moves(normalpos)
list =
hash = {}
list = pushadd(normalpos, 1, 3, 4, hash, list)
list = pushadd(normalpos, 2, 3, 4, hash, list)
list = pushadd(normalpos, 1, 4, 3, hash, list)
list = pushadd(normalpos, 2, 4, 3, hash, list)
for i in 1 ..@maxfinger - 1
list = pushclap(normalpos, i, hash, list)
end
return list
enddef scan1(x)
normalpos = normalize(x)
m = moves(normalpos)
if (m.size > 0)
@movehash[normalpos] = m * 1
@scorehash[normalpos] = m * 1
end
enddef scanall()
for i in 1 .. @maxfinger
for j in 0 ..i
for k in 1 .. @maxfinger
for m in 0 .. k
scan1(i * 1000 + j * 100 + k * 10 + m)
end
end
end
end
enddef condense()
@scorehash.each_key do | i |
list = @scorehash[i]
list.each do | item |
if item < 100
@scorehash[i] = Maxscore
break
end
end
end
enddef findbadnews()
@scorehash.each_key do | i |
list = @scorehash[i]
if list.class.to_s != 'Array'
list = [list * 1]
end
m = Maxscore + 1
list.each do | ak |
if (ak > Thresh)
m = 0
break
elsif ((@scorehash.has_key? ak) &&
@scorehash[ak].class.to_s == "Fixnum" &&
@scorehash[ak] > Thresh)
m = [m, @scorehash[ak]].min()
else
m = 0
break
end
end
# all moves lead to winning positions for the opponent.
if (m > 0)
@scorehash[i] = -m + 1
end
end
enddef findgoodnews()
@scorehash.each_key do | i |
list = @scorehash[i]
if list.class.to_s != 'Array'
next
end
m = Maxscore + 1
list.each do | ak |
# a definite loss for the opponent.
if ((@scorehash.has_key? ak) &&
@scorehash[ak].class.to_s == "Fixnum" &&
@scorehash[ak] < -Thresh.to_i)
m = [m, @scorehash[ak]].min()
end
end
if (m < 0)
@scorehash[i] = -m - 1
end
end
end
end # class FingerFinger.new($maxfinger, $depth).main()
#-------------------- End ---------------------------
__________________________________________________
Do You Yahoo!?
Tired of spam? Yahoo! Mail has the best spam protection around
http://mail.yahoo.com
···
Begin forwarded message: