55740
pythonを使い、数字を順番通りにならべかえるゲームを作っています。terminalで表示して遊べるところまではできたのですが、ソースコードにも書いている`random.shuffle(list1)`を使ってしまうと、本当に数字がランダムにシャッフルされてしまい、元どおりにならべかえることが難しくなってしまうゲームになっています。  
現在、

```

    123
    456
    78
    
```

と右下に１マス空け、上下左右ランダムに10回ほど動いてからゲームを開始するというプログラムを書きたいのですが、これをどうやればいいか悩んでいます。  
教えていただけると幸いです。

```

    import string
    import random
    import sys
    moves = 0
    game_start=True 
    list1 = [0,1,2,3,4,5,6,7,8]
    random.shuffle(list1)
    print('\n'*2)
    
    matrix33=[]
    while list1 !=[]:
        matrix33.append(list1[:3])
        list1 = list1[3:]
    
    def zero(board):
        global empty_space
        for x in range (len(board)):
            for y in range(len(board[x])):
                if board[x][y]==0:
                    empty_space = (x,y)
        return empty_space
    
    def draw_board(board):
        print('\n\t+-----+-----+-----|')
        for x in range (len(board)):
            for y in range(len(board[x])):
                if board[x][y] == 0:
                    print('\t|  XX' , end='')
                else:
                    print('\t|  ' + '{:02d}' .format(board[x][y]), end=' ') 
            print('\n\t+-------+-------+-------|')
    
    def ask_number():
        global num , piece 
        num = input('\nplease type the number of the piece to move : ( q ) to quit  ')
        if num in ['q','Q']:
            print('\n\ngame over  ')
            sys.exit()     
        num = int(num)
        piece=()
        for i in range(len(matrix33)):
            for j in range(len(matrix33[i])):
                if num == matrix33[i][j]:
                    piece = (i,j)
        return piece , num
    
    zero(matrix33)
    while game_start:
        draw_board(matrix33)      
        ask_number()         
        if num > 8:
            print('illegal move , try again  ')
        else:
            if(empty_space==(piece[0]-1,piece[1]))\
               or(empty_space==(piece[0]+1,piece[1]))\
               or(empty_space==(piece[0],piece[1]-1))\
               or(empty_space==(piece[0],piece[1]+1)):
                matrix33[empty_space[0]][empty_space[1]]=num
                matrix33[piece[0]][piece[1]]=0
                empty_space=(piece[0],piece[1])
                moves = moves +1
                print()
                print('you have made ',moves , 'moves so far ')
                print(2*'\n')
            else:
                print('illegal move , try again ')
    
```
CC BY-SA 4.0
2019-06-13T01:58:49.157
55736
2019-06-13T04:26:54.283
2019-06-13T02:12:52.047
34091
question
python アルゴリズム
シャッフルパズルゲームのシャッフルについて
８パズルの駒は偶奇性があって、ルール通りの動かし方をする限り偶数パリティな状態から奇数パリティな状態には絶対にならないことが証明されています。

別言語ですが参照。  
[８パズルで、最初にシャッフルさせる時の考え方](https://ja.stackoverflow.com/questions/48268/)
CC BY-SA 4.0
2019-06-13T02:15:17.870
55738
2019-06-13T02:15:17.870
8589
55736
answer
質問文のソースコードには「与えられた方向にコマを動かす」という部分の処理が既にあるので、ここを関数化した上で、「与えられた方向」をランダムに決めてコマを動かす処理を10回繰り返せば良さそうです。もちろんそのままだと動かせない場合があるので、動かせた場合だけ数えるようにします。

具体的には、ちょっと雑ですがたとえば下のように書けます。

```

    matrix33 = [[0, 1, 2], [3, 4, 5], [6, 7, 8]]
    empty_space = (0, 0)
    dir = [[-1, 0], [1, 0], [0, -1], [0, 1]]
    
    # matrix33[y][x] にあるコマを空白へ移動する関数。
    # 移動できたら True、できなかったら False を返す。
    def move(y, x):
        global empty_space, matrix33
        if x < 0 or x > 2 or y < 0 or y > 2:
            print('x and y should be between 0 and 2')
            sys.exit(1)
    
        # 動かせるかチェックする
        can_move = False
        for i in range(4):
            target = (y + dir[i][0], x + dir[i][1])
            if target == empty_space:
                can_move = True
                break
        if not can_move:
            return False
    
        # 動かす
        num = matrix33[y][x]
        matrix33[empty_space[0]][empty_space[1]] = num
        matrix33[y][x] = 0
        empty_space = (y, x)
        return True
    
    # n回シャッフルする関数。
    def shuffle():
        count = 0
        while count < n:
            x = random.randint(0, 2)
            y = random.randint(0, 2)
            ok = move(y, x)
            if ok:
                count = count + 1
    
    shuffle(10)
    
```

このように `move` 関数として機能を切り出すと、プレイヤーにコマを動かしてもらうところも下のように簡潔になります。

```

    if move(piece[0], piece[1]):
        moves = moves + 1
        print()
        print('you have made ', moves, 'moves so far.')
        print(2*'\n')
    else:
        print('illegal move, try again.')
    
```

以下おまけです。

  * 最初は `shuffle` 関数の引数として小さめの数を渡すとデバッグしやすいです。
  * もっと Python っぽく書くにはクラスを使いたいところですね。
  * ところで今のソースコードだと8パズルの1手を決める際「○番のコマを空白へ動かす」と考えていますが、逆に「空白部分を×方向に動かす」と考えることもできます。8パズルくらいだと前者の考え方でもシャッフルはたいてい高速に終わるので問題ありませんが、コマの数が増えてくると後者の方が「動かせない」状態に陥る確率が低く、シャッフルがすぐ終わるようになります。
CC BY-SA 4.0
2019-06-13T03:05:35.000
55740
2019-06-13T04:26:54.283
2019-06-13T04:26:54.283
19110
19110
55736
answer