英语单词学习应用
周五发布的文章Flask开发天气查询软件,带你掌握pipenv的使用与手机Termux下的部署发布后,看到喜欢的人比较多。本来周末打算照着扇贝/极光单词,写一个英语单词自测工具。但苦于单词的分类和数据没找到很细致的文档,所以这个内容往后延一下。
如果大家有英语单词、音标、翻译这种根据不同年级或等级分类的数据可以共享给我,开发完成大家一起学习背单词。
成语接龙
6月高考的前一天,我发布的一篇文章,决战高考,帮你秒变成语之王,当时只是吧网站的成语爬下来保存到数据库中,文末提到有机会了抽时间拿这些数据搞点事情,那么今天就来搞事情吧。用3W+的成语数据库,开发一款成语接龙的小游戏。
接龙规则
实现分析
数据库信息
先来看看我们的数据库信息:
数据库表idiom分为id,name,speak,meaning,example,hot 几个字段,hot是当时搜索的网站热词排行,跟咱们没有太大关系…主要是name和speak字段。
登陆排行
为了能增强可玩性,我们在每次开场前,允许用户随机输入一个名字。在挑战过程中,针对用户坚持的接龙次数进行排名。
创建用户排名表:
CREATE TABLE rank (
name VARCHAR (50) NOT NULL,
round_num INT NOT NULL
);
这里为什么不设置主键呢?
游戏界面
首先映入眼帘的是ROUND 1的接龙次数显示,有没有儿时拳皇对打的感觉…
为了帮助大家在玩游戏的同时能学习成语知识,也避免有些生僻字不认识,所以在界面中显示了成语、注音、解释和示例,当然示例不是每个成语都有,网站有啥我就展示啥呗…
成语判断
首先必须是四字的成语,用户输入非四字的成语会弹出警示栏,其次用户填写完成语后,会将成语在数据库中进行检索,如果是成语则进行接龙后返回电脑的匹配结果,进行第二轮的基隆,如果数据库中无此成语会弹出游戏结束的提示“挑战结束:用户输入的成语是自己编的吧!”,返回登陆页,并将用户的挑战结果入库rank表进行排行。
这里需要注意,成语接龙的收尾字可以不一样但音必须相同,包括声调哦!
拼音识别
数据库中的成语我们存在拼音了,但用户输入的是汉字,我们如何进行拼音转化呢?这里需要使用到python的一个模块pypinyin。针对这个模块的使用,之前写过一篇文章Python为文档批量注音(生僻字歌词为例),喜欢的朋友可以去看看。用法很简单,但我们需要做到和数据库中相对应才行。
from pypinyin import pinyin
pinyin('唇枪舌剑')
# output:
[['chún'], ['qiāng'], ['shé'], ['jiàn']]
# 此处为一个嵌套列表,我们需要转化为数据库中的格式
' '.join(map(lambda x: x[0], pinyin('唇枪舌剑')))
# output:
'chún qiāng shé jiàn'
代码编写
Jinjia2模板
大家看到不管是用户登录还是游戏界面,外框内容基本一致,基于这种场景使用Jinjia2的模板继承是个很不错的选择:
layout.html主要负责大体框架及相关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>清风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-欢迎关注我的公众号:<a href="https://www.jianshu.com/u/d23fd5012bed">清风Python</a>
</div>
</div>
</body>
</html>
login.html涉及到挑战者排行和用户名提交与页面跳转
{% 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">如果战绩足够出色,你的名字也将出现在下方!</span>
</div>
<div class="form-group table_show">
<table class="table table-hover table-bordered">
<thead>
<tr>
<th>排名</th>
<th>挑战者</th>
<th>对答次数</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主要负责成语接龙游戏的监控与AJAX数据的后台刷新。
{% 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("请填写四字成语...");
} 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数据库的交互,所以在每次请求前,需要建立数据库,请求结束后需要释放连接。此时我们需要使用到两个装饰器,@app.before_request和@app.teardown_request,before_request见名知意就是在请求访问前调动该装饰器,那么为什么不用对应的@app.after_request呢?因为即便用户代码在执行过程中,出现任何错误,也可以通过@app.teardown_request装饰器最终释放数据库连接,但@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': "挑战结束:用户输入的成语是自己编的吧!", 'url': request.host_url})
游戏演示
说了这么多,让我们来开一局:
我们使用一个Neo的新用户来进行游戏,随便接龙了几次,然后我编了一个“蝉鸣鸟叫”的成语结束这次演示,不然好好答不来个几百轮的那里能结束啊,哈哈…可以看到游戏结束后退回到首页,并进行了挑战排序。还好没几个号,不然排不到前五都看不到效果了…
手机搭建项目
既然上一篇的天气预报工程可以搭建到手机,那么这篇成语接龙,也一样来试试呗。
代码clone
代码我已经上传到了我的git仓库,手机登陆Termux直接clone下载即可:
git clone https://github.com/KingUranus/IdiomsGame.git
pipenv导入
进入clone好的代码路径,之后输入pipenv install创建虚拟环境并下载依赖的模块
键入pipenv shell 进入虚拟环境
通过flask run运行我们的Flask app程序…
The End
今天的Flask项目开发成语接龙游戏的文章,大家是否喜欢,如果觉得内容对你有所帮助,欢迎点击文章右下角的“在看”。
项目代码我都贴出来了,但是有些css和引用的js就没往出贴。如果大家想搭建app玩玩,可以从git上下载代码,或公众号回复成语接龙,自动获取代码的百度网盘地址。