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

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

ただいまの
回答率

88.64%

python3 ログファイルの解析

解決済

回答 2

投稿

  • 評価
  • クリップ 0
  • VIEW 226

17issosu

score 6

前提・実現したいこと

python3.7で、ログファイルを解析し、ブラックジャックのカウンティングをするというプログラムを組んでいます。

読み取るログファイルの中身は
♣6 ♡6 ♢A ♠5,♢9 ♡5 ♢4,0
♡9 ♡Q,♠6 ♢10 ♣4,-10
♣5 ♡10 ♢J,♣8 ♠7,-10
♠8 ♠J,♢6 ♣2 ♢5 ♠3 ♣Q,10
です。最後の0か10か-10は関係ないので無視し、
A,K,Q,J,10→-1
6,5,4,3,2→+1
その他→±0
で計算し、このログファイル全体の合計値を出します。

発生している問題・エラーメッセージ

合計値として5が出力されるはずですが、10が出力されてしまいます。

該当のソースコード

import sys
s=0

try:
    with open(sys.argv[1]) as fp:
        for line in fp:
            if line.find("A"or"K"or"Q"or"J"or"♢10"or"♡10"or"♠10"or"♣10")>=0:
                num_m=line.count("A")+line.count("K")+line.count("Q")+line.count("J")+line.count("♢10")+line.count("♡10")+line.count("♠10")+line.count("♣10")
                s-=num_m
            else:
                pass

            if line.find("6"or"5"or"4"or"3"or"2")>=0:
                num_p=line.count("6")+line.count("5")+line.count("4")+line.count("3")+line.count("2")
                s+=num_p                
            else:
                pass

        print(s)

except FileNotFoundError:
    print("File read error")

補足情報(FW/ツールのバージョンなど)

windows10を使っています

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

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

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

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 過去に投稿した質問と同じ内容の質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 2

checkベストアンサー

+1

import sys
s=0

try:
  with open(sys.argv[1]) as fp:
    for line in fp:
      num_m=line.count("A")+line.count("K")+line.count("Q")+line.count("J")+line.count("♢10")+line.count("♡10")+line.count("♠10")+line.count("♣10")
      s-=num_m

      num_p=line.count("6")+line.count("5")+line.count("4")+line.count("3")+line.count("2")
      s+=num_p

  print(s)

except FileNotFoundError:
  print("File read error")

絵札と番号札とで条件分岐は不要なので、単純に数え上げればよいはずです。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2019/11/11 00:46

    ありがとうございます。確かに条件分岐は不要でした。しかし、上記のプログラムを実行すると5ではなく7を出力として得てしまいます。何が問題なのでしょうか・・・?

    キャンセル

  • 2019/11/11 01:05

    文字化けの問題でした・・・!!このプログラムで正常な出力が得られました。ありがとうございます

    キャンセル

0

論理バグの原因と解法について

直接的原因
if line.find("A"or"K"or"Q"or"J"or"♢10"or"♡10"or"♠10"or"♣10")>=0:

この条件は、次のように書いているのと同じです。

if line.find("A")>=0:
強引な解法

次のように、帰属判定した結果をorで結んでやります。
※ 帰属判定とは、リストなどのコレクションにある特定の要素が含まれるか調べること。

if line.find("A") >= 0 or line.find("K") >= 0 or line.find("Q") >= 0 or ...:

なお帰属判定にはin演算子を使うことが好ましいので、次のように書き換えると少しはマシです。
参考: 組み込み型 — Python 3.8.0 ドキュメント

if "A" in line or "K" in line or "Q" in line or ...:

any関数とジェネレータ式を使うとずっと簡略化できますが、回答の本旨に反するため省略します。

現実的な解法

既にNCC1701さんが回答されているとおり、不要な分岐を無くすことです。

論理演算について、もう少し詳しく

値にはいわゆるtruthyなものとfalsyなものが存在します。
これらについて乱暴に説明すると、bool関数に突っ込んだときtrueを返す値がtruthyです

>>> bool('spam')  # 'spam' はtruthy
True
>>> bool('ham')   # 'ham' はtruthy
True
>>> bool('')      # '' はfalsy
False

シーケンスについては、長さ0のものがfalsyに振舞うように設計されています。
文字列の場合、空文字列です。


or演算子は両オペランドの真偽を判断し、結果が確定した際の値を返します。
or演算の場合、最初に見つけたtruthyな要素を返すことになります。

>>> 'spam' or ''
'spam'
>>> '' or 'ham'
'ham'
>>>
>>> 'spam' or 'ham'
'spam'
>>> 'ham' or 'spam'
'ham'
>>> '' or ''
''

上記を踏まえると、"A" or "K" or ... が "A" を返すことが分かります。

別解

私なら次のように書きます。

import sys


def get_score(card):
    rank = card[1:]

    if rank in ['A', '10', 'J', 'Q', 'K']:
        return -1

    rank = int(rank)
    if 2 <= rank <= 6:
        return +1

    return 0


s = 0
assert 1 < len(sys.argv), 'USAGE: .py logfile'
with open(sys.argv[1]) as fin:
    for line in fin:
        cards1, cards2, _ = line.split(',')
        cards1 = cards1.split()
        cards2 = cards2.split()

        s += sum(map(get_score, cards1))
        s += sum(map(get_score, cards2))

print(s)

Wandbox

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

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

  • ただいまの回答率 88.64%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

同じタグがついた質問を見る