ひるあんどんブログ

色々なことに手を出してみるブログ

Pawn Brotherhood


世の中のほとんどすべての人が昔のゲーム チェスを知っていて、ルールについて基本的な理解はしている。チェスは様々なユニットを持ち、幅広い動きのパターンを持っているので非常に多くのゲームパターンを可能にしている。(例えば、最後のn手での可能なチェス盤面の数) このミッションではチェスのポーンの動きと振る舞いについて調べる。

チェスは2人で行う戦略的ゲームであり、8つの列(1-8の数で示されるランクと呼ばれるものがある)と8つの行(a-hの文字で示されるファイルと呼ばれるものがある)の四角があるチェッカーのゲームボードの上で行う。 それぞれのチェスボードの四角はユニークな座標のペアによって示される ー 文字と数である(例: "a1", "h8", "d6")。 このミッションでは私たちはポーンについてのみ考える。ポーンは隣接した斜め前にある敵の駒を、そのマスに動かすことによって取ることができる。白のポーンにとって前のマスは現在のマスよりも大きい数字の列になる。

ポーンは一般的に弱いユニットだが、私たちはそれらを8つ持っておりポーンの防御壁を築くことができる。 この戦略ではひとつのポーンは別のポーンを守っている。 別のポーンが取れるマスではポーンは安全(safe)である。 私たちはいくつかの白のポーンだけを持っている。 あなたはいくつのポーンが安全であるか探しだすコードを設計しなくてはならない。



あなたは白のポーンが置かれているマスの座標のセット(set)が与えられる。 いくつのポーンが安全であるか数えなくてはならない。

入力 ポーンが置かれている座標が文字列のsetとして与えられる

出力 安全なポーンの数を整数として出力する

safe_pawns({"b4", "d4", "f4", "c3", "e3", "g5", "d2"}) == 6

safe_pawns({"b4", "c4", "d4", "e4", "f4", "g4", "e5"}) == 1


どのように使われるか ゲームのAIにとって重要なタスクの一つがゲームの状態を見積もる能力である。 このコンセプトはどうやってあなたが単純なチェスの図でやれるかを示すだろう。

事前条件
0 < pawns ≤ 8


このコードは動かない

def check_safe(target):
    """
    ななめ4方の座標をかえす
    """
    
    target = list(target)
    alpha = target[0]
    number = target[1]
    result = []
    
    
    if alpha != "a" and number != 8:
        alphas = ord(alpha)
        alphas = chr(alphas+1)
        result.append(str(alphas) + str(number + 1))
    
    if alpha != "h" and number != 8:
        alphas = ord(alpha) + 1
        alphas = chr(alphas)
        result.append(alphas+ str(number + 1))
        
    if alpha != "a" and number != 1:
        alphas = ord(alpha) - 1
        alphas = chr(alphas)
        result.append(alphas + str(number - 1))
    
    if alpha != "h" and number != 1:
        alphas = ord(alpha) + 1
        alphas = chr(alphas)
        result.appned(alphas + str(number - 1))
        
    return result
    
     

def safe_pawns(pawns):
    pawns = list(pawns)
    count = 0
    for x in pawns:
        result = check_safe(x)
        if pawn in result:
            count += 1
        
    return count
        

if __name__ == '__main__':
    #These "asserts" using only for self-checking and not necessary for auto-testing
    assert safe_pawns({"b4", "d4", "f4", "c3", "e3", "g5", "d2"}) == 6
    assert safe_pawns({"b4", "c4", "d4", "e4", "f4", "g4", "e5"}) == 1

ななめ4方のそれぞれの座標を返して、その数を数えようとしたのだけれど、うまく動かなかった。

どうにも元気がないので、ズルだけれど、正答を読みといて勉強する。

def safe_pawns(pawns):
    def get_coord(cell):
        return ord(cell[0])-96, int(cell[1])

 
    def defend_coord(x, y):
        defend = []
        if (x+1 <= 8) and (y+1 <= 8):
            defend.append([x+1, y+1])
        if (x-1 <= 8) and (y+1 <= 8):
            defend.append([x-1, y+1])
        return defend

    board = [[0 for j in range(9)] for i in range(9)]
    pawns, ans = list(pawns), 0

    for pawn in pawns:
        for pwn in defend_coord(*get_coord(pawn)):
            board[pwn[0]][pwn[1]] = 1

    
    for pawn in pawns:
        ans += board[get_coord(pawn)[0]][get_coord(pawn)[1]]
    return ans

clear一位の人たちのコードはハイレベル過ぎて読み解くのが大変なので、なるべく自分の考えに近いコードを。
まず、defend_coord(x,y)

これはあるポーンの座標(x,y)を引数にとって、そのポーンの座標からみて斜め4方の座標をリストに追加して返すようだ。
もちろん、盤上を超えてしまう座標については除外するようにしている。

次にget_coord(cell)
引数であるcellには、"b4"などの座標が入る。

ord関数は

ord(c)

    1 文字の Unicode 文字を表す文字列に対し、その文字の Unicode コードポイントを表す整数を返します。例えば、 ord('a') は整数 97 を返し、 ord('\u2020') は 8224 を返します。これは chr() の逆です。

とある。
つまり、この96を引いている理由はaを1にbを2と変換することで今後の関数に対応しやすくしている。
返り値は(1、4)など、int型を2つ含むタプルだ。

さてリストの内包表記で8*8のリスト(変数はboard)をつくる。pythonで二次元配列をなんというのかは、わからないけどいわゆる二次元配列のリストだ。要素は全て0

多重代入によって、座標のリストと作ると同時にカウンター変数を0に初期化している


あとはforループによって、board上の全てのポーンの斜め4方の座標を1に変更していく。

最後に、それぞれのポーンの座標をループでまわし、もしboard上の座標と一致していればそれがsafe_pawnなので、カウンターに加算する。