質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
Python 3.x

Python 3はPythonプログラミング言語の最新バージョンであり、2008年12月3日にリリースされました。

Q&A

解決済

1回答

776閲覧

3目並べの打ち手探索条件について

step_by_step

総合スコア8

Python 3.x

Python 3はPythonプログラミング言語の最新バージョンであり、2008年12月3日にリリースされました。

0グッド

2クリップ

投稿2020/04/22 01:03

3目並べを行うコードを見て、写し書いているのですが、

w = [i for i in range(9) if (board & (1 << i)) == 0] #置ける場所を探す

こちらの行の "if (board & (1 << i)) == 0" が何を規定しているのか内容がわからず。
i for i in range(9)部分では、3 x 3 の盤面を9個の要素があるリストの枠として規定しているのだと
思いますが、そのあとの if 文では何を絞り込んでいるのでしょうか? 特に整数 1 に対して ビット演算シフト
をしている理由、またそれが 0 と同等かどうか見極めている意味がわかりません。

どなたかご教示いただければ大変助かります。

python

1import random 2 3# 終了条件 4 5goal = [ 6 0b111000000, 0b000111000, 0b000000111, 0b100100100, 7 0b010010010, 0b001001001, 0b100010001, 0b001010100 8] 9 10#3つ並んだか判定 11 12def check(player): 13 for mask in goal: 14 if player & mask == mask: 15 print("tested") 16 return True 17 return False 18 19#交互に置く 20 21def play(p1, p2): 22 print("play_ ", bin(p1), bin(p2)) 23 if check(p2): #3つ並んでいたら出力して終了 24 print("settled", [bin(p1), bin(p2)]) 25 return 26 board = p1 | p2 #現在の盤面状況 27 print("board ", bin(board)) 28 if board == 0b111111111: #すべて置いたら引き分けで終了 29 print([bin(p1), bin(p2), "draw"]) 30 return 31 32 w = [i for i in range(9) if (board & (1 << i)) == 0] #置ける場所を探す 33 print("move_ ", w) 34 r = random.choice(w) 35 print("rchoice ", r) 36 play(p2, p1 | (1 << r )) #再帰:手番を入れ替えて次を探す 37 38play(0, 0) 39

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

meg_

2020/04/22 01:33

・コードの出典元を明記しましょう。 ・コードの作成者には直接質問できない状況でしょうか?(本人に聞ければベストかと思うので)
step_by_step

2020/04/22 06:34

アドバイスをありがとうございます。 コードの出典は「python ではじめるアルゴリズム入門」(翔泳社) という書籍になります。 著者の方にコンタクトも考え個人ウェブを見たところ、業務対応をメインとされている方の ようでしたので、まずはヴォランタリーなアドバイスを求めるため、こちらに展開いたしました。 ソースが明らかな場合はなるべく作成者への質問を中心に対応できるよう心がけるようにします。
guest

回答1

0

ベストアンサー

このコードではボードデータを ビットで保持しているようですね。
今どきこんなメモリーケチケチ仕様のコードはあまり見かけませんが、8bit時代にはよく用いられた手法です。

例えば

110
001
000

のようなボードデータは

876543210
110001000

のようにシリアル化されて最終的には

0b110001000

のような9bitデータに置き換えられて保持されます。

で、上記のデータ(0b110001000)から下のような bitが0の位置のリスト、つまり [0,1,2,4,5,6] を作成している箇所が質問のコードとなります。

で質問のコードですが、現状は内包表記で書かれておりますが、通常のループで書くと

Python

1w = [] 2for i in range(9): 3 mask = 1 << i # 対象のビットが 1 それ以外は 0 のマスクを作成 4 if (board & mask) == 0: # 対象となるビットが 0 かどうか 5 w.append(w)

こんな感じになります。
見ていただくとわかると思いますが、単に下位ビットから値が0かどうかを調べて、0 の場合のみリストに追加するということをやっております。

投稿2020/04/22 02:15

編集2020/04/22 02:22
magichan

総合スコア15898

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

step_by_step

2020/04/22 06:54

ご丁寧にありがとうございます。いただいたアドバイスをもとに以下のように 出力してみて、当該行の動きがよくわかりました。重ねて御礼まで。 i = 0 0b1 # シフト前の bin(1) 0b1 # i 分だけ左シフト ----- i = 1 0b1 0b10 ----- i = 2 0b1 0b100 ----- i = 3 0b1 0b1000 ----- i = 4 0b1 0b10000 ----- i = 5 0b1 0b100000 ----- i = 6 0b1 0b1000000 ----- i = 7 0b1 0b10000000 ----- i = 8 0b1 0b100000000 -----
step_by_step

2020/04/23 08:32

すみません、理解したつもりになっていたのですが、上記で理解できた行から先の 挙動が咀嚼しきれておりませんでした。内包表記を通常のループ文に開いて示して いただいた中での下記の行、 if (board & mask) == 0: # 対象となるビットが 0 かどうか という箇所ですが、たとえば、 i = 3, maskが 0b1000 に際して、board が 0b100000001 だったとして、 board & mask という条件は、なにをどのように判定しているものでしょうか? ビット演算の論理積であることは理解しているつもりなのですが、たとえば、 長さの違うビット列を扱う際の挙動がよくわからず... お手数ですが、再びご教示いただければ幸いです。
magichan

2020/04/23 08:52 編集

単に表示する際に上位の桁が表示されていないだけと考えてください。 maskが 0b1000 に際して、board が 0b100000001 の場合(仮にどちらも24bitデータと仮定すると) 0b0000000000001000 0b0000000100000001 とがand演算されて 0b0000000000000000 が得られるということになります。
step_by_step

2020/04/25 04:10

ご教示のほど、ありがとうございます。 ビット列の長さの違いは左寄せで短い方を補完するものと勝手に理解しておりました... 逆であることがわかってから、以降の処理含めて腹落ちしました。 重ねて御礼申し上げます。
magichan

2020/04/26 02:58

はい。通常の四則演算となんら変わりません。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問