読者です 読者をやめる 読者になる 読者になる

やってみた

アルゴリズム

makeplex salon:あなたのスキルで飯は食えるか? 史上最大のコーディングスキル判定 (1/2) - ITmedia エンタープライズ
3時間でできなければ優秀でないことが証明されてしまうことで一部で話題になっている問題をやってみた。
結果は...



“ほぼ確実に”優秀ではない!orz

とりあえずコード晒しとく。Rubyで書いたのにやけに長い。
真面目にアルゴリズムの勉強しないとだめだなぁ。

Kotsu = 1
Shuntsu = 2
Any = 3
class Array
    def Array.deepcopy(arr)
        Marshal.load(Marshal.dump(arr))
    end

    def top
        self[self.length - 1]
    end

    def car
        if self.length > 0
            self[0]
        else
            nil
        end
    end

    def cdr
        new_a = Array.deepcopy(self)
        new_a.shift
        new_a
    end

    def rest(i)
        new_a = Array.deepcopy(self)
        new_a.delete_at(i)
        new_a
    end
end

class Machi
    def initialize
        @machi = nil
        @atama = nil
        @triple = []
    end
    attr_accessor :machi, :atama, :triple

    def eql?(m)
        self.hash == m.hash
    end

    def hash
        str = @triple.sort.join
        str += @atama.join if @atama
        str += @machi.join if @machi
        str.hash
    end

    def print
        @triple.sort!
        @triple.each{|t|
            STDOUT.print "(#{t.join})"
        }
        STDOUT.print "(#{@atama.join})" if @atama && @atama.length > 0
        STDOUT.print "[#{@machi.join}]" if @machi
        STDOUT.print "\n"
    end

    def deepcopy
        new_machi = Machi.new
        new_machi.machi = Array.deepcopy(self.machi)
        new_machi.atama = Array.deepcopy(self.atama)
        new_machi.triple = Array.deepcopy(self.triple)
        new_machi
    end
end

def check_four_tiles(n)
    $four_tiles.each{|t| return true if t == n}
    return false
end

def search_same(temp, rest)
    return {} if temp.length == 0
    v = temp[0]
    for i in 0...rest.length
        if v == rest[i]
            return {v => rest.rest(i)}
        end
    end
    return {}
end

def search_forward_backword(temp, rest)
    return {} if temp.length == 0
    if temp.length == 2
        return {} if temp[1] - temp[0] != 1
    end
    forward = temp.first - 1
    backward = temp.last + 1
    result = {}
    for i in 0...rest.length
        if rest[i] == forward || rest[i] == backward
            if !result.key?(rest[i])
                result[rest[i]] = rest.rest(i)
            end
        end
    end
    return result
end

def search_aida_machi(temp, rest)
    return {} if temp.length != 1
    forward = temp.first - 2
    backward = temp.last + 2
    result = {}
    for i in 0...rest.length
        if rest[i] == forward || rest[i] == backward
            if !result.key?(rest[i])
                result[rest[i]] = rest.rest(i)
            end
        end
    end
    return result
end

def get_machi(shuntsu2)
    return [] if shuntsu2.length != 2
    case shuntsu2[1] - shuntsu2[0]
    when 1
        ret = []
        ret << shuntsu2[0] - 1 if shuntsu2[0] > 1
        ret << shuntsu2[1] + 1 if shuntsu2[1] < 9
        return ret
    when 2
        return [shuntsu2[1] - 1]
    else
        return []
    end
end

def search(type, rest, temp, result)
    if rest.length == 0 && temp.length == 0
        $final_result << result
        return
    end
    case type
    when Kotsu
        search_same(temp, rest).each{|num, new_rest|
            new_result = result.deepcopy
            new_result.triple << (temp + [num])
            search(Any, new_rest, [], new_result)
        }
    when Shuntsu
        search_forward_backword(temp, rest).each{|num, new_rest|
            new_result = result.deepcopy
            new_result.triple << (temp + [num]).sort
            search(Any, new_rest, [], new_result)
        }
    when Any
        if temp.length == 0
            search(Any, rest.cdr, temp + [rest.car], result.deepcopy)
            if !result.atama && !result.machi && !check_four_tiles(rest.car) #一個待ちパターン
                new_result = result.deepcopy
                new_result.machi = [rest.car]
                new_result.atama = []
                search(Any, rest.cdr, [], new_result)
            end
        elsif temp.length == 1
            search_same(temp, rest).each{|num, new_rest|
                search(Kotsu, new_rest, temp + [num], result.deepcopy)
                if !result.atama #頭パターン
                    new_result = result.deepcopy
                    new_result.atama = temp + [num]
                    search(Any, new_rest, [], new_result)
                end
                if !result.machi && !check_four_tiles(num) #刻子待ちパターン
                    new_result = result.deepcopy
                    new_result.machi = temp + [num]
                    search(Any, new_rest, [], new_result)
                end
            }
            search_forward_backword(temp, rest).each{|num, new_rest|
                search(Shuntsu, new_rest, (temp + [num]).sort, result.deepcopy)
                exist_machi = false
                get_machi((temp + [num]).sort) .map{|m| !check_four_tiles(m)} .each{|m| exist_machi |= m}
                if !result.machi && exist_machi #順子待ちパターン
                    new_result = result.deepcopy
                    new_result.machi = (temp + [num]).sort
                    search(Any, new_rest, [], new_result)
                end
            }
            if !result.machi
                search_aida_machi(temp, rest).each{|num, new_rest|
                    exist_machi = false
                    get_machi((temp + [num]).sort) .map{|m| !check_four_tiles(m)} .each{|m| exist_machi |= m}
                    if exist_machi
                        new_result = result.deepcopy
                        new_result.machi = (temp + [num]).sort
                        search(Any, new_rest, [], new_result)
                    end
                }
            end
        end
    end
end

def check_number_of_every_tile(tiles)
    arr = []
    ret = []
    arr.fill(0, 1..9)
    tiles.each{|t| arr[t.to_i] += 1}
    for i in 1..9
        ret << i if arr[i] == 4
    end
    ret
end

$final_result = []
$four_tiles = []
input = [
    "1112224588899",
    "1122335556799",
    "1112223335559",
    "1223344888999",
    "1112345678999",
    "1113335558888",
    "1222233456788",
    "1223567789789"
]

input.each{|i|
    $final_result.clear
    $four_tiles.clear
    puts i
    nums = i.split(//).map{|n| n.to_i}.sort
    $four_tiles = check_number_of_every_tile(nums)
    search(Any, nums, [], Machi.new)
    $final_result.uniq.each{|r| r.print}
    puts
}