文字列の八方向検索
Posted feedbacks - Ruby
普通のやり方ですか。
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 26 27 28 | TEXT=<<-EOS
リオウウリウ
ウオリウオリ
オリリオリウ
リリオオウオ
EOS
WORD="ウオリ"
M_TEXT=TEXT.split("\n").map{|e| e.split(//)}
A_WORD=WORD.split(//)
S_DEST=[
["上",-1,0],["右上",-1,1],["右",0,1],["右下",1,1],
["下",1,0],["左下",1,-1],["左",0,-1],["左上",-1,-1]
]
M_TEXT.each_with_index do |line,y|
line.each_with_index do |c,x|
next unless c==A_WORD[0]
S_DEST.each do |desc,dy,dx|
unless (1...A_WORD.size).find do |i|
((y+dy*i<0)||M_TEXT[y+dy*i].nil?)||
(x+dx*i<0)||(M_TEXT[y+dy*i][x+dx*i]!=A_WORD[i])
end
puts "#{desc}(#{x},#{y})"
end
end
end
end
|
配列回転させて8個作る方式。
アフィン変換させようかと思ったけど面倒そうだから斜めだけ作ればいいや、
と思ってやったらこれはこれで面倒でした。汚いし。
4方向で似たようなのがたしかanarchy golfゴルフにありましたね。
実行例:
[["左", [[2, 0]]],["右", [[0, 1], [3, 1]]],["下", [0, 1]]],["左上", [[4, 3]]]]
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 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 | #!ruby -Ku
require 'pp'
def slant(x,y)
a = []
until (x < 0 || y < 0)
a << [x,y]
x-=1; y-=1
end
a
end
def slant_array(a)
ret = []
size_x = a[0].size
size_y = a.size
size_x.times{|i|
ret << slant(i, size_y-1).map{|x,y| a[y][x]}
}
size_y.times{|i|
ret << slant(size_x-1, i).map{|x,y| a[y][x]}
}
ret.uniq
end
def reverse_x(a)
a.map{|line| line.reverse}
end
def rotate_array(migi)
hidari = reverse_x(migi)
sita = migi.transpose
ue = reverse_x(sita)
hidari_ue = slant_array(migi)
migi_ue = slant_array(hidari)
hidari_sita = reverse_x(migi_ue)
migi_sita = reverse_x(hidari_ue)
a = [
["左", hidari],
["右", migi],
["上", ue],
["下", sita],
["左上", hidari_ue],
["左下", hidari_sita],
["右上", migi_ue],
["右下", migi_sita]
]
end
def match_pos(str_ary, tar_ary, a)
ret = []
a.each{|e|
line = e.map{|x,y| str_ary[y][x]}
line.size.times{|i|
ret << e[i] if line[i,tar_ary.size] == tar_ary
}
}
ret
end
def dk99(str, tar)
str_ary = str.split(/\n/).map{|e| e.split(//)}
tar_ary = tar.split(//)
migi = []
str_ary.size.times{|y|
str_ary[0].size.times{|x|
(migi[y] ||= []) << [x,y]
}
}
rotate_array(migi).map{|vec, ary|
ret = match_pos(str_ary, tar_ary, ary)
[vec, ret] unless ret.empty?
}.compact
end
s =
"リオウウリウ
ウオリウオリ
オリリオリウ
リリオオウオ"
pp dk99(s, "ウオリ")
|
汎用化を狙いました。 ”ウリリ”とするとエラーになりますが暫定版としてアップします。 連続する文字列をベクトルと考え、1行読むごとにベクトルが成長したら出力しています。 例:ウオ=移動量1のベクトル、リオウ=移動量2のベクトル
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 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 | def dir8(f)
ch = Hash[*(w = f[1].split(//)).zip((0..vmax = w.length-1).to_a).flatten]
hrz, vrt = {1=>"右", 0=>"", -1=>"左"}, {1=>"下", 0=>"", -1=>"上"}
va = [] #--- vector array
row = -1
open(f[0]) {|fin|
while (line = fin.gets) != "\n"
row += 1
line = line[0..-2].split(//).map {|i|ch[i]}
(0...line.size).each {|col|
item = [col, row, line[col]]
(0...va.size).each {|i|
va[i] = nextVector(va[i], [vmax, hrz, vrt]) if va[i][0..2] === item
}
-1.upto(1){|ic| #--- make vector around
-1.upto(1){|ir|
dv = (ir > 0 || ic + ir > 0 ? 1 : -1)
va << [col + ic * dv, row + ir * dv, line[col] + dv, ic, ir, 0, dv]
}
}
}
va = va.select {|i|i if (i[1] > row) || (i[0]+i[1] > 0)}
end
}
end
def nextVector(a, par)
x, y, val, vx, vy, len, dv = a
vmax, hrz, vrt = par
if (len += 1) == vmax
hosei = (dv == -1 ? 0 : -1) * vmax
p [x + vx * hosei, y + vy * hosei, hrz[vx] + vrt[vy]]
end
[x + vx * dv, y + vy * dv, val + dv, vx, vy, len, dv]
end
if $FILE != $0
dir8(ARGV)
end
#ruby -Ku dir8.rb dir8.in "ウオリ"
|



kuromin #4400() Rating0/2=0.00
[ reply ]