SVX日記
2023-05-23(Tue) 名状しがたいバックアップ方法を開発
最近のゲームでは少ないだろうが、例えば、売ってしまってはいけないアイテムを売ってしまい、その状態でセーブしたら、その後ゲームを進められなくなってしまう、などという状況がある。しかし、そういう場合、セーブエリア1,2, 3を順に使っていれば回避できる可能性がある。直前のセーブデータより、もうふたつ古い世代のセーブデータから始められるからだ。これは簡単に実行できる。
これを「何となく、ではなく」実現するのは難しい。例えば10章まで進んだ時点で5章のデータを残しておくことはできるが、20章まで進んだ時点では10章付近のデータが残っているべきなのだ。セーブエリアの数に制限がなければ考える必要はないが、6個とかに限定されるとやりくりする必要が生じる。
この問題は、ゲームのセーブデータに限らない。例えば、自分はヴォーカルの練習の記録を残してあるが、もう始めて5年くらいになるので、最近、記録容量が溢れそうになっている。後で成長の記録を確認したいと思えば、古いものや、2年半くらい前のものは残しておきたい。しかし、具体的にはどのように消していったらいいのか?
そしてPCのバックアップである。例えば、6回分の保持が可能な容量があるとして、直近の6世代を残すのはいい方法なのだろうか? それだと、1週間前にオペレーションミスしたことに気づいたら、あきらめるほかない。直前と、もうふたつ古い世代は残しておくとしても、残りの3回分は、もう少し他にやりようがあるのではないか?
動きを図化するとこんな感じだ。横軸がバックアップ世代、縦軸が時間の経過を意味している。概ねどの時間に着目しても、その時点の中間点と、中間点以降での中間点あたりの世代がまばらに残される動きになっている。フラクタル的にも見えるな。
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