ロマンシング サガ2 リベンジオブザセブン

ロマサガ2のリメイク

しかも、HD2Dではなくまさかのフル3D。

スーパーファミコン時代のゲームのリメイクはHD2Dが鉄板になってきていて、ドラクエ3のリメイクもHD2Dだから、ロマサガ2がリメイクされるとしたらHD2Dだろうな、と予想していたのに。

良い意味で予想が外れた。

細かなところまで親切設計

まずナビが親切過ぎる。普通にストーリーを進めるだけなら迷うことがない。

酒場でパーティーメンバー入れ替えることができるし、パーティーからメンバーを外すこともできる。

新システムのアビリティ

職業固有のアビリティは、極意化したら他のキャラにも装備できるので、組み合わせを考えるのが楽しい。ちょっとしたデッキビルド感覚。

自分はBP回復系が重宝した。終盤では連携に関係するアビリティが役立った。キックバックとか。

職業では忍者が最強

体術と大剣が得意で、最終皇帝並みの火力が出せる。イーストガードも大剣技を次々に閃いてくれる。

ロマサガ2は進め方自由なので、序盤から仲間にすることもできる。この自由さが最高。

リメイクでは七英雄によりフォーカス

なにせリベンジオブザセブンなので。七英雄に過去に何があったのか明かされた。古代人の自業自得で、七英雄には同情の余地ある。

ただ、七英雄は古代人に復讐する目的忘れてそう。ノエルとロックブーケの兄妹だけは、古代人の足跡を調査してるみたいだったけど。古代人を追って異次元に行こうとしていたのだろうか。

閃きシステムは健在

戦闘中、閃く可能性があるときは豆電球マークが表示される。そのキャラが閃くことができる技もメニューで確認できる。おかげで、光速剣や無明剣、千手観音といったオリジナルをプレイした当時に閃けなかった技を閃くことができた。

戦闘システムはガラリと変わった

行動順に変わり、弱点と連携が追加された。弱点を突いて高いダメージを与えたり、うまく相手をスタンにして一方的にボコったり、連携で大ダメージを与えたりと、戦略性が増した。

戦闘に勝つ回数が増えると敵が強くなるのは変わらない。たた、逃げたり全滅した場合は強くならないのが救い。詰まずに済む。

大剣が強いけど、体術がもっと強い

千手観音最強。大剣は鍛冶屋でクロスクレイモア作ったら最後まで活躍できる。

スタンが効く敵には切り落とし、ボス戦ではかめごうら割りで防御率下げたり、流し斬りで腕力下げたり。

合成術も強い

クリムゾンフレアとか。天と火の合成術が重宝した。あと、エリクサーやレストレーションといった回復系。オリジナルをプレイしたときは脳筋で、物理で殴るばっかりだったから、術、とりわけ合成術を使うとかなり有利に進められることにリメイクで気付けた。

最高のリメイク

キャラや敵、フィールドが 3D になってもなんら違和感なかった。むしろ、思い出補正を超えてきた。今までプレイしたリメイクの中でも最高な出来では。

オリジナルのロマサガ2は理不尽さがあって、それはそれで魅力ではあったけど、今作は万人にオススメできる作品だった。

B12 - Equation

atcoder.jp

1 ≦ N ≦ 100000 で、x * x * x + x = N になる x を探すわけだから、x が 100 未満なのは確実。

var N = int.Parse(Console.ReadLine()!);

var left = 0.0;
var right = 100.0;
while ((right - left) >= 0.001)
{
    var x = (left + right) / 2.0;
    var a = f(x);
    if (a <= N)
    {
        left = x;
    }
    else
    {
        right = x;
    }
}

Console.WriteLine(left);

double f(double x) => x * x * x + x;

A12 - Printer

atcoder.jp

1 ≦ Ai ≦ 10,000,000,000 なので、A1 = 1, A2 = 2, ... Ai = i になる、か?一応正解したけど腑に落ちていない。

var NK = Console.ReadLine()!.Split(" ").Select(x => long.Parse(x)).ToList();
var N = NK[0];
var K = NK[1];
var A = Console.ReadLine()!.Split(" ").Select(x => long.Parse(x)).ToList();

var leftSecond = 1L;
var rightSecond = 10_000_000_000L;
while (leftSecond < rightSecond)
{
    var middleSecond = (leftSecond + rightSecond) / 2;
    if (Check(middleSecond))
    {
        rightSecond = middleSecond;
    }
    else
    {
        leftSecond = middleSecond + 1;
    }
}

Console.WriteLine(rightSecond);

bool Check(long second)
{
    var sum = A.Sum(a => second / a);
    return sum >= K;
}

B11 - Binary Search 2

atcoder.jp

LowerBound が標準ライブラリには見当たらなかったので自前実装。

var N = int.Parse(Console.ReadLine()!);
var A = Console.ReadLine()!.Split(" ").Select(int.Parse).ToList();
var Q = int.Parse(Console.ReadLine()!);
var X = new List<int>();
for (var i = 0; i < Q; i++)
{
    X.Add(int.Parse(Console.ReadLine()!));
}

var sortedA = A.Order().ToList();
for (var i = 0; i < Q; i++)
{
    var idx = LowerBound(sortedA, X[i]);
    Console.WriteLine(idx);
}

static int LowerBound(IReadOnlyList<int> A, int X)
{
    if (A.Count == 0) return -1;
    if (A[0] > X) return 0;

    var L = 0;
    var R = A.Count;
    while ((R - L) > 1)
    {
        var M = (L + R) / 2;
        if (A[M] < X)
        {
            L = M;
        }
        else
        {
            R = M;
        }
    }
    return R;
}

A11 - Binary Search 1

atcoder.jp

List<T> には BinarySearch メソッドがあるけど、それ使っちゃ勉強にならないので、自前実装。

var NX = Console.ReadLine()!.Split(" ").Select(int.Parse).ToArray();
var N = NX[0];
var X = NX[1];
var A = Console.ReadLine()!.Split(" ").Select(int.Parse).ToArray();

var idx = Search(N, X, A);
Console.WriteLine(idx + 1);

static int Search(int N, int X, int[] A)
{
    var L = 0;
    var R = N - 1;
    while (L <= R)
    {
        var M = L + (R - L) / 2;
        if (A[M] == X)
        {
            return M;
        }
        else if (A[M] < X)
        {
            L = M + 1;
        }
        else
        {
            R = M - 1;
        }
    }
    return -1;
}

知識創造企業

マネジメントの勉強として読んでみたけど、本書も経営層向けで、自分のステージにはまだ早かった。中間管理職なんで。そんな自分でも役立ちそうなところだけメモ。

  • 知識変換の四つのモード
  • ミドル・アップダウン・マネジメント
    • ミドルは、トップと第一線マネジャーを結びつける戦略的「結節点」
    • トップが持っているビジョンとしての理想と第一線社員が直面することの多い錯綜したビジネスの現場をつなぐ「かけ橋」
    • ミドルは、知識創造企業の真の「ナレッジエンジニア」

.NET MAUI で終了時のウィンドウサイズと位置を保存して次回復元する

Window が閉じられるとにに各プロパティの値を保存しておいて、次回 Window 作成時にセットしてやるだけでよかった。念の為デスクトップアプリかどうかの判定はしている。

namespace HelloMaui;

public partial class App : Application
{
    public IServiceProvider ServiceProvider { get; }

    public App(IServiceProvider serviceProvider)
    {
        ServiceProvider = serviceProvider;

        InitializeComponent();
    }

    protected override Window CreateWindow(IActivationState? activationState)
    {
        var mainPage = ServiceProvider.GetRequiredService<MainPage>();
        var window = new Window(mainPage);

        if (DeviceInfo.Current.Idiom == DeviceIdiom.Desktop)
        {
            window.Destroying += HandleWindowDestroying;

            window.Width = Preferences.Default.Get($"{nameof(Window)}.{nameof(window.Width)}", window.Width);
            window.Height = Preferences.Default.Get($"{nameof(Window)}.{nameof(window.Height)}", window.Height);
            window.X = Preferences.Default.Get($"{nameof(Window)}.{nameof(window.X)}", window.X);
            window.Y = Preferences.Default.Get($"{nameof(Window)}.{nameof(window.Y)}", window.Y);
        }

        return window;
    }

    private void HandleWindowDestroying(object? sender, EventArgs e)
    {
        if (sender is Window window)
        {
            Preferences.Default.Set($"{nameof(Window)}.{nameof(window.Width)}", window.Width);
            Preferences.Default.Set($"{nameof(Window)}.{nameof(window.Height)}", window.Height);
            Preferences.Default.Set($"{nameof(Window)}.{nameof(window.X)}", window.X);
            Preferences.Default.Set($"{nameof(Window)}.{nameof(window.Y)}", window.Y);
        }
    }
}