ChatGPTはデザインパターンを用いたリファクタリングもできるのねという話。

 ふとChatGPTはリファクタリングができるらしいけど、デザインパターンを用いたリファクタリングもできるのかなあと思って衝動的に聞いてみました。
結果としてはガッツリできたので便利と思う反面脅威ですね。

リファクタリング前コード

 あくまで例なので単純ですが、とりあえず以下のようなよろしくないコードを書きました。

def get_foo(kind):
    if kind == "1":
        return "foo"
    elif kind == "2":
        return "ふー"
    elif kind == "3":
        return "フー"

def get_bar(kind):
    if kind == "1":
        return "bar"
    elif kind == "2":
        return "ばー"
    elif kind == "3":
        return "バー"

def get_hoge(kind):
    if kind == "1":
        return "hoge"
    elif kind == "2":
        return "ほげ"
    elif kind == "3":
        return "ホゲ"

kind = input("入力")
print(get_foo(kind) + get_bar(kind) + get_hoge(kind))

 inputで1~3を入力すると、foobarhoge・ふーばーほげ・フーバーホゲとそれぞれに表示を変えて表示されます。kindが0とか4とかだと誤作動起こすと思いますがまあそれは今回割愛で。
 同じ条件式が3つの関数内で登場するというCode Smellがするコードです。kindの種類が増えるとif文がそれぞれの関数で追加される変更に弱いコードです。これは各関数が近い位置にあるので良いですが、関数の位置がとっ散らかってたらget_hogeとget_barにはif文追加したけどget_fooには追加し忘れてバグになるとかめっちゃ起こりそうなコードですね。

ChatGPTに訪ねた文言

 kindの状態によるのでStateパターンを用いればこのif文を消すことができますね。というわけで以下のようにChatGPTに訪ねました。

以下のPythonコードをStateパターンを用いてリファクタリングしてください

(以下コード。無駄に行数食うので省略)

ChatGPTの答え

そして返ってきたのがこちら。

class State:
    def get_foo(self):
        pass

    def get_bar(self):
        pass

    def get_hoge(self):
        pass

class Kind1State(State):
    def get_foo(self):
        return "foo"

    def get_bar(self):
        return "bar"

    def get_hoge(self):
        return "hoge"

class Kind2State(State):
    def get_foo(self):
        return "ふー"

    def get_bar(self):
        return "ばー"

    def get_hoge(self):
        return "ほげ"

class Kind3State(State):
    def get_foo(self):
        return "フー"

    def get_bar(self):
        return "バー"

    def get_hoge(self):
        return "ホゲ"

class KindContext:
    def __init__(self, kind):
        if kind == "1":
            self.state = Kind1State()
        elif kind == "2":
            self.state = Kind2State()
        elif kind == "3":
            self.state = Kind3State()

    def get_foo(self):
        return self.state.get_foo()

    def get_bar(self):
        return self.state.get_bar()

    def get_hoge(self):
        return self.state.get_hoge()

kind = input("入力")
context = KindContext(kind)
print(context.get_foo() + context.get_bar() + context.get_hoge())

 いやー素晴らしい。忌々しいif文を1つにすることがちゃんとできてます。あとはクラス名を変更すればOKですね。

不明点

  1. 今回はかなりわかり易い例。実践的なコードでここまでできるだろうか?
  2. 尋ねる文言にStateパターンを指定した。つまりこのケースではStateパターンを使用したほうが良いと人間が判断した。指定しなくてもやってくれるだろうか?ちなみに「もう一回尋ねたら?」と思うかも知れませんが、もうすでにこの例を出力しているのでStateパターンの文言を抜いても同じ答えが返ってくるでしょう。

 特に2については気になります。人間がデザインパターンを理解している必要があるかどうかが問われます。必要ないならデザインパターンを勉強する必要も無くなっちゃうかも。

ガーシー議員が72年ぶりの除名ということで、その前に除名された川上貫一氏について軽く調べてみた。

 実に72年ぶりの除名処分ということで話題になってますね。ぶっちゃけガーシー氏は個人的にどうでも良いのですが、その前に除名された人ってどんな人かしらん、と思って軽く調べてみました。

 結論から言うと、2023年から72年前、すなわち1951年に除名されたのは川上貫一氏です。日本共産党所属で、戦前から共産主義活動をしていたバリバリの左派ですね。

 これで終わりでも良いんですが、軽く蛇足を以下追加していきます。

 

目次

1951年当時の状況

当時は戦後まだ6年ほどで、1948年に発足した第二次吉田茂内閣の時代。日本はGHQの占領下にあり、前年1950年には朝鮮戦争が勃発、それを受けて自衛隊の前身である警察予備隊が発足しています。

 日本の状況としては戦後の復興が始まったばかりくらいというところでしょうか、有名な「もはや戦後ではない」の言葉が出たのは1956年。日米安保条約が締結されるのは1960年。ちょっと年表ぽくしてみます。

 

1945年 終戦

1948年 第二次吉田内閣発足

1950年 朝鮮戦争勃発、警察予備隊発足

1951年 川上氏除名 ←ここ

1956年 「もはや戦後ではない」宣言

1960年 日米安保条約締結

 

これである程度当時の状況が分かるでしょうか。ちなみに当時はまだ自由民主党は存在せず、前身の自由党民主党が存在している時代でした。

問題視された川上氏の発言

 さて話を川上氏に戻すと、そもそも氏が除名に至ったきっかけとしては、1951年1月27日の衆議院本会議での発言であるようです。以下しんぶん赤旗のWebページの引用です。

そういうなかで同年1月27日、衆議院本会議で川上氏は、「…国民の大多数は単独講和に反対しておる。…再軍備に反対しておる。同時に占領軍の早期撤退を望んでおります。…ここに日本国民の名において、かような政治を即時中止して、日本国憲法を守って、ポッダム宣言に基づく全面講和を実現するいっさいの政策を実行することを要求するものであります」と1時間近い代表質問に立ちます。〈このいわゆる「除名演説」全文は川上著『たたかいの足おと』(新日本出版社)にあります。衆院会議録ではかなり削除されています〉

www.jcp.or.jp

 ここで出てくる「単独講和」「全面講和」というのは日本が独立を回復するための講和条約のこと。全面講和というのは連合国すべての国と一斉に講話をすること、単独講和はまずは講話できる国と先行して講話しようということです。吉田茂内閣は単独講和を進めようとしていました。川上氏はこれに反対し、全面講和が良いと主張したということです。

 これに対して自由党民主党の一部が不穏当な表現であり国会の品位を汚したとして懲罰動議を提出しました。懲罰委員会はそれを認めて川上氏に陳謝を求めるも、それを拒否したため除名された、という流れです。ちなみに得票は賛成239、反対71でした。ガーシー氏の得票は賛成235、反対1。ガーシー圧倒的w

 国会の品位を汚したというなんともあやふやな理由で除名されるというのは、当時朝鮮戦争勃発でGHQによるいわゆるレッド・パージが吹き荒れていたことが関係してそうな気がします(ホントのところは分からない)。

除名されるも国会議員に復帰した川上氏

 除名された川上氏なのですが、2年後の1953年の衆議院選挙で当選し、議員に返り咲いています。除名されたにも関わらず返り咲くというのは、これが当時の民意ということも言えるかも知れませんね。

 

 蛇足もここまで。さてガーシー氏は川上氏と同様議員に返り咲くことはできるんでしょうか。個人的にはできないに賭けたいところですねw

 ちなみに川上氏について最初ChatGPTについて聞いてみました。楽できるかなと思って。そしたら共産党なのに自民党所属とか、2007年に贈賄で除名とか思いっきり嘘を吐かれましたw聞き方が悪かったのかAIがまだまだなのかは不明です。ぜんぜん違うよと言ったら素直に謝るChatGPT可愛い。擬人化待ったなし。

セーリングエラ(Sailing Era)。交易で儲けるコツ教えます。

やってますか!セーリングエラ!
コーエーテクモの『大航海時代』シリーズに大ハマリした人間にとってはもう福音とも言ってもいいゲームが出ましたね!

STEAMページは以下。アフィリじゃないので安心してクリックしてくだしあ。
store.steampowered.com

雰囲気としては『大航海時代2』と『大航海時代4』を足した感じ。でも言語を勉強する必要があったりするのは『大航海時代3』ぽさもあるかも。

今回はこの手のゲームの基本、交易のコツを紹介しようと思います。

交易のコツ

・「繁栄」「不景気」を狙う
・「異文化」を狙う
・「奢侈品」を狙う
・儲けづらい地域は貿易派遣で交易品を手に入れる

「繁栄」「不景気」を狙う

おそらく毎月ランダムに生じると思うんですが、各港には状態があります。「繁栄」はいわゆる好景気。交易品の相場が上がります。逆に「不景気」は交易品の相場が下がります。

もうおわかりかと思うんですが、「不景気」の港で交易品を仕入れ、「繁栄」の港で捌けばもうボロ儲け、というわけです。

まちがっても繁栄の港で買わないように。また絶対にこの2つの組み合わせじゃなくてもいいです。不景気の港でとりあえず買って、通常の港で売っても儲かります。通常の港で買って繁栄の港で売ってもOKです。


(「繁栄」の港はピカピカ光ってすぐわかります。一方不景気は見ても分からないので注意)

「異文化」を狙う

港ないしは交易品には文化圏があるようです(マスクデータ?)。例えば日本と中国。例えばヨーロッパとイスラームという具合。この文化が違うと、同じ交易品でも値段が上がります。

追記:ちゃんと調べてみるとそういうことは特になかったです。ただし、異文化の港の方がやはり価格指数(%で表される価格水準のこと)が高いことが多いため、意識するに越したことはないようです。

あ、ただしイスラームは宗教上飲酒ができないのを反映して、ワインなどの酒はそもそも売れません。間違って仕入れないようにしましょう。

「奢侈品」を狙う

奢侈品は「しゃしひん」と読みます。贅沢品の意味です。ここでは単価が高い商品のことを指します。
大航海時代」シリーズでもセオリーですが、「単価が高い」ものの方が儲けやすいです。例えば不景気の港で50%の相場で買い、繁栄の港で150%で売ったとしましょう。それぞれ単価が500と2000の交易品で考えてみましょう。

500の場合

仕入れ:500 * 50% = 250
販売:500 * 150% = 750
つまり、船倉1つあたり500の儲け。

2000の場合

仕入れ:2000 * 50% = 1000
販売:2000 * 150% = 3000
つまり、船倉1つあたり2000の儲け。

どうでしょう。1500の差が出てきます。船倉には限りがあるため、単価が高い交易品の方が儲けやすいのです。これは「大航海時代」シリーズでも同様。コショーが意外と儲けられない原因になってたりします。ただしこのゲームの場合コショーは儲かります。結構単価高いので。

さて、これらを考慮して「儲けやすい地域」を考えてみます。

儲けやすい地域

まだ筆者はアメリカ大陸に到達していないのですが、それ以外の地域では一通り交易しました。その中で儲けやすいと筆者が感じた地域はこの2つです。

  • 東アジア
  • 地中海

東アジア

東アジアは中国と日本の文化圏が異なり(朝鮮も別かも)ます。それが狭い東シナ海で切り替わるため、短時間で儲けやすいです。奢侈品も中国の青磁、日本の日本刀、朝鮮の高麗人参など、我々日本人にとってわかりやすく仕入れやすいです。

どうでも良いけど江戸の交易品が小麦やタイマイ(亀)なのはなぜなんだろう・・・?w

地中海

地中海はヨーロッパキリスト教圏と、北アフリカ、中東のイスラーム圏の文化圏が異なり、地中海も比較的狭いため儲けやすい地域です。ただし、意外と地中海は雨が多くて交易品が悪くなりがち。雨でやられない交易品にするか、整備室を作りたいところです。

奢侈品はヴェネツィアアテネイスタンブールアレクサンドリアなどで仕入れられます。特にアレクサンドリアは許可を取ればコショーを扱えます。雨には注意。

そういえば『大航海時代2』ではアテネの美術品とイスタンブールの絨毯が鉄板でしたね。この作品でも似たようなことができます。

儲けにくい地域

逆に儲けにくいと感じた地域はこの2つ。

  • 東南アジア
  • アフリカ

違う文化圏までの距離が割と長く、奢侈品を扱うには許可が必要なケースが多い。赤道付近のため雨も多くて交易品がダメになりやすい、と少々厳しい場所です。

ちなみに中東~インドは普通です。中東とインドは違う文化圏ですが、少しだけ距離があるので少々儲けづらいです。

(中東は少々儲けづらいけれど許容範囲。しかもカリカットの酒場女エイミーちゃんはとても可愛い。この港の商人ギルドの名前を『エイミーちゃん親衛隊』にしたことは彼女には秘密だ!(多分バレてる))

ですが、これらの地域に価値が無いわけではありません。商人ギルドを作り、「貿易艦隊」を派遣すればこれらの弱点をカバーできます。

貿易艦隊で簡単に交易品を手に入れる

商人ギルドを作り、投資をして港の人口と技術を一定まで上げると「商人ギルド貿易」コマンドが開放されます。これはいくらかのコストで指定した港に艦隊を派遣、交易品の買付をさせられるというもの。艦隊を別に用意する必要はありません。ソシャゲでよくある「遠征」みたいなイメージです。


カリカットの商人ギルド『エイミーちゃん親衛隊』の様子。技術値はおそらく999まで上げられそう)

買付には1ヶ月かかり、商人ギルドがある港に交易品が降ろされます。自分で行く必要がないため非常に便利です。ただし何を買い付けてくるかはある程度指定はできても基本ランダム。また交易品は自分で捌く必要があります。

さて、どこに派遣すればよいかということですが、つまりはここでアフリカ・東南アジアが生きてきます。距離のあるこれらの地域も派遣なら関係ないわけです。

オススメ派遣場所

オススメはアフリカ。以下が良いでしょう。

西アフリカはセント・ジョージやシエラレオネ。許可を取れば前者は金、後者はダイヤモンドを扱えるようになります。
東アフリカはソファラが断然オススメ。許可品が金で、それ以外の交易品もサイのツノとエメラルドなのでハズレがありません。


(中東スタートのアヴドゥラー編の場合、ソファラはとても美味しい。ちなみに史実上では、現在のジンバブエに存在したモノモタパ王国から産出した金がソファラに運ばれていました。ポルトガルは後々この王国を属国化します)

とりあえず筆者が見出した交易のコツは以上です。
令和のこの時代にこういうゲームを出してくれたことが本当に嬉しいですね。これでプレイヤーが増えてくれることを願っています。
それでは良い大航海時代ライフを!

ジャンヌ・ダルクが大砲を野戦で始めて使ったっていう都市伝説を否定してみる

ネットを見るとたまーに(ほんとに極たまに)「ジャンヌ・ダルクが始めて野戦で大砲を人に向けて撃った」って話をする人を見かける。

 

それまで大砲は攻城兵器としてしか使われていなかったけど、騎士の戦いにこだわらないジャンヌ・ダルクが野戦で使用して人に向かって撃ち出した。仁、これが誉れある戦いと言えるか

ここから発展して

 

ジャンヌ・ダルク登場後、フランス軍が野戦でも勝てるようになったのは、イングランドの長弓兵を大砲の射程で圧倒したから。

なんて話をする人も見かけた。

 

「それ多分違うなー」と思いながらもドイツ史・戦史はそこそこ知ってるがフランス史はあまりしらない俺はその都度スルーしていた。

 

だけど今回わりとがっつり調べた(つってもソースはほとんどWikipedia)ので、忘れないようにメモがてら書いておく。

 

ジャンヌ・ダルクが生まれる前に野戦ですでに使用されていた大砲

百年戦争中の野戦で、大砲が使用された最初の例は有名なクレシーの戦い。ジャンヌ・ダルクどころかフランス軍でもなく、イングランド軍が使用している。

desaixjp.blog.fc2.com

2~3門の大砲を撃ち、フランス軍に動揺が走ったようだ。

否定する向きもあるようだが、大多数の歴史家に受け入れられている様子。

 

クレシーの戦いは1346年。

ジャンヌ・ダルクが生まれたのは1412年。

ジャンヌ・ダルクが世に出るきっかけとなったオルレアン包囲戦は1428年。

 

この時点でもう「ジャンヌ・ダルクが始めて人に大砲を撃ち始めた」が否定される。

 

さらにオルレアン包囲戦のさなかに起きたニシンの戦いにおいてもフランス軍が大砲を使用している。

ja.wikipedia.org

ちなみにジャンヌ・ダルクはこの戦いでフランス軍が負けると予言し、的中させたため聖女と認められたらしい。

それまでは相手にされていなかったので、この戦いでジャンヌ・ダルクフランス軍に大砲の使用を具申することはできない。

 

探せば他にもありそうだけどとりあえずこれだけでも十分否定になると思うのでこの程度で。

 

ではもう一つ、大砲の長い射程で長弓兵を圧倒した事実はあるのか。

大砲のアウトレンジ戦法で長弓兵に勝った戦いはあったのか?

なるほどリーチの差を使えば敵に対し有利にはなりそう。

では実際にそのような戦いがあったのか?

結論から言うと、調べた限りはなかった。だが大砲が活躍できた戦いはあった。

 

ジャンヌ・ダルク登場後にフランス軍が勝利した最初の野戦としてはパテーの戦いがある。

だけどこの勝因は、たまたまイングランド軍の伏兵にフランス軍が気がついたから。

そしてイングランド軍の準備が整わないうちにフランス軍が突撃をかけたから。

 

それ以後の戦いでも、大体はフランス軍の突撃が適切に行われたことで勝利している。

要はこの時代でも騎兵による突撃は有効な戦い方だった。

 

モード・アングレの弱点

クレシーの戦いで有名になったイングランド軍のモード・アングレは、有効に働くためには事前に敵の攻撃を止めるための準備が重要である。

その準備が適切に行われていなかった場合は機能しなかった。

 

クレシーやアジャンクールの戦いイングランド軍が勝てたのは、フランス軍の突撃を前者は下馬騎士が、後者は逆茂木が止めてくれたからと言える。

 

また敵の攻撃を受け止める騎士と長弓兵との間で連携が取れなかった場合も負けている。

百年戦争ではないがイングランドスコットランドの戦い、バノックバーンの戦いがそう。

百年戦争より前に行われたこの戦いでは、まだ騎士が馬に乗っていたため突出してしまい、歩兵の長弓兵としっかり連携が取れなかった。

ja.wikipedia.org

大砲が活躍できたカスティヨンの戦い

結局百年戦争において大砲は野戦で活躍できなかったのか、と言われると「一応できた戦いはある」と答えられる。それが百年戦争最後の戦い、1453年のカスティヨンの戦いだ。

weaponsandwarfare.com

だがこの戦いも大砲のおかげ、と言われると微妙なところがある。

 

カスティヨンの街近郊で行われたこの戦いは、フランス軍が砲兵陣地を構築。この陣地には実に300門もの大砲が設置されていた。

 イングランド軍はこの陣地のフランス軍が退却している、という情報を得てこの陣地に攻撃を開始。だがこの情報は誤報だった。

 誤報と分かった後もイングランド軍は攻撃を続けたが陣地の突破はならず、大きな損害を出して退却。

 

というのがこの戦いの趨勢だ。

 

つまりモード・アングレで攻撃を待ち受ける長弓兵を大砲のアウトレンジで撃滅したわけではなく、フランス軍の方が野戦築城で攻撃を待ち受けていた。

誤報のせいとはいえイングランド軍がしたことは、アメリ南北戦争ゲティスバーグの戦いで行われたピケットの突撃のような無謀な行為。

それを「してくれた」おかげで勝てたようなもの、と言ったら言い過ぎか。

f:id:sekiroku-kocho:20210517213542j:plain

クレシーの戦い

f:id:sekiroku-kocho:20210517213416j:plain

カスティヨンの戦い

大砲が撃たれていたはずなのに全く登場しないクレシーの戦いに対し、カスティヨンの戦いでははっきりと大砲が登場している。やはり活躍したのだろう。ただしアウトレンジ戦法ではない。

カスティヨンの戦いの右端真ん中、クロスボウの奥にある銀色の細長いものはひょっとしたらアルケブス(初期の火縄銃)だろうか?


まとめ

ジャンヌ・ダルクが生まれる以前からすでに大砲は野戦においても使用されていた。

ただし大砲が野戦で活躍できたケースは非常にまれだった。 

 

実際のところ、この時代の大砲が野戦で活躍するのはかなり難しかった。

カスティヨンの戦いでフランス軍が(運もあるが)それを可能にしたのには秘密があった。

そのへんについては長くなったので別記事で書いてみる予定。