# 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()
```