SVX日記

2004|04|05|06|07|08|09|10|11|12|
2005|01|02|03|04|05|06|07|08|09|10|11|12|
2006|01|02|03|04|05|06|07|08|09|10|11|12|
2007|01|02|03|04|05|06|07|08|09|10|11|12|
2008|01|02|03|04|05|06|07|08|09|10|11|12|
2009|01|02|03|04|05|06|07|08|09|10|11|12|
2010|01|02|03|04|05|06|07|08|09|10|11|12|
2011|01|02|03|04|05|06|07|08|09|10|11|12|
2012|01|02|03|04|05|06|07|08|09|10|11|12|
2013|01|02|03|04|05|06|07|08|09|10|11|12|
2014|01|02|03|04|05|06|07|08|09|10|11|12|
2015|01|02|03|04|05|06|07|08|09|10|11|12|
2016|01|02|03|04|05|06|07|08|09|10|11|12|
2017|01|02|03|04|05|06|07|08|09|10|11|12|
2018|01|02|03|04|05|06|07|08|09|10|11|12|
2019|01|02|03|04|05|06|07|08|09|10|11|12|
2020|01|02|03|04|05|06|07|08|09|10|11|12|
2021|01|02|03|04|05|06|07|08|09|10|11|12|
2022|01|02|03|04|05|06|07|08|09|10|11|12|
2023|01|02|03|04|05|06|07|08|09|10|11|12|
2024|01|02|03|04|

2023-05-23(Tue) 名状しがたいバックアップ方法を開発

  こういうことはないだろうか?

  ロールプレイングゲームなど、プレイ途中、数十〜数百回ものセーブを繰り返しながら進んでいくゲームがあるとして「直前の記録をいくつか残したい」と思ったことは?

  最近のゲームでは少ないだろうが、例えば、売ってしまってはいけないアイテムを売ってしまい、その状態でセーブしたら、その後ゲームを進められなくなってしまう、などという状況がある。しかし、そういう場合、セーブエリア1,2, 3を順に使っていれば回避できる可能性がある。直前のセーブデータより、もうふたつ古い世代のセーブデータから始められるからだ。これは簡単に実行できる。

  では、だいぶ前のイベントをもう一度見たくなった時のために「現在までの中間地点付近の記録をまばらに残したい」と思ったことは?

  これを「何となく、ではなく」実現するのは難しい。例えば10章まで進んだ時点で5章のデータを残しておくことはできるが、20章まで進んだ時点では10章付近のデータが残っているべきなのだ。セーブエリアの数に制限がなければ考える必要はないが、6個とかに限定されるとやりくりする必要が生じる。

  この問題は、ゲームのセーブデータに限らない。例えば、自分はヴォーカルの練習の記録を残してあるが、もう始めて5年くらいになるので、最近、記録容量が溢れそうになっている。後で成長の記録を確認したいと思えば、古いものや、2年半くらい前のものは残しておきたい。しかし、具体的にはどのように消していったらいいのか?

  そしてPCのバックアップである。例えば、6回分の保持が可能な容量があるとして、直近の6世代を残すのはいい方法なのだろうか? それだと、1週間前にオペレーションミスしたことに気づいたら、あきらめるほかない。直前と、もうふたつ古い世代は残しておくとしても、残りの3回分は、もう少し他にやりようがあるのではないか?

  つうわけで作ってみた。結論からいうと、完全に気に入った結果にはなっていないが、とりあえず「直前3世代+まばら3世代」での結果については、そこそこ使える動きになっていると思う。

  画像の説明

  動きを図化するとこんな感じだ。横軸がバックアップ世代、縦軸が時間の経過を意味している。概ねどの時間に着目しても、その時点の中間点と、中間点以降での中間点あたりの世代がまばらに残される動きになっている。フラクタル的にも見えるな。

  クラス化してあるので、以下のように使う。stored=で最新の世代数を渡し、should_delete?で既存の世代を削除するべきかどうか訊き、肯なら削除すればいい。

backups = {}; last_gen = -1
Dir.glob('xxx_backups/*').each {|path|
    gen = open('%s/.gen' % path).read.to_i
    backups[gen] = path
    gen > last_gen and last_gen = gen
}
 
ebackup = EspBackup.new
ebackup.stored = last_gen
backups.each {|gen, path|
    ebackup.should_delete?(gen) and p('rm -rf %s' % path)
}

  クラスの内容は以下。

class EspBackup
 
    def initialize(sgens = 3, lgens = sgens)
        @sgens = sgens; @lgens = lgens
        @bhs = []               # 3: [ '1110', '1100', '1000', '0100', '0110', '0111', '0000' ]
        sgens.times {|i0|
            i = sgens - i0      # sgens..1
            @bhs << ('1' * i + '0' * (i0 + 1))
        }
        sgens.times {|i0|
            i = i0 + 1          # 1..sgens
            @bhs << ('0' + '1' * i + '0' * (sgens - i))
        }
        @bhs << '0' * (sgens + 1)
    end
 
    def stored=(gen)
        @rgens = {}
        @lgens.times {
            @rgens[gen] = true
            (gen -= 1) < 0 and return
        }
        bw = ('%b' % gen).size
        @bhs.each {|bh|
            (it = (bh + '0' * bw)[0, bw].to_i(2)) <= gen and @rgens[it] = true
            @rgens.size == @sgens + @lgens and return
        }
    end
 
    def rgens
        @rgens.keys.sort
    end
 
    def should_delete?(gen)
        !@rgens[gen]
    end
end

  とりあえず、それなりの結果にはなっているので実用に供しようと思うが、完全に気に入った結果にはなっていないのだよな。特に保持数を上げると不自然な結果になってしまう。大きな考え方はいいと思うのだが、フラクタルがヒントなのかなぁ。