---
# System prepended metadata

title: 'Projects : telegram上的踩地雷小遊戲'

---

# Projects : telegram上的踩地雷小遊戲
與telegram進行連結，並實作一個可以在telegram實際操作的踩地雷小遊戲

## 說明
### 輸入說明
-   `/start` 指令輸入欲產生盤面資訊。  
    第一個輸入數字為盤面的列 (row) 數  RR。  
    第二個輸入數字為盤面的行 (col) 數  CC。  
    第三個輸入數字為地雷總數  kk。  
    範例：`/start 10 10 8`  
    但只有輸入 `/start` 時，請內定  R=8R=8,  C=9C=9,  k=10k=10。  
    其餘狀況需顯示錯誤訊息，並套用前述內定值。
-   `/open` 指令輸入欲打開盤面之座標。  
    每對數字  m,nm,n 代表有一個地雷的座標為  (m,n)(m,n)， mm 為第幾列， nn 為第幾行，其中  mm 和  nn 都從  11 開始。  
    範例：`/open (8, 7)`  
    其餘狀況需顯示錯誤訊息，並套用前述內定值。
-   一名稱為 `重玩` 按鈕可重玩這一局（不重新 Random 地雷座標）。

### 輸出說明
產生  R×CR×C 的格子盤面，以`@`表示尚未挖出的地面，使用 `/open` 輸入座標，挖該區塊地雷，觸發以下狀況：

  留言

-   該區塊沒有地雷
    -   顯示以其為中心的周圍 8 格中，所有的地雷總數。如至少有一個，請顯示阿拉伯數字；否則顯示 `+` ，並挖周圍 8 格地雷，反覆到周圍有發現地雷為止。
    -   尚有未挖過的無地雷區塊：更新盤面。
    -   已沒有未挖過的安全區塊：結束遊戲，顯示遊戲勝利，並顯示完整盤面（包含地雷座標及數量）。
-   該區塊有地雷
    -   該區塊顯示`*`，結束遊戲，顯示遊戲失敗，並顯示完整盤面（包含地雷座標及數量）。

點擊一區塊可翻開：

-   如果是地雷，翻開所有地雷區塊，將他們改為`*`，並結束遊戲。
-   如果周圍的區塊均無地雷，則除了翻開該區塊外，繼續翻開周圍 8 個區塊。
-   如周圍 8 格 中有  ss 個地雷，則除了翻開該區域外，需顯示  ss 至該區塊上。

### 輸入規格
+ $8 \le R \le 15$
+ $8 \le C \le 15$
+ $0 \le k \le R\times C$
+ $1 \le m \le R$
+ $1 \le n \le C$
+ 多顆地雷不被放置在同一個格子

## 實作

### import 
```python=
import secret, random
from telegram import InlineKeyboardMarkup, InlineKeyboardButton
from telegram.ext import Updater, CommandHandler, MessageHandler, Filters
```
### 連接 telegram
```python=
updater = Updater(token=secret.access_token, use_context=True)
dispatcher = updater.dispatcher
```
### Define function
初始化場地
```python=
def init_board():
    global board #普通的版面
    global revealed  #翻開的版面
    board = [[0] * C for i in range(R)] 
    revealed = [[False] * C for i in range(R)]
    mines = random.sample([(x, y) for x in range(R) for y in range(C)], k)
    for x, y in mines:  #檢查周邊有幾個地雷
        board[x][y] = '*'
        for X in range(x-1, x+2):
            for Y in range(y-1, y+2):
                if 0 <= X < R and 0 <= Y < C and board[X][Y] != '*':
                    board[X][Y] += 1
    for X in range(0,R):
              for Y in range(0,C):
                        if board[X][Y] == 0:
                                  board[X][Y]='+' 
```

每回合show出目前的盤面
```python= 
def show_board(): 
    for board_row, revealed_row in zip(board, revealed):
        columns = [board_row[i] if revealed_row[i] else '@' for i in range(C)]
        print(*columns)
    # 以下部分不該顯示在遊戲畫面上
    # real_board()

```

每回合把目前的盤面給使用者看
```python=
def show_board(): 
    for board_row, revealed_row in zip(board, revealed):
        columns = [board_row[i] if revealed_row[i] else '@' for i in range(C)]
        print(*columns)
    # 以下部分不該顯示在遊戲畫面上
    # real_board()
```

實際的盤面(沒被遮蓋的)
```python= 
def real_board():
    print('real board:')
    for board_row, revealed_row in zip(board, revealed):
        columns = [board_row[i] for i in range(C)]
        print(*columns)
```

打開後會發生的事情
```python=
def open_cell(r, c):  #打開這個位置會發生的事情
    if r <= 0 or r > R or c <= 0 or c > C:
        return
    r, c = r-1, c-1
    if revealed[r][c]:  #如果翻開過的情況
        return
    #print(f'revealing row {r+1} col {c+1}')
    revealed[r][c] = True  
    if board[r][c] == '*':
        started = False
        print('爆啦~~~')
        for X in range(0, R):
                  for Y in range(0, C):
                            if board[X][Y] == "*":
                                      revealed[X][Y] = True    
        show_board() 
    elif board[r][c] == 0 :  #如果是0，則要翻開其他格子
        for i in range(r-1, r+2):
            for j in range(c-1, c+2):
                open_cell(i+1, j+1)
    #print(f'open_cell({r + 1}, {c + 1}) is done.')
```

給予參數，並開始遊戲
```python=
R,C,k = 8, 9, 10
init_board()
```

---
定義開始遊戲的情況，以下的function為實際在telegram操作上的情形
```python=
def start(update, context):
           tokens = update.message.text[7:].split()
           if len(tokens) == 0:
                     global R
                     global C
                     global k
                     global sum
                     R, C, k = 8, 9, 10

                  
           elif len(tokens) == 3 and all(x.isdigit() for x in tokens[0:]):   #如果使用者有指定數字
                  R, C, k = [int(x) for x in tokens[0:]]
                  if R < 8 or R > 15 or C < 8 or C > 15 or k < 0 or k > R * C:   #規定各數字範圍
                    R, C, k = 8, 9, 10
                    context.bot.send_message(
                    chat_id=update.effective_chat.id, text="數字超出規定範圍"
                    )
                           
           else:
                R, C, k = 8, 9, 10
                context.bot.send_message(
                chat_id=update.effective_chat.id, text="你亂打!"
                )
           global board
           global revealed
           board = [[0] * C for i in range(R)]
           revealed = [[False] * C for i in range(R)]
           mines = random.sample([(x, y) for x in range(R) for y in range(C)], k)
           for x, y in mines:
                     board[x][y] = '*'
                     for X in range (x-1, x+2):
                               for Y in range (y-1, y+2):
                                         if 0 <= X < R and 0 <= Y < C and board[X][Y] != '*':
                                                   board[X][Y] += 1
           for board_row, revealed_row in zip(board, revealed):
                columns = [board_row[i] for i in range(C)]
                str1 = "".join([str(_) for _ in columns])
                context.bot.send_message(
                chat_id=update.effective_chat.id, text=str1
                )
          
           context.bot.send_message(
           chat_id=update.effective_chat.id, text="上面是答案啦哈哈，不要偷看(demo方便)"
          )

           for board_row, revealed_row in zip(board, revealed):
                columns = [board_row[i] if revealed_row[i] else '@' for i in range(C)]
                str1 = "".join([str(_) for _ in columns])
                context.bot.send_message(
                chat_id=update.effective_chat.id, text=str1
                )
          
           context.bot.send_message(
           chat_id=update.effective_chat.id, text="請輸入/open (x,y) 代表想開的座標點"
           )
```

在telegram輸入想打開的座標後會發生的情形
```python=
def open(update, context):
          if update.message.text == "/open" :
                context.bot.send_message(
                chat_id=update.effective_chat.id, text="座標呢..."
                    )
                
          r, c = eval(update.message.text[6:])
          if board[r-1][c-1] == '*':   #如果爆了
                    open_cell(r,c)
                    context.bot.send_message(
                    chat_id=update.effective_chat.id, text="爆了..."
                    )
                    for board_row, revealed_row in zip(board, revealed):
                          columns = [board_row[i] if revealed_row[i] else '@' for i in range(C)]
                          str1 = "".join([str(_) for _ in columns])
                          context.bot.send_message(
                          chat_id=update.effective_chat.id, text=str1
                          )
                    quit()
          open_cell(r, c)
          for board_row, revealed_row in zip(board, revealed):
                    columns = [board_row[i] if revealed_row[i] else '@' for i in range(C)]
                    str1 = "".join([str(_) for _ in columns])
                    context.bot.send_message(
                    chat_id=update.effective_chat.id, text=str1
                    )
          sum = 0
          for X in range(0, R):
                    for Y in range(0,C):
                              if revealed[X][Y] == True:
                                        sum = sum + 1
          if sum == R*C - k:  #全部找完了
                    context.bot.send_message(
                    chat_id=update.effective_chat.id, text="太屌了吧..."
                    )
                    for board_row, revealed_row in zip(board, revealed):
                               columns = [board_row[i] for i in range(C)]
                               str1 = "".join([str(_) for _ in columns])
                               context.bot.send_message(
                               chat_id=update.effective_chat.id, text=str1
                               )
          
```

在telegram上想重玩一遍
```python=
def replay(update, context):   
          revealed = [[False] * C for i in range(R)]
          for board_row, revealed_row in zip(board, revealed):
                    columns = [board_row[i] if revealed_row[i] else '@' for i in range(C)]
                    str1 = "".join([str(_) for _ in columns])
                    context.bot.send_message(
                    chat_id=update.effective_chat.id, text=str1
                    )
```

防呆
```pyyhon=
def remind(update, context):
    context.bot.send_message(
        chat_id=update.effective_chat.id, text="你在幹嘛== 請輸入 /start, /open or /replay")
```

開始在telegrame上進行遊戲
```python=
start_handler = CommandHandler('start', start)
dispatcher.add_handler(start_handler)

open_handler = CommandHandler('open', open)
dispatcher.add_handler(open_handler)

replay_handler = CommandHandler('replay', replay)
dispatcher.add_handler(replay_handler)

repeat_handler = MessageHandler(Filters.text & (~Filters.command), remind)
dispatcher.add_handler(repeat_handler)



updater.start_polling()
```