我用Python寫了一個成語接龍的游戲,并把它部署到了手機上
成語大全數(shù)據(jù)
6月高考的前一天比伏,我發(fā)布的一篇文章胜卤,決戰(zhàn)高考,幫你秒變成語之王赁项,當(dāng)時只是把 http://chengyu.haoshiwen.org/ 網(wǎng)站的3W+條成語爬下來保存到數(shù)據(jù)庫中葛躏。
文末提到有機會抽時間拿這些數(shù)據(jù)搞點事情澈段,但這事兒一直就這么放著了。
今天我們就來用3W+的成語數(shù)據(jù)庫舰攒,開發(fā)一款成語接龍的小游戲败富。
接龍規(guī)則
成語接龍是中華民族傳統(tǒng)的文字游戲。它不僅有著悠久的歷史和廣泛的社會基礎(chǔ)摩窃,同時還是體現(xiàn)我國文字兽叮、文化、文明的一個縮影猾愿,是老少皆宜的民間文化娛樂活動鹦聪。
成語接龍規(guī)則多樣,大家一般熟知的是采用成語字頭與字尾相連不斷延伸的方法進(jìn)行接龍蒂秘;用四個字成語的最后一個字與下一句成語的第一個相同的字【音同就可以】泽本,首尾相接不斷延伸,形成長龍姻僧。
數(shù)據(jù)庫信息
先來看看我們的數(shù)據(jù)庫信息:
數(shù)據(jù)庫表idiom分為id,name,speak,meaning,example,hot 幾個字段规丽,hot是當(dāng)時搜索的網(wǎng)站熱詞排行,跟咱們沒有太大關(guān)系...主要是name和speak字段撇贺。
登陸排行
為了能增強可玩性嘁捷,我們在每次開場前,允許用戶隨機輸入一個名字显熏。在挑戰(zhàn)過程中,針對用戶堅持的接龍次數(shù)進(jìn)行排名晒屎。
創(chuàng)建用戶排名表:
CREATE TABLE rank (
name VARCHAR (50) NOT NULL,
round_num INT NOT NULL
);
這里為什么不設(shè)置主鍵呢喘蟆?主要是排名取前5,用戶使用一個名字多次參戰(zhàn)鼓鲁,如果犀利的話包攬前5看這也很帥氣啊蕴轨,清一色的都是我,想想都覺得自我滿足感爆棚骇吭。
游戲界面
首先映入眼簾的是ROUND 1的接龍次數(shù)顯示橙弱,有沒有兒時拳皇對打的感覺...
為了幫助大家在玩游戲的同時能學(xué)習(xí)成語知識,也避免有些生僻字不認(rèn)識燥狰,所以在界面中顯示了成語棘脐、注音、解釋和示例龙致,當(dāng)然示例不是每個成語都有蛀缝,網(wǎng)站有啥我就展示啥唄...
成語判斷
首先必須是四字的成語,用戶輸入非四字的成語會彈出警示欄目代,其次用戶填寫完成語后屈梁,會將成語在數(shù)據(jù)庫中進(jìn)行檢索嗤练,如果是成語則進(jìn)行接龍后返回電腦的匹配結(jié)果,進(jìn)行第二輪的基隆在讶,如果數(shù)據(jù)庫中無此成語會彈出游戲結(jié)束的提示“ 挑戰(zhàn)結(jié)束:用戶輸入的成語是自己編的吧煞抬! ”,返回登陸頁构哺,并將用戶的挑戰(zhàn)結(jié)果入庫rank表進(jìn)行排行革答。
這里需要注意,成語接龍的收尾字可以不一樣但音必須相同遮婶,包括 聲調(diào) 哦蝗碎!
拼音識別
數(shù)據(jù)庫中的成語我們存在拼音了,但用戶輸入的是漢字旗扑,我們?nèi)绾芜M(jìn)行拼音轉(zhuǎn)化呢蹦骑?這里需要使用到python的一個模塊pypinyin。針對這個模塊的使用臀防,之前寫過一篇文章Python為文檔批量注音(生僻字歌詞為例)眠菇,喜歡的朋友可以去看看。用法很簡單,但我們需要做到和數(shù)據(jù)庫中相對應(yīng)才行袱衷。
from pypinyin import pinyin
pinyin('唇槍舌劍')
# output:
[['chún'], ['qiāng'], ['shé'], ['jiàn']]
# 此處為一個嵌套列表捎废,我們需要轉(zhuǎn)化為數(shù)據(jù)庫中的格式
' '.join(map(lambda x: x[0], pinyin('唇槍舌劍')))
# output:
'chún qiāng shé jiàn'
Jinjia2模板
大家看到不管是用戶登錄還是游戲界面,外框內(nèi)容基本一致致燥,基于這種場景使用Jinjia2的模板繼承是個很不錯的選擇:
layout.html主要負(fù)責(zé)大體框架及相關(guān)css和js的引入工作
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1 ,user-scalable=no">
<title>清風(fēng)python</title>
<link rel="icon" href="{{ url_for('static',filename='favicon.ico') }}">
<link rel="stylesheet" href="{{ url_for('static',filename='css/bootstrap.min.css') }}">
<link rel="stylesheet" href="{{ url_for('static',filename='css/main.css') }}">
<script src="{{ url_for('static',filename='js/jquery.min.js') }}"></script>
</head>
<body>
<div class="container container-small">
<div class="content">
<div class="header">
成語接龍
</div>
<div class="block-info">
{% block contents %}
{% endblock %}
</div>
</div>
<div class="footer">
?2019-歡迎關(guān)注我的公眾號:<a href="http://www.reibang.com/u/d23fd5012bed">清風(fēng)Python</a>
</div>
</div>
</body>
</html>
login.html涉及到挑戰(zhàn)者排行和用戶名提交與頁面跳轉(zhuǎn)
{% extends "layout.html"%}
{% block contents %}
<form method="post">
<div class="form-group has-success">
<div class="input-group">
<div class="input-group-addon">
選手姓名:
</div>
<input id='name' name="name" class="form-control" required autofocus>
</div>
</div>
<div class="form-group ">
<button type="submit" class="form-control btn-primary" id="load">火前留名</button>
</div>
</form>
<div class="form-group ">
<span class="label label-info">如果戰(zhàn)績足夠出色登疗,你的名字也將出現(xiàn)在下方!</span>
</div>
<div class="form-group table_show">
<table class="table table-hover table-bordered">
<thead>
<tr>
<th>排名</th>
<th>挑戰(zhàn)者</th>
<th>對答次數(shù)</th>
</tr>
</thead>
<tbody>
{% if rank_list|length %}
{% for rank in rank_list %}
<tr>
<th scope="row">{{ loop.index }}</th>
<td>{{rank.name}}</td>
<td>{{rank.round_num}}</td>
</tr>
{% endfor %}
{% endif %}
</tbody>
</table>
</div>
{% endblock %}
game.html主要負(fù)責(zé)成語接龍游戲的監(jiān)控與AJAX數(shù)據(jù)的后臺刷新嫌蚤。
{% extends "layout.html"%}
{% block contents %}
<div class="form-group has-success">
<h3 id='round_num' class="round_num">ROUND 1</h3>
</div>
<div class="form-group rank">
<table class="table table-hover table-bordered table_show table-condensed">
<tbody>
<tr>
<th>成語</th>
<td id="idiom_name"> {{idiom.name}} ({{idiom.speak}})</td>
</tr>
<tr>
<th>解釋</th>
<td id="idiom_meaning">{{idiom.meaning}}</td>
</tr>
<tr>
<th>示例</th>
<td id="idiom_example"> {{idiom.example}}</td>
</tr>
</tbody>
</table>
</div>
<div class="form-group has-success">
<div class="input-group">
<div class="input-group-addon" required autofocus>
成語:
</div>
<input id='user_idiom' class="form-control">
</div>
</div>
<div class="form-group ">
<button class="form-control btn-primary" id="load">用戶:{{user}} 作答</button>
</div>
<script type="text/javascript">
$(function () {
$('#load').click(function () {
let user_idiom = $('#user_idiom').val();
if (user_idiom.length != 4) {
alert("請?zhí)顚懰淖殖烧Z...");
} else {
$.ajax({
url: '/more/' + user_idiom,
type: 'get',
success: function (data) {
$('.result').html(data);
if (data['code'] == 200) {
$('#round_num').html('ROUND ' + data['round']);
$('#idiom_name').html(data['info']['name'] + ' (' + data['info']['speak'] + ')');
$('#idiom_meaning').html(data['info']['meaning']);
$('#example').html('ROUND ' + data['info']['example']);
} else {
alert(data['error']);
$(location).attr('href', data['url']);
}
}
})
}
})
})
</script>
{% endblock %}
Flask裝飾器
首先辐益,我們的游戲涉及到SQLite數(shù)據(jù)庫的交互,所以在每次請求前脱吱,需要建立數(shù)據(jù)庫智政,請求結(jié)束后需要釋放連接。此時我們需要使用到兩個裝飾器箱蝠,@app.before_request和@app.teardown_request续捂,before_request見名知意就是在請求訪問前調(diào)動該裝飾器,那么為什么不用對應(yīng)的@app.after_request呢宦搬?因為即便用戶代碼在執(zhí)行過程中牙瓢,出現(xiàn)任何錯誤,也可以通過@app.teardown_request裝飾器最終釋放數(shù)據(jù)庫連接床三,但@app.after_request可不行...
Flask整體代碼如下:
import sqlite3
from flask import Flask, render_template, request, g, session, redirect, url_for, jsonify
import random
from pypinyin import pinyin
app = Flask(__name__)
DATABASE = 'static/db/database.db'
app.secret_key = 'Breeze Python'
def connect_db():
return sqlite3.connect(DATABASE)
@app.before_request
def before_request():
g.db = connect_db()
@app.teardown_request
def teardown_request(exception):
if hasattr(g, 'db'):
g.db.close()
def query_db(query, args=(), one=True):
cur = g.db.execute(query, args)
rv = [dict((cur.description[idx][0], value)
for idx, value in enumerate(row)) for row in cur.fetchall()]
if not query.startswith('select'):
g.db.commit()
return (rv[0] if rv else None) if one else rv
@app.route('/', methods=['GET', 'POST'])
def index():
if request.method == 'POST':
user = request.form.get('name')
session['user'] = user
session['round'] = 1
return redirect(url_for('game'))
rank_list = query_db('select * from rank order by round_num desc limit 5',one=False)
print(rank_list)
return render_template('login.html', rank_list=rank_list)
@app.route('/game')
def game():
if not session.get('user'):
return redirect(url_for('index'))
id = random.randint(1, 30000)
idiom = query_db('select * from idiom where id = ?',
[id])
return render_template('game.html', user=session.get('user'), idiom=idiom)
@app.route('/more/<user_idiom>')
def more(user_idiom):
speak_list = pinyin(user_idiom)
print(speak_list[0][-1])
idiom_speak = ' '.join(map(lambda x: x[0], speak_list))
if query_db('select * from idiom where speak = ?',
[idiom_speak]):
new_idiom = query_db("select * from idiom where speak like ('%s%%')" % speak_list[-1][0])
session['round'] = session.get('round') + 1
print({'code': 200, 'round': session.get('round'), 'info': new_idiom})
return jsonify({'code': 200, 'round': session.get('round') + 1, 'info': new_idiom})
else:
query_db('replace into rank (name,round_num) values (?,?)',
[session.get('user'), session.get('round')])
return jsonify({'code': 404, 'error': "挑戰(zhàn)結(jié)束:用戶輸入的成語是自己編的吧一罩!", 'url': request.host_url})
游戲演示
說了這么多,讓我們來開一局:
我們使用一個Neo的新用戶來進(jìn)行游戲撇簿,隨便接龍了幾次聂渊,然后我編了一個“蟬鳴鳥叫”的成語結(jié)束這次演示差购,不然好好答不來個幾百輪的那里能結(jié)束啊,哈哈...可以看到游戲結(jié)束后退回到首頁汉嗽,并進(jìn)行了挑戰(zhàn)排序欲逃。還好沒幾個號,不然排不到前五都看不到效果了...
手機搭建項目
既然上一篇的天氣預(yù)報工程可以搭建到手機饼暑,那么這篇成語接龍稳析,也一樣來試試唄。
代碼clone
代碼我已經(jīng)上傳到了我的git倉庫弓叛,手機登陸Termux直接clone下載即可:
git clone https://github.com/KingUranus/IdiomsGame.git
pipenv導(dǎo)入
進(jìn)入clone好的代碼路徑彰居,之后輸入pipenv install創(chuàng)建虛擬環(huán)境并下載依賴的模塊
鍵入pipenv shell 進(jìn)入虛擬環(huán)境
通過flask run運行我們的Flask app程序...
The End
期待你關(guān)注我的公眾號清風(fēng)Python
,如果你覺得不錯撰筷,希望能動動手指轉(zhuǎn)發(fā)給你身邊的朋友們陈惰。
我的github地址:https://github.com/BreezePython