-1

私は現在、無重力のコネクト4ゲームであるプログラムを作成しようとしています。つまり、ボードのどこからでもピースを配置できます。現在、列を選択し、ピースを上から配置する作業を行っています。また、私のプログラムは、ゲームを難しくするために、ボード上にいくつのブロックを配置したいかをユーザーに尋ねます。たとえばC8と入力すると、各リストの8番目の要素のリストの8番目の行が調べられます。何かご意見は?

私が編集したコードは次のとおりです。

#this imports random for my blocks 
import random




#this makes my board
table = [[ "   ","C1", "C2", "C3", "C4", "C5", "C6", "C7", "C8", "C9", "C10"],
         [ " R1|", " |", " |", " |", " |", " |", " |", " |", " |", " |", " |"],
         [ " R2|", " |", " |", " |", " |", " |", " |", " |", " |", " |", " |"],
         [ " R3|", " |", " |", " |", " |", " |", " |", " |", " |", " |", " |"],
         [ " R4|", " |", " |", " |", " |", " |", " |", " |", " |", " |", " |"],
         [ " R5|", " |", " |", " |", " |", " |", " |", " |", " |", " |", " |"],
         [ " R6|", " |", " |", " |", " |", " |", " |", " |", " |", " |", " |"],
         [ " R7|", " |", " |", " |", " |", " |", " |", " |", " |", " |", " |"],
         [ " R8|", " |", " |", " |", " |", " |", " |", " |", " |", " |", " |"],
         [ " R9|", " |", " |", " |", " |", " |", " |", " |", " |", " |", " |"],
       [ "R10|" ," |", " |", " |", " |", " |", " |", " |", " |", " |", " |"]]
#my two different player pieces
player1="#|"
player2="@|"
block="B|"
row=11
columns=11
#this is a function i can call to print the table
def printTable(table):
    for row in table:
        for value in row:
            print (value,end=' ')
        print ('\n')

#this ask the user how many blocks they want on their board then places it on there
def block(table):
    blockQuestion=(input("how many blocks would you like to put on the table? \n (please enter a number between 1 and 25)"))
    number=blockQuestion[:2]
    number=int(number)
    number=number-1
    print("this is number ",number)
    count = 0      
    number=int(number)
    while number >= count:
        x=random.randint(1,10)
        y=random.randint(1,10)
        print("x and y ", x,y)

        table[x][y]="B|"
        count +=1

    printTable(table)
    move()



#this is my function to ask the user for their move.
def move():
    move=input("Please choose where you would like to drop your marker \n (For instance C1, R5)")
    move.split()
    rorc=move[0:1]
    ans=move[1:3]
    answer=int(ans)

    print(rorc," ",answer)

    if "R" in move:
        row(answer)

    if "C" in move:
        col(answer)
#this is my function if the user wants to go by row
def row(answer):
    side=input("would you like to insert it from the right or left \n Please type R for right or L for left ")

    if "R" in side:

        try:
            table[answer].reverse()

            blockCheck=table[answer].index("B|")
            if blockCheck == 0:
                print ("you can not place a peice there because of the block")
                tryAgain()                   
        except:
            try:
                p1Check=table[answer].index("#|")
                if p1Check is 0:
                    print ("you can not place a peice there due to the opponents marker")
                    tryAgain()
            except:
                try:
                    p2Check=table[answer].index("@|")
                    if p2check is 0:
                        print ("you can not place a peice there due to the opponents marker")
                        tryAgain()
                except:
                    print('hi')
    try:
        tits=max(blockCheck,p1Check,p2Check)
        print("All three checks",tits)

    except:
        try:
            tits=max(blockCheck,p1Check)
            print("this is bc and p1c",tits)
        except:
            tits=(blockCheck)
            print("this is block check",tits)
    table[answer].reverse()
    table[answer][-tits]= (player1)
    printTable(table)
#this is my function if the user wants to go by columns
def col(answer):
    side=input("would you like to insert it from the top or bottom \nPlease type T for top or B for bottom")
    answer=int(answer)
    if "T" in side:
        try:   
            blockCheck=table[:][answer].index("B|")

            print("blockCheck ", blockCheck)
            if blockCheck == 1:
                print ("you can not place a peice there because of the block")
                tryAgain()
        except:
            try:
                p1Check=table[answer].index("#|")
                if p1Check is 1:
                    print ("you can not place a peice there due to the opponents marker")
                    tryAgain()
            except:
                try:
                    p2Check=table[answer].index("@|")
                    if p2check is 1:
                        print ("you can not place a peice there due to the opponents marker")
                        tryAgain()
                except:
                    print("whaa")       
        try:
            tits=min(blockCheck,p1Check,p2Check)
            print("All three checks",tits)

        except:
            try:
                tits=min(blockCheck,p1Check)
                print("this is bc and p1c",tits)
            except:
                try:
                    tits=(blockCheck)
                    print("this is block check",tits)
                except:
                    tits=11
        table[tits-1][answer]= (player2)
        printTable(table)
#function to restart the program to the move function
def tryagain():
    tryAgain=input('try again \nPlease type y or n ')
    if tryAgain == 'y':
        move()
    elif tryAgain =='n':
        bash





#calls the function to start the program 
block(table)

前もって感謝します!

4

1 に答える 1

5

既にお気付きのこととif思いますが、ここにあるような一連のステートメントをデバッグするのは非常に困難です。実際、適切に作成されたプログラムのほとんどは、move機能さえあればほとんど何も含んでいません。Linus Torvalds は、Linux カーネルのスタイル ガイドで次のように述べています。

関数は短くて魅力的で、1 つのことだけを行う必要があります。それらはテキストの 1 つか 2 つの画面いっぱい (ISO/ANSI の画面サイズは 80×24 であることは周知のとおりです) に収まる必要があり、1 つのことを適切に実行する必要があります。

言い換えれば、(特に!) 最新のオペレーティング システム カーネルのように信じられないほど複雑なものをプログラミングしている場合でも、関数は 48 行以上のコードを占めるべきではありません Python よりもはるかに冗長です。あなたはここでその規則をかなりひどく破っています。move関数の長さが 100 行を超えています。

したがって、私の答えは実際には答えではなく、メタアンサーです。そのmove関数をいくつかの小さな関数に分割します。必要な入力の種類ごとに、入力を受け取り、それが正しいことを確認して、プログラムが使用できる値に変換する別の関数を記述します。if上記のロジックを可能な限りそれらの関数にシフトします。次に、move関数でそれらの関数を呼び出し、必要な最上位ロジックを適用します。少なくとも3 つ、おそらく5 つまたは6 つの異なる関数が 1 つの巨大な関数にまとめられているのがわかります。

分割したら、print ステートメントを使用して各関数を個別にテストし、期待どおりに動作することを確認します。それが完了し、期待どおりに動作していることを確認したら、問題がトップレベルmove関数に分離されていることがわかります。そこから、デバッグするのはまったく難しくありません - 私たちにとってもあなたにとっても!


あなたの編集により、状況が改善されました。しかし、関数がどのように機能するべきかについて、あなたが直感的な感覚を持っていないことは明らかです。上記のコードをどのようにリファクタリングしたかを検討してください。関数を作成しました。次に、その関数の最後で、別の関数を呼び出します。次に、その関数の最後で別の関数を呼び出します。関数を何度も連鎖させています。上記のコードの呼び出し図を描くと、次のようになります。

block
 |
 -> move
     |
     -> row | col
         |
         -> ...keep on calling new functions...          

それはそれが機能するはずの方法ではありません。代わりに、他の関数を呼び出して戻り値を取得する単一のメイン関数を用意する必要があります。次の簡単な例を考えてみましょう。

def get_val():
    x = None
    while x is None:
        x = raw_input('Give me a value: ')
        try:
            x = int(x)
        except ValueError:
            print('Value must be an integer')
            x = None
    return x

def transform_val(x):
    return x * 2

def main():
    val = get_val()
    val = transform_val(val)
    print(val)

上記の 2 つの関数が他の関数を呼び出していないことがわかります。彼らはただ何かをして戻ってきます。呼び出し図は次のようになります。

main
 |
 -> get_val
  <- |
 |
 -> transform_val
  <- |
 |

この場合、mainがプログラムの「最上位」にあり、すべてを制御していることがわかります。そのように見えるようにコードを再構築します。テーブルで動作する他の関数を呼び出すメイン関数が必要です。は変更可能であるためtable、これらはほとんど何も必要ありませんreturnが、別の関数呼び出しで終了するべきではありません。mainそれを関数に移動します。

def main():
    # define some variables here
    block(table)
    while no_winner(table):
        move(table)

ここno_winnerでテーブルを見て、誰かが勝ったかどうか、またはそれ以上の移動が可能でないかどうかを確認します。別の動きが可能かどう returnかに応じて、True または False を実行します。moveユーザーからの入力を受け取り、それに基づいてテーブルを変換します。これで、必要なすべての最上位ロジックがループに含まれるようになりました。次に、プログラムの下部で、これを実行してメイン プログラムを開始します。(これは、Python で呼び出す標準的な方法です。今のところ、その意味についてmain心配する必要はありません。__name__

if __name__ == '__main__':
    main()

私はまだあなたの実際の質問に答えていないことを知っています。しかし、これは実際には、探している特定のバグよりもはるかに重要だと思います。とはいえ、今から探し始めます。

于 2012-05-07T00:01:30.567 に答える