Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

This article is a Private article. Only a writer and users who know the URL can access it.
Please change open range to public in publish setting if you want to share this article with other users.

「いちばんやさしいPython入門教室」修正(hit and blow判定のバグ修正)

Last updated at Posted at 2023-06-01

ブロー判定バグ

「いちばんやさしいPython入門教室」15章のヒットアンドブローゲームのブロー判定にバグがあります.

テキストの

    blow = 0
    for j in range(4):
        for i in range(4):
            if (int(b[j])==a[i]) and (int(b[i])!=a[i]) and(int(b[j])!=a[j]):
                blow = blow + 1
                break

だと,randomで作った数字が

[0,1,6,0]

に対して

[6,6,1,0]

と予測した場合に,

hit:1 blow:3

と判断されます.正しくは,

hit:1 blow:2

バグの中身

添付のようなコードに書き換えて,おかしい様子を表示させてみました.

def print_check(txt, mark, i, j):
    global a,b,mark_a,mark_b
    print(txt, i,j)
    mark_a[i]=mark
    mark_b[j]=mark
    print('answer: [{0:s}{4:d}, {1:s}{5:d}, {2:s}{6:d}, {3:s}{7:d}]'.format(*mark_a,*a))
    print(' trial: [{0:s}{4:d}, {1:s}{5:d}, {2:s}{6:d}, {3:s}{7:d}]'.format(*mark_b,*b))


def naive_check_text(a, b):
    global mark_a,mark_b
    blow, hit = 0, 0
    for i in range(4):
        if a[i] == b[i]:
            print_check('hit:','o',i,i)
            hit += 1
    for j in range(4):
        for i in range(4):
            if (b[j] == a[i]) and (a[i]!=b[i]) and (a[j]!=b[j]):
                print_check('blow:','x',i,j)
                blow = blow+1
                break
    return hit, blow

a = [0, 1, 6, 0]
b=[6,6,1,0]
mark_a=[' ',' ',' ',' ']
mark_b=[' ',' ',' ',' ']
print("\ncheck by text")
print(naive_check_text(a, b))
> python for_rev_check.py
check by text
hit: 3 3
answer: [ 0,  1,  6, o0]
 trial: [ 6,  6,  1, o0]
blow: 2 0
answer: [ 0,  1, x6, o0]
 trial: [x6,  6,  1, o0]
blow: 2 1
answer: [ 0,  1, x6, o0]
 trial: [x6, x6,  1, o0]
blow: 1 2
answer: [ 0, x1, x6, o0]
 trial: [x6, x6, x1, o0]
(1, 3)

となり,'o'で表記しているhit pairと,'x'で表記しているblow pairがおかしくなっている様子がわかると思います2, 3

仕様の変更??

というわけで,ゲームをしているときのヒントが,とんでもなく複雑でなかなか終わりません.解決策としては,

  1. 重複した数字を選ばないようにする,か,
  2. はたまた,より厳密にblowを判断させるか...

です.でも,1.の解決策はゲームのルールを変えるある種の仕様変更です.バグを「それは仕様です」と強弁する漫画がよくありますが,それと同じです.正しいプログラマ(?)は2.の道を進もうとしますが...

解決策

初めに自分で考えたやつは,意外と難しかったんです.

「もっと楽なやり方があれば教えてください」にtkuro-pさんに回答いただいたコードの改良版です3

 1  def naive_check_revised(answer, trial):
 2      global mark_a,mark_b
 3      blow, hit = 0, 0
 4      answer = answer[:] # 浅いコピー
 5      trial = trial[:] # 浅いコピー
 6      for i in range(len(trial)):
 7          if trial[i] == answer[i]:
 8              answer[i] = trial[i] = None
 9              print_check('hit:','o',i,i)
10              hit +=1
11      for i in range(len(answer)): 
12          for j in range(len(trial)): 
13              # print(i,j,answer[i],trial[j])
14              if (answer[i] == None) or (trial[j] == None):
15                  continue
16              if answer[i] == trial[j] :
17                  answer[i] = trial[j] = None
18                  blow+=1
19                  print_check('blow:','x',i,j)
20      return hit, blow

そんなに難しくないので,追いかけてください.

continueはそれ以降の処理をパスして,次の'j'で続けるという命令です.使っているテクニックは,

  • 浅いコピー(shallow copy)でダミーのデータを作っておいて(L4, 5),
  • 一度使った数字はNoneに書き換えて(L8, 17)
  • 以降のLoopでは使わない(continue) (L14, 15)

ことです.結果は,

check by revised
hit: 3 3
answer: [ 0,  1,  6, o0]
 trial: [ 6,  6,  1, o0]
blow: 1 2
answer: [ 0, x1,  6, o0]
 trial: [ 6,  6, x1, o0]
blow: 2 0
answer: [ 0, x1, x6, o0]
 trial: [x6,  6, x1, o0]
(1, 2)

と,ちゃんと予想通りになります.追いかける時のコツは,

  • L13のコメントアウトしているprintをアンコメントして生き返らせる
  • 変数名を意図を表すより具体的な英語(answer, trial)に変え,
  • i,j-loopの順序を普通に戻す

こういう簡単な書き換えで,読みやすく,デバッグしやすくなります.

print関連の,print_check呼び出しやglobalの行(L2)を外すとtextのcodeに置き換えて使えます.

参照

Footnotes

1 「いちばんやさしいPython入門教室」大澤文孝著,(ソーテック社出版,2017).

2 21年度テキスト

3 「いちばんやさしいPython入門教室」修正(hit and blow判定のバグ修正)記事


  • source ~/Desktop/lecture_24s/comp_a24/d7_11_python/d9_hit_and_blow_rev_23.org
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?