vvonder's blog http://vvonderblog.appspot.com/ vvonder的技术博客 2010-07-30T08:27:34Z g.liwentao http://vvonderblog.appspot.com/entry/166001 使用Python编写扑克游戏(1) 一直想用Python语言编写一个有点规模的项目,却一直没有好点子。在玩过Windows下某个几乎全能的扑克游戏(Pk32),我决定也开发一个类似的,并且带联网游戏功能。

经过一番尝试后,我发现这还是有难度的,由于我个人没游戏开发经验,网络编程也刚入门,但是还是可以做下去的。下面是这两周来的开发经验总结。

开发资料:

相关资料挺难找,刚开始没头绪,只有一边写一边找了。暂时找到一篇有参考价值的:http://blog.csdn.net/realman1981/archive/2006/07/18/934011.aspx

开发环境:

开发语言和工具:Python+PyQt+Eric

管理工具:Google Code + SVN

既然是练习Python,还要编写网络和界面程序,当然选择之前熟悉的Eric作为开发调试工具。这次还在Google Code注册了个项目使用SVN来管理进度,项目地址:http://code.google.com/p/python-poker/

开发概要:

介绍:
    Python语言开发的网络扑克游戏
功能目标:
    *支持客户端和服务端的多人游戏
    *支持机器人(Bots)
    *支持定义游戏规则,包含子游戏
    *支持图形用户界面(计划PyQt)

开发进度:

开发近两周,版本到v0.2(r20),实现基本游戏框架,实现网络通信(待改进),实现简单命令行界面(仅可调试信息),实现一个简单游戏(跟花)的逻辑和AI(待改进),进入图形界面开发。

由于定位为敏捷开发,文档后行。文档方面只有游戏框架UML类图和简要说明,代码注释比较丰富,希望有兴趣的朋友能提出宝贵建议。

相关阅读:

本文网址:http://vvonderblog.appspot.com/2010/07/30/python-poker-game-1.html

]]>
None 2010-07-30T08:27:34Z
http://vvonderblog.appspot.com/entry/63001 PyQt编写Google翻译客户端程序 本文主要介绍使用eric开发环境和PyQt开发一个Google翻译客户端程序。

最终效果图:


所使用开发环境:

  • Windows XP/Linux
  • Python 2.6.4
  • eric4 4.3.10
  • PyQt4 4.5.3

开发步骤:

步骤一至四主要为eric的操作,我只贴图,详细可参考之前文章提供的参考资料

一.使用eric新建PyQt4工程gtranslate


二.工程中添加窗体,调用QT Designer设计主界面,保存为main.ui


三.编译窗体文件main.ui为Python代码Ui_main.py

四.工程中根据窗体文件生成代码main.py,代码将根据以上生成的Ui类派生,选择需要的信号槽


五.完善main.py,编写核心代码

主要原理:

  • Google翻译接口调用参见这里
  • 使用urllib、urllib2来连接网络
  • 使用Python2.6的json库来解析返回的json数据
  • 翻译模块派生自QT线程类QThread,基础的线程使用,防止界面失去响应

参考代码:

# -*- coding: utf-8 -*-

"""
Module implementing Dialog.
"""
import urllib
import urllib2
import sys
import json

from PyQt4 import QtGui, QtCore
from PyQt4.QtGui import QDialog
from PyQt4.QtCore import pyqtSignature, SIGNAL, QThread

from Ui_main import Ui_Dialog

class Dialog(QDialog, Ui_Dialog):
    """
    Main window
    """
    def __init__(self, parent = None):
        """
        Constructor
        """
        QDialog.__init__(self, parent)
        self.setupUi(self)
        
        lang=sorted(GTranslate.LANG.keys())
        self.cbOrigin.addItems(lang)
        self.cbOrigin.setCurrentIndex(lang.index('ENGLISH'))
        self.cbTarget.addItems(lang)
        self.cbTarget.setCurrentIndex(lang.index('CHINESE'))
    
    @pyqtSignature("")
    def on_btnTranslate_clicked(self):
        """
        Submit to google translate
        """
        text=self.tOrigin.toPlainText()
        text=unicode(text).encode('utf-8')
        key=str(self.cbOrigin.currentText())
        langOrigin=GTranslate.LANG[key]
        key=str(self.cbTarget.currentText())
        langTarget=GTranslate.LANG[key]
        
        self.gt=GTranslate(langOrigin, langTarget, text)
        self.connect(self.gt, SIGNAL("finished()"), self.showResult)
        
        self.gt.start()
        self.updateUi(False)
    
    @pyqtSignature("")
    def on_btnReset_clicked(self):
        """
        Reset the UI
        """
        self.gt.terminate()
        self.updateUi(True)
    
    def showResult(self):
        result=self.gt.result
        if(result):
            self.tTarget.setText(result)
        self.updateUi(True)
    
    def updateUi(self, enable):
        self.btnTranslate.setEnabled(enable)
        self.btnReset.setEnabled(not enable)

class GTranslate(QThread):
    
    def __init__(self, langOrigin='en', langTarget='zh', text=None, parent=None):
        QThread.__init__(self, parent)
        
        self.text=text
        self.langOrigin=langOrigin
        self.langTarget=langTarget
        self.result=None
    
    def translate(self):
        query = (GTranslate.URL % (urllib.quote(self.text), self.langOrigin, self.langTarget))
        req = urllib2.Request(query)
#        req.add_header("Referer", "http://www.my-ajax-site.com")
        try:
            r = urllib2.urlopen(req)
            data = r.read()
        except:
            self.result='Network Connect Error!'
            return
        
        obj = json.loads(data)
        if obj['responseStatus'] != 200L:
            self.result="Error: %s" % obj['responseDetails']
        else:
            self.result=obj['responseData']['translatedText']
    
    def run(self):
        self.translate()
    
    URL = "http://ajax.googleapis.com/ajax/services/language/translate?v=1.0&q=%s&langpair=%s%%7C%s"
    LANG={

      'AFRIKAANS' : 'af',
      'ALBANIAN' : 'sq',
      ...
      'UNKNOWN' : ''
    }

if __name__ == "__main__":
    app = QtGui.QApplication(sys.argv)
    main = Dialog()
    main.show()
    sys.exit(app.exec_())

六.测试、打包和发布

这里使用py2exe打包,以便发布在没有安装Python和PyQt的Windows环境下。打包脚本setup.py如下:

#!/usr/bin/env python
#coding=utf-8
from distutils.core import setup
import py2exe

setup(
    data_files=[
        #vc9 runtime
        'msvcr90.dll',
        'msvcp90.dll',
        'Microsoft.VC90.CRT.manifest',
    ],
    windows=['main.py'],
    options={
        "py2exe": {
            'includes': ['sip'],
            "compressed": True,
#            'bundle_files': 2,
        }
    }
)

注意最好连VS2008相关的库文件一起打包(Python2.6需要msvcr90.dll,PyQt4需要msvcp90.dll),我已将相关的文件放到源码目录,见打包脚本。

工程文件可到我的网盘下载:

工程源码py2exe打包版


相关阅读:

本文网址:http://vvonderblog.appspot.com/2009/12/23/pyqt-google-translate-client.html

]]>
None 2009-12-23T11:32:03Z
http://vvonderblog.appspot.com/entry/60004 学习PyQt之资料收集篇 一直想用简洁的Python语言做客户端界面开发,现在是时候了。之前研究过Python做GUI开发的库,比较流行的有Tkinter、 wxPython、PyGtk、PyQt等好几种。托Python福,几乎都可以跨平台。试用以上几种方案,感觉Tkinter简单,Python内置 但界面太丑且不够灵活;wxPython不错有不少ide支持,据说有类似MFC的结构,但我找的ide都不满意;PyGtk类似c风格,有单独的界面设 计器Glade帮助设计,可惜缺少ide支持且windows下界面有点另类;PyQt类库丰富,界面友好,有强大的ide:eric支持使得开发简便, 于是就选它了。

开始学习了。现在正在研究的主要参考书为《Prentice.Hall.Rapid.GUI.Programming.with.Python.and.Qt》,E文的讲得相当详细,后面有点难度,PDF版和配套源码可以到我的网盘下载

PyQt项目首页有丰富的学习资源,包括参考手册

另外有几篇网上的中文教程推荐:

http://hi.baidu.com/runningon/blog/item/115662279ff36a06918f9d0b.html  --eric4结合PyQt教程

http://www.cnitblog.com/addone/archive/2006/04/01/8469.aspx  --eric4结合PyQt教程,另一篇

http://code.google.com/p/pyqt-doc-cn/  --PyQt简介教程

http://www.czug.org/python/pyqt4/  --某PyQt教程的翻译

http://www.blogjava.net/glorywine/category/32060.html  --一系列PyQt教程

以上教程我已打包整理到网盘

相关阅读:

本文网址:http://vvonderblog.appspot.com/2009/12/22/learning-pyqt-about-resources.html

]]>
None 2009-12-22T10:58:51Z
http://vvonderblog.appspot.com/entry/53001 为micolog添加图形验证码 micolog带的算法验证码似乎太弱了,容易引来垃圾评论。我把它改成了图形验证码,并加入了session机制。图形验证码的实现来自SDBlog,使用的是pngcanvas库绘制;session实现来自gmemsess库,基于memcache。

原理是访客访问/checkimg/获得生成的图形验证码,同时服务器使用session保存验证码值,并在处理提交评论表单时检查。

先测试一下效果,代码以后再整理。

部分代码如下:

safecode.py,gmemsess.py,pngcanvas.py放到app目录

blog.py添加CheckImg类,并在主函数添加路径映射,用于生成验证码图片:

('/checkimg/', CheckImg),
from app.safecode import Image
from app.gmemsess import Session

class CheckImg(BaseRequestHandler):
    def get(self):
        img = Image()
        imgdata = img.create()
        sess=Session(self,timeout=180)
        if not sess.is_new():
            sess.invalidate()
            sess=Session(self,timeout=180)
        sess['code']=img.text
        sess.save()
        self.response.headers['Content-Type'] = "image/png"
        self.response.out.write(imgdata)

Post_comment主要修改如下,验证输入的验证码和session中的是否一致:

        sess=Session(self,timeout=180)
        if not self.is_login:
            if not (self.request.cookies.get('comment_user', '')):
                try:
                    logging.info(checkret)
                    logging.info(sess['code'])
                    if sess.is_new() or (int(checkret) != sess['code']):
                        sess.invalidate()
                        if useajax:
                            self.write(simplejson.dumps((False,-102,('Your check code is invalid .'))))
                        else:
                            self.error(-102,('Your check code is invalid .'))
                        return
                   
                except:
                    sess.invalidate()
                    if useajax:
                        self.write(simplejson.dumps((False,-102,('Your check code is invalid .'))))
                    else:
                        self.error(-102,('Your check code is invalid .'))
                    return
        sess.invalidate()

为了使验证码显示(默认首次访问检查验证码),可以点击这里清除cookie

相关阅读:

本文网址:http://vvonderblog.appspot.com/2009/11/25/add-micolog-image-checkcode.html

]]>
None 2009-11-25T11:16:26Z
http://vvonderblog.appspot.com/entry/50002 Python Web开发框架之web.py web.py是基于Python的小巧高效的Web开发框架,而且有成熟的应用,如果感到Django复杂,这个无疑是个好的入门学习的框架。

其主页:http://webpy.org/,用的人挺多,文档很丰富。

另外最近在免费的神龙主机上弄了个空间来搞了个web.py的简单应用:一个留言版程序guestbook,来演示一下web.py的简洁和强大。

源码如下,演示了web.py的路径映射、数据库访问、模板等功能。

业务逻辑模块view.py:

#!/usr/local/python2/bin/python
#coding:utf-8
import os, sys
#导入webpy包的路径(上上层目录,根据需要调整)
sys.path.append(os.path.abspath('../../'))

#避免URL重定向时出现脚本名
os.environ['REAL_SCRIPT_NAME'] = ""

import web

#URL映射
urls = (
    '/clear/?','clear',             #清空数据库
    '/guestbook/?','guestbook',     #留言本
    '/.*', 'index',                 #首页
)

app = web.application(urls, globals())

#模板放到当前路径templates目录
render = web.template.render('templates/')

#连接sqlite数据库,当前目录的guestbook.db
db = web.database(dbn='sqlite', db='guestbook.db')

class clear:
    def GET(self):
        #db.delete('comment')
        db.query('delete from comment')
        web.seeother('/guestbook')
       
class guestbook:
    def GET(self):
        comments=db.select('comment')
        return render.guestbook(comments)
       
    def POST(self):
        i=web.input()
        if i.author and i.content:
            db.insert('comment', author=i.author, content=i.content)
        web.seeother('/guestbook')
       
class index:
    def GET(self):
        web.seeother('/guestbook')

#fcgi运行时必需,需要flup服务器,本地运行不需要
web.wsgi.runwsgi = lambda func, addr=None: web.wsgi.runfcgi(func, addr)

if __name__ == "__main__":
    app.run()

模板文件guestbook.html(放到当前路径的templates目录):

$def with (comments)
<html>
<body>
    <form method="post" action="/guestbook">
    <p><input type="text" name="author" />author<br />
    <input type="text" name="content" />content<br />
    <input type="submit" value="Add" /></p>
    </form>
    <p>Comments:</p>
    <ul>
    $for comment in comments:
        <li>$comment.author: $comment.content</li>
    </ul>
</body>
</html>

数据库生成脚本initDB.py(执行生成guestbook.db):

#!/usr/local/python2/bin/python
#coding:utf-8
#import sqlite3
from pysqlite2 import dbapi2 as sqlite3 #神龙主机的sqlite3库

def initDB(con):
    cur = con.cursor()
    cur.execute("""
        create table comment(
        author varchar(20),
        content varchar(1000)
        )""")
    con.commit()

if __name__ == '__main__':
    initDB(sqlite3.connect("guestbook.db"))

将这些文件上传到神龙主机,当然先要在主机上部署好web.py框架(即上传web文件夹到某目录),并设置好URL重写脚本.htaccess即可访问了,我是放在根目录的webpy目录里。

.htaccess脚本:

RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ webpy/view.py/$1 [QSA,L]
DirectoryIndex webpy/view.py

演示地址:http://vv0nder.freebsdhost.org/

相关阅读:

本文网址:http://vvonderblog.appspot.com/2009/11/10/python-web-framework-webpy.html

]]>
None 2009-11-10T04:44:06Z
http://vvonderblog.appspot.com/entry/50001 迷你Python Web开发框架:Bottle 发现一个迷你的Python Web框架:Bottle,整个框架只有一个文件,几十K,却自带了路径映射、模板、简单的数据库访问等web框架组件,确实是个可用的框架。初学web开发可以拿来玩玩,其语法简单,部署也很方便,个人觉得文档还不够全面。

中文文档可参考网友的翻译:

译者的那个页面好像就是用Bottle框架的。

另外推荐篇Python Web开发的好文章,进一步理解Python Web框架:网站开发深入浅出Python篇

相关阅读:

本文网址:http://vvonderblog.appspot.com/2009/11/10/python-web-framework-bottle.html

]]>
None 2009-11-10T04:19:55Z
http://vvonderblog.appspot.com/entry/46073 Linux学习网站推荐 趁着新版Ubuntu发布的热潮,宣传一下Linux。

首先推荐个很好的Linux学习站点:

鸟哥的Linux私房菜:

主要介绍Linux系统管理方面的知识,很有技术含量,学完几乎成为Linux高手了。

这里还有简体离线版打包下载

下面介绍几个常去的Linux学习社区:

  • Ubuntu中文论坛 -- Ubuntu作为最流行的Linux发行版,其中文社区也成为了中文最火的Linux社区,这里气氛很好,是个Linux初学的好地方
  • LinuxSir社区 -- 国内比较有技术含量的Linux社区,面向各个主流Linux发行版
  • ChinaUnix社区 -- 也是不错的Linux技术社区,面向网络和系统管理

本文网址:http://vvonderblog.appspot.com/2009/11/1/linux-learning-website.html

]]>
None 2009-11-01T13:11:17Z
http://vvonderblog.appspot.com/entry/38001 简单的JavaScript分页导航 收集了一些分页导航脚本,主要用于前端页面美化,所以以JavaScript为主。

现在我博客用的简单脚本(来自互联网,有修改):

<script language="javascript">
    <!--
    function showPageLink(sUrl,iPage,iCount){
        var i;
        i=Math.max(1,iPage-1);
        if(iPage==1){
            document.write("<span style='color:#7D7D7D'>首页</span> ");
            document.write("<span style='color:#7D7D7D'>上一页</span> ");
        }
        else{
            document.write("<a href=\"" + sUrl + "1\" title='第 1 页'>首页</a> ");
            document.write("<a href=\"" + sUrl + i + "\" title='上一页(第 " + i + " 页)'>上一页</a> ");
        }
        if(iPage>6) document.write("<span>...</span> ");
        for(i=Math.max(1,iPage-5);i<iPage;i++){
            document.write("<a href=\""+sUrl + i + "\" title='第 " + i + " 页'><b>" + i + "</b></a> ");
        }
        document.write("<font color='red'><b>" + iPage + "</b></font> ");
        for(i=iPage+1;i<=Math.min(iCount,iPage+5);i++){
            document.write("<a href=\""+sUrl + i + "\" title='第 " + i + " 页'><b>" + i + "</b></a> ");
        }
        i=Math.min(iCount,iPage+1);
        if(iCount>iPage+5) document.write("<span>...</span> ");
        if(iPage==iCount){
            document.write("<span style='color:#7D7D7D'>下一页</span> ");
            document.write("<span style='color:#7D7D7D'>尾页</span> ");
        }
        else{
            document.write("<a href=\"" + sUrl + i + "\" title='下一页(第 " + i + " 页)'>下一页</a> ");
            document.write("<a href=\"" + sUrl + iCount + "\" title='最后一页(第 " + iCount + " 页)'>尾页</a> ");
        }
    }
    showPageLink("/page/",{{pageindex}},{{pagecount}});//记得按需要修改
    //-->
</script>

使用方法showPageLink("url格式",当前页码,总页码)


基于jQuery的插件

相关阅读:

本文网址:http://vvonderblog.appspot.com/2009/10/23/simple-javascript-page-navigation.html

]]>
None 2009-10-23T05:02:43Z
http://vvonderblog.appspot.com/entry/36002 使用Python编写简单Web服务器 发现用Python编写用于测试用的Web服务器非常简单,值得研究一下。

先研究一下SimpleHTTPServer模块,这个确实够简单:

不用代码的:

终端直接运行命令:python -m SimpleHTTPServer [端口]

两行代码的,保存为Python脚本执行:

import SimpleHTTPServer
SimpleHTTPServer.test() 

默认端口为8000,直接访问http://localhost:8000即可,根路径是运行命令或脚本的文件夹。

这个东西有个实用的功能是拿来共享文件Smile

以后再来点复杂的...

相关阅读:

本文网址:http://vvonderblog.appspot.com/2009/10/22/python-simple-web-server.html

]]>
None 2009-10-22T03:19:56Z
http://vvonderblog.appspot.com/entry/31031 推荐一个文本复制脚本zeroclipboard zeroclipboard是结合JavaScript和Flash的Web文本复制脚本,兼容多个浏览器和最新的Flash版本,使用简单。

项目地址http://code.google.com/p/zeroclipboard/

演示地址http://bowser.macminicolo.net/~jhuckaby/zeroclipboard/

使用简介

可参考开源的 JavaScript 复制库类 Zero Clipboard

本人在使用过程中发现它的示例在本地无法使用,而在服务器环境下没问题。有Python而一时没法架设服务器的朋友可以这样测试:

  • 打开终端,进入示例文件夹执行python -m SimpleHTTPServer
  • 在浏览器里访问http://localhost:8000/test.html即可访问测试页。

这也是快速利用Python架设Http测试服务器的方法。

已经弄到高亮代码页面,欢迎测试。

成功调用的代码(我把它放在Body标签里的最下面成功,要用到jQuery):

<script type="text/javascript" src="/static/ZeroClipboard/ZeroClipboard.js"></script>
<script type="text/javascript">
    ZeroClipboard.setMoviePath( '/static/ZeroClipboard/ZeroClipboard.swf' );
    function clipInit() {
        var clip = new ZeroClipboard.Client();
        clip.setHandCursor(true);
        clip.addEventListener('mouseOver', function(client){
            clip.setText(document.getElementById('code').value);
        });
        clip.addEventListener('complete', function(client,text){
            alert("成功复制代码到剪贴板!");
        });
clip.glue('copybtn');
    }
//jQuery onLoad
$(document).ready(function() {
    clipInit();
});
</script>

其中高亮部分依次是ZeroClipboard脚本地址、ZeroClipboard影片地址、待复制的文本框ID、复制控件ID(被ZeroClipboard覆盖),注意需要Flash支持。

为了兼容ie,使用了jQuery加载初始化代码,如果不想使用jQuery,需要在body标签属性里加入onload='clipInit'。

相关阅读:

本文网址:http://vvonderblog.appspot.com/2009/10/21/a-copy-to-clipboard-script.html

]]>
None 2009-10-21T15:42:40Z