tinytwitterとかいうpythonの薄ーいラッパー

作ってみたんだけどuserstreamをjson.loadsするとエラーが・・・。そのまま表示することはできるんだけどなぁ。

とりあえず、使い方だけ書いておきます。dictで返すのでpymongoとかと一緒に使うには相性がいいかも。
import tinytwitter as twitter

consumer_key = 'your-consumer-key'
consumer_secret = 'your-consumer-secret'
token_key = 'token-key'
token_secret = 'token-secret'

auth = twitter.OAuth(consumer_key, consumer_secret, token_key, token_secret)
api = twitter.Api(auth)

api.fetch('http://api.twitter.com/1/statuses/update.json', 'POST', status='test')

def print_tweet(tweet):
try:
if tweet[u'user'][u'lang'] == 'ja':
print tweet['text']
except:
print 'error'

api.stream('http://stream.twitter.com/1/statuses/sample.json', 'GET', print_tweet)

追記(4/22):
ちょっとメソッド(get, post, put, delete)を追加しました。fetchをラップするかんじのもので、メソッド(インターネットのほう)を文字列で指定するのは面倒かなと思って追加しました。ちなみにstreamはそのままです。

あと、いい忘れていたんだけど、oauth2というライブラリが必要なのでpip install oauth2とかしてください。

あ、あと、使い方
#post a new tweet
status = api.post(tw.STATUSES_UPDATE, status='message')

#show home timeline
for tweet in api.get(tw.STATUSES_HOME_TIMELINE):
print tweet['text']

#delete a tweet
api.post(tw.STATUSES_DESTROY % status['id'])

#create a new list
list = api.post(tw.USER_LISTS % status['user']['screen_name'], name='foo')

#delete a list
api.delete(tw.USER_LISTS_ID % (status['user']['screen_name'], list['id']))

ソース:
ukyo/tinytwitter at master - GitHub
posted by 右京 | Python

pythonでプロキシサーバー越しにアクセスするプログラムをつくる

python→プロキシサーバー→twitterAPIのようにアクセスする方法。
$ export http_proxy='http://hoge.proxy.com:8080'
$ python hoge.py

こんな感じだね。
posted by 右京 | Python

GAEでカウンターつくるとしたら

こんなかんじかな?まぁ、試してもいないんですが。

class CounterPage(webapp.RequestHandler):

def get(self, name):
id = name.split("\.")[0]
counter = Counter.get_by_id(int(id))
counter_image = CounterImage.all().get(1)
counter.n += 1
_n = counter.n
numbers = []
for i in range(10):
numbers.append(_n % 10)
_n /= 10
inputs = [(
images.crop(counter_image.image,
left_x=i*0.1,
top_x=0,
right_x=i*0.1+0.1,
bottom_x=1,
output_encoding=images.JPEG),
i*NUMBER_WIDTH,
0,
1.0,
images.TOP_LEFT
) for i in numbers.reverse()]
self.response.headers['Content-Type'] = 'image/jpeg'
self.response.out.write(images.composite(inputs,
width=COUNTER_WIDTH,
height=COUNTER_HEIGHT,
output_encoding=images.JPEG))
counter.put()
posted by 右京 | Python

Yahoo!テキスト解析APIのPythonラッパー全部

係り受け解析だけしか作ってなかったのが全部そろってしまったよ。

一応、jsonで吐き出すよ。
GAEでも動くはず、試してないけど。

パラメーターとかの詳細は
http://developer.yahoo.co.jp/webapi/jlp/

ソースは
http://github.com/ukyo/pyahooapis

pypiにも一応upしておいたので、何が起きても怒らない人だけ使ってください(今のところエラー対策なしなので)。
posted by 右京 | Python

Yahoo日本語係り受け解析APIのPythonラッパー

こんなかんじです。

da = DAService(appid)
for chunk in da.getChunkList('うちの庭には二羽鶏がいます。'):
print chunk, "->", chunk.dependenceChunk

うちの -> 庭には
庭には -> います。
二羽鶏が -> います。
います。 -> None


ソースコード:
daservice.py
posted by 右京 | Python

[GAE][Python]MemcacheList

[Python]Pythonで排他制御を行ってくれるデコレーターがかなり便利

このデコレーターを使用してmemcache上でlistを管理するクラスを作ってみた。何個もメソッドがある場合は、やはり便利。
import threading

from google.appengine.api import memcache

from synchronized import synchronized


lock = threading.Lock()

class MemcacheList(threading.Thread):
def __init__(self, memcache_key):
threading.Thread.__init__(self)
self.memcache_key = memcache_key

def __iter__(self):
return (l for l in self())

def __len__(self):
return len(self())

def __call__(self):
return memcache.get(self.memcache_key) or []

def set(self, list):
memcache.set(self.memcache_key, list)

@synchronized(lock)
def append(self, object):
list = self()
list.append(object)
self.set(list)

@synchronized(lock)
def remove(self, value):
list = self()
list.remove(value)
self.set(list)

def index(self, value):
return self().index(value)

@synchronized(lock)
def pop(self, index=None):
list = self()
value = list.pop() if index is None else list.pop(index)
self.set(list)
return value

def count(self, object):
return self().count(object)

@synchronized(lock)
def extend(self, list):
list_ = self()
list_.extend(list)
self.set(list_)

@synchronized(lock)
def insert(self, index, object):
list = self()
list.insert(index, object)
self.set(list)

def reverse(self):
return self().reverse()


で、実際はこんな感じで使ってる。とりあえずチャットとか作るときに便利だよ、多分。
members = MemcacheList("members")

members.append("yui")
members.append("azunyan")
members.append("mugi")
members.append("ritu")
members.append("mio")

for member in members: print member
posted by 右京 | Python

[Python]Pythonで排他制御を行ってくれるデコレーターがかなり便利

「python synchronized decorator」でググったらこんなのが見つかった。
http://code.activestate.com/recipes/465057-basic-synchronization-decorator/

これはpythonの面倒臭い排他制御がデコレーターで簡単に書けるようになるってもの。

例えば、普通に排他制御を書くとこんな感じだが、
from threading import Thread, Lock

lock = Lock()

class Hoge(Thread):
def __init__(self):
Thread.__init__(self)

def run(self):
lock.acquire()
try:
print 'hoge'
finally:
lock.release()


このデコレーターを使うと以下のようにかなり短く書ける。これは便利だね。
from threading import Thread, Lock

lock = Lock()

class Hoge(Thread):
def __init__(self):
Thread.__init__(self)

@synchronized(lock)
def run(self):
print 'hoge'
posted by 右京 | Python

[GAE]Channel APIを使用したチャットプログラム(Comet)

Channel APIの使用例。実際の環境だと何か登録しなくてはいけないらしい。開発環境だと動きます。

2010/10/06
・ちょっと修正しました。

・githubにアップしました。
http://github.com/ukyo/cometchat/

とりあえず使えます(dev_appserver.pyにパスが通っていること前提)
git clone git://github.com/ukyo/cometchat.git
cd cometchat
dev_appserver.py src/


流れは
1.名前を送る(js側)
2.入室している人のリストに名前とそれに対応するuuidを登録(py側)
3.uuidからchannel_tokenを取得(py側)
4.channel_tokenからchannelを作って色々する。(js側)
5.何かあったらリストのメンバー全員にpush(py側)

uuidでchannel_tokenを作る理由は、日本語が入るとなんだか調子が悪いから。encodeURIComponentしてもダメだから、やっぱりダメなんじゃないかな。


SafeThreadRequestHandlerに関しては以下参照。
http://hujimi.seesaa.net/article/164473267.html


main.py
#coding: utf-8

from google.appengine.ext.webapp.util import run_wsgi_app
from google.appengine.ext import webapp

from cometchat import *

application = webapp.WSGIApplication([
('/cometchat', CometChatMainPage),
('/cometchat/post', PostCommentPage),
('/cometchat/enter', EnterPage),
('/cometchat/out', OutPage),
('/cometchat/connected', ConnectedPage),
('/cometchat/members', MembersPage),
('/cometchat/token', GetChannelTokenPage),
], debug=True)


def main():
run_wsgi_app(application)

if __name__ == "__main__":
main()


cometchat.py
#coding: utf-8

import cgi
import uuid

from google.appengine.ext import webapp
from google.appengine.api import memcache, channel
from django.utils import simplejson as json

from utils import SafeThreadRequestHandler

MEMCACHE_CHAT_KEY = 'cometchat'
MAX_LENGTH = 1000

TEMPLATE_HTML = u'''
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">

<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<title>Simple Ajax Chat(Comet)</title>
<link href="/css/chat.css" rel="stylesheet" type="text/css" />
<script type="text/javascript" src="/js/jquery-1.4.1.min.js"></script>
<script type="text/javascript" src='/_ah/channel/jsapi'></script>
<script type="text/javascript" src="/js/cometchat.js"></script>
</head>
<body>
<div id="container">
<div id="screen">
<h1>Simple Ajax Chat(Comet)</h1>
<div id="content">
<div id="form">
<label>Name</label><input type="text" id="name" maxlength="10">
<button id="submit">submit</button><span id="error"></span>
</div>
<div id="members">
<h2>Members</h2>
<ul></ul>
</div>
<div id="chat">
<h2>Comments</h2>
<ul></ul>
</div>
</div>
</div>
</div>
</body>
</html>
'''


def get_members():
'''memcacheから入室しているメンバーを取得'''
members = memcache.get(MEMCACHE_CHAT_KEY + "members")
if members is None:
members = []
return members

def get_comments():
'''memcacheからコメントを取得'''
comments = memcache.get(MEMCACHE_CHAT_KEY)
if comments is None:
comments = []
return comments

def get_uuids():
'''memcacheからuuidを取得'''
uuids = memcache.get(MEMCACHE_CHAT_KEY + "uuid")
if uuids is None:
uuids = []
return uuids

def broadcast_message(message):
'''各メンバーにpush'''
result = json.dumps(message)
for id in get_uuids():
channel.send_message(id, result)


class CometChatMainPage(SafeThreadRequestHandler):
'''メインページ'''
def get(self):
self.response.out.write(TEMPLATE_HTML)


class MembersPage(webapp.RequestHandler):
'''入室しているメンバーを取得'''
def get(self):
self.response.out.write(json.dumps(get_members()))


class EnterPage(SafeThreadRequestHandler):
'''入室したときの処理'''
def get(self):
self.post()

def post(self):
name = cgi.escape(self.request.get("name"))

self.mutex.acquire()
comment = {
"name": "chat system",
"text": name + u"さんが入室しました。"
}
comments = get_comments()
comments.append(comment)
if len(comments) > MAX_LENGTH: comments.pop(0)
memcache.set(MEMCACHE_CHAT_KEY, comments)
self.mutex.release()

broadcast_message({"members": get_members(),
"comments": [comment]})


class OutPage(SafeThreadRequestHandler):
'''退室したときの処理'''
def post(self):
name = cgi.escape(self.request.get("name"))

self.mutex.acquire()
members = get_members()
uuids = get_uuids()
try:
index = members.index(name)
members.remove(name)
uuids.pop(index)
memcache.set(MEMCACHE_CHAT_KEY + "members", members)
memcache.set(MEMCACHE_CHAT_KEY + "uuid", uuids)
except:
pass
comment = {
"name": "chat system",
"text": name + u"さんが退室しました。"
}
comments = get_comments()
comments.append(comment)
if len(comments) > MAX_LENGTH: comments.pop(0)
memcache.set(MEMCACHE_CHAT_KEY, comments)
self.mutex.release()

broadcast_message({"members": members,
"comments": [comment]})


class ConnectedPage(webapp.RequestHandler):
'''すでにあるコメントとかを取得。'''
def get(self):
self.response.out.write(json.dumps({"members": get_members(),
"comments": get_comments()}))


class GetChannelTokenPage(SafeThreadRequestHandler):
'''Channel Tokenを取得する。これがないとCometできない。'''
def post(self):
name = cgi.escape(self.request.get("name"))

self.mutex.acquire()
members = get_members()
members.append(name)
uuids = get_uuids()
uuid_ = str(uuid.uuid4())
uuids.append(uuid_)
memcache.set(MEMCACHE_CHAT_KEY + "members", members)
memcache.set(MEMCACHE_CHAT_KEY + "uuid", uuids)
self.mutex.release()

self.response.out.write(channel.create_channel(uuid_))


class PostCommentPage(SafeThreadRequestHandler):
'''コメント投稿'''
def post(self):
name = cgi.escape(self.request.get("name"))
text = cgi.escape(self.request.get("text"))

self.mutex.acquire()
comment = {
"name": name,
"text": text
}
comments = get_comments()
comments.append(comment)
if len(comments) > MAX_LENGTH: comments.pop(0)
memcache.set(MEMCACHE_CHAT_KEY, comments)
self.mutex.release()

broadcast_message({"members": get_members(),
"comments": [comment]})


cometchat.js
$(document).ready(function(){
var name;
var pushUnloadButton = false;
var members = [];

var postComment = function(){
var text = $("#text").val();
$.post('/cometchat/post', {name:name, text:text});
$("#text").val('').get(0).focus();
};

var getMembers = function(){
$.getJSON('/cometchat/members', function(json){
showMembers(members = json);
});
};

var showMembers = function(members){
var result = '';
for(var i = 0; i < members.length; i++){
result += '<li class="member">' + members[i] + '</li>';
}
$("#members ul").html(result);
};

var showComments = function(comments){
for(var i = 0; i < comments.length; i++){
var result = '<li class="comment">';
result += comments[i].name + '>' + comments[i].text;
result += '</li>';
$("#chat ul").prepend(result);
}
};

var enterChatRoom = function(){
name = $("#name").val();
if(name === ""){
$("#error").text("名前を入力してください。");
return;
}
for(var i = 0; i < members.length; i++){
if(members[i] === name){
$("#error").text("その名前はすでに使用されています。");
return;
}
}

$("#form").html(
'<label>Text</label><input type="text" id="text" maxlength="140">'+
'<button id="submit">submit</button>'+
'<button id="out">退室</button>'
);

$.getJSON('/cometchat/connected', {name:name}, function(json){
showMembers(json.members);
showComments(json.comments);
$("#chat").show();
});

$.post('/cometchat/token', {name:name}, function(token){
var channel = new goog.appengine.Channel(token);
var socket = channel.open();
socket.onopen = function(){
setTimeout(function(){
$.post('/cometchat/enter', {name:name});
}, 100);
};

socket.onmessage = function(e){
var o = $.parseJSON(e.data);
showMembers(o.members);
showComments(o.comments);
};
});

$("#text").keypress(function(e){
if(e.which == 13) postComment();
});
$("#submit").click(postComment);
$("#out").click(function(){
outChatRoom();
pushUnloadButton = true;
location.href = '/cometchat';
});
window.onunload = function(){
if(!pushUnloadButton){
outChatRoom();
alert("退室します。");
}
};
};

var outChatRoom = function(){
$.post('/cometchat/out', {name:name});
};

//init
$("#name").keypress(function(e){
if(e.which == 13) enterChatRoom();
});
$("#submit").click(enterChatRoom);
getMembers();
});
posted by 右京 | Python

[GAE]簡単なチャット

Google App Engineで簡単なチャットを作ってみた。
データはmemcacheにだけ書き込むので、そのうち消えるという仕様。

データ読み込みは差分をjsonで受け取るかんじ。
あと、cometはGAEだと使えないので(使えるみたいですね
#appengine でComet! Channel APIでpushできるぞ)1秒間隔でpolling。


一応、30秒何もしないと、pollingの間隔は1分になる。

Demoページ
http://web-board.appspot.com/chat

chat.py
#coding: utf-8

import datetime
import cgi

from google.appengine.api import memcache
from django.utils import simplejson as json

from utils import SafeThreadRequestHandler

MEMCACHE_CHAT_KEY = 'chat'

TEMPLATE_HTML = u'''
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">

<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<title>Simple Ajax Chat</title>
<link href="/css/chat.css" rel="stylesheet" type="text/css" />
<script type="text/javascript" src="/js/jquery-1.4.1.min.js"></script>
<script type="text/javascript" src="/js/chat.js"></script>
</head>
<body>
<div id="container">
<div id="screen">
<h1>Simple Ajax Chat</h1>
<div id="content">
<div id="form">
<label>Name</label><input type="text" id="name" maxlength="10">
<label>Text</label><input type="text" id="text" maxlength="140">
<button id="submit">submit</button>
</div>
<div id="chat"></div>

</div>
<div id="footer">
<div id="copyright">Copyright (c) 2010. <a href="http://hujimi.seesaa.net">Ukyo</a></div>
</div>
</div>
</div>

</body>
</html>
'''


class ChatPage(SafeThreadRequestHandler):
def get(self):
length = self.request.get("length")
if length:
length = int(length)
comments = self.get_comments()
res = {
'length' : len(comments),
'comments' : comments[length:]
}
self.response.out.write(json.dumps(res))
return

self.response.out.write(TEMPLATE_HTML)

def post(self):
name = cgi.escape(self.request.get("name"))
text = cgi.escape(self.request.get("text"))
date = datetime.datetime.now().strftime("(%H:%M:%S UTC+00:00)")

self.mutex.acquire()
comments = self.get_comments()
comments.append({
"name" : name,
"text" : text,
"date" : date
})
memcache.set(MEMCACHE_CHAT_KEY, comments)
self.mutex.release()

def get_comments(self):
comments = memcache.get(MEMCACHE_CHAT_KEY)
if comments is None:
comments = []

return comments


utils.pyのSafeThreadRequestHandler
class SafeThreadRequestHandler(webapp.RequestHandler, threading.Thread):
'''スレッドセーフなリクエストハンドラ'''

mutex = threading.Semaphore(1)

def __init__(self):
webapp.RequestHandler.__init__(self)
threading.Thread.__init__(self)


chat.js
$(document).ready(function(){
var pass = '/chat';
var length = 0;
var intervalFastMs = 1000;
var intervalSlowMs = 30000;
var timeoutMs = 60000;

var getComments = function(){
$.getJSON(pass, {'length':length}, function(json){
var comments = json.comments;
for(var i = 0; i < comments.length; i++){
var comment = '<ul class="comment">';
comment += '<li class="comment-name">' + comments[i].name + '</li>';
comment += '<li class="comment-text">' + comments[i].text + '</li>';
comment += '<li class="comment-date">' + comments[i].date + '</li>';
comment += '</ul>';
$("#chat").prepend(comment);
}
length = json.length;
});
};

var interval, timeout;

var changeReadSpeed = function(speed){
clearInterval(interval);
clearTimeout(timeout);
interval = setInterval(getComments, speed);
timeout = setTimeout(function(){changeReadSpeed(intervalSlowMs)}, timeoutMs);
};

changeReadSpeed(intervalFastMs);

var postComment = function(){
var name = $("#name").val();
var text = $("#text").val();

$.post(pass, {'name':name, 'text':text}, function(data){});
$("#text").val('').get(0).focus();
changeReadSpeed(intervalFastMs);
};

$("#submit").click(postComment);

$("#text").keypress(function(e){
if(e.which == 13) postComment();
});

$(document).mouseover(function(){
changeReadSpeed(intervalFastMs);
});
});
posted by 右京 | Python

githubにうpしてみた

twitterでもいいかなと思ったけれども、こういうことはブログでね。
この間作ったBBS for GAEをgithubにうpした。で、初めて使ってみたので一応記事にもしておこうかなということです。

http://github.com/ukyo/BBS-for-Google-App-Engine
posted by 右京 | Python

掲示板プログラムで何をmemcacheに入れておくかの考察

基本はフェッチしたデータをそのままmemcacheに入れる。memcacheを更新するときに色々面倒(後で説明)。

最速はhtmlに変換したものを直接入れる。memcacheから呼び出した後に処理する手間が省ける、データ追加が楽という利点があるが、柔軟性はなくなる(携帯版とか作るときに面倒)。

で、一番柔軟性が高いのはlistで保存すること(だと思う)。一番最初にそのままデータをいれたときに面倒だっていうのは、実はフェッチしたデータはappendできないってのがあって、更新する度にデータストアから全部引っ張ってこないとダメらしいんだよね。listにしておけば、appendしてmemcache.setするだけ。


読み込み
def get_comments(thread_key):
comments = memcache.get("comments" + thread_key)
if comments is None:
comments_ = Comment.all().filter("thread_key", thread_key)
comments = [comment for comment in comments_]
memcache.put("comments" + thread_key, comments)
return comments

書き込み
def set_comment(comment, thread_key):
comments = get_comments(thread_key)
comments.append(comment)
memcache.set("comments" + thread_key, comments)


大体こんな感じかな。
posted by 右京 | Python

Google App Engine用の掲示板できた

ライセンス
・MITライセンス。

機能
・http://で始まるコメントはクリックできるようになるよ。
・2ch風のアンカーリンクが使える。
・はてなのスーパーpre記法でソースコードに色がつく。
・各スレッドごとにRSS配信。
・全コメントでのRSS配信。

手抜き
・タイムゾーン。
・css(Operaは見れたもんじゃない、IEも果てしなく微妙)。


というわけで、ソースコード
bbs for gae.zip
posted by 右京 | Python

Google App Engineで掲示板作った

こんなかんじです。
gae_bbs.png

サイトは↓
http://web-board.appspot.com/

コードはとっちらかっているので、整理したら公開するかも。
posted by 右京 | Python

exceptions.ImportError

Google App Engineでexceptions.ImportErrorなるものが出た。

エラーが出たときのインポートは以下のようになってた。
from test import Test


名前がまずかったのかなと思って、ファイル名をadmintest.py、クラス名をDataStoreTestにしてインポートを
from admintest import DataStoreTest

このようにしたらなんとかなったりした。というわけで、インポートエラーがでたらとりあえず名前を変えてみよう!(理由はよくわからん)
posted by 右京 | Python

wxPythonのPaintDCでアンチエイリアスや透過を使う

メモがわりかつ日本語のサンプルがなかったので。

まず、通常どおりにPaintDCを使った場合
#coding: utf-8

import wx

class Frame(wx.Frame):
def __init__(self):
wx.Frame.__init__(self, None, size=(200,200))
self.Bind(wx.EVT_PAINT, self.OnPaint)

def OnPaint(self, event):
dc = wx.PaintDC(self)
dc.DrawEllipse(10, 10, 100, 100)

if __name__ == "__main__":
app = wx.App(0)
frame = Frame()
app.SetTopWindow(frame)
frame.Show()
app.MainLoop()

表示は以下のようにギザギザとしたものになる。
paintDC_before.png

次に、GCDCを通してPaintDCを使ってみる(OnPaintの部分を以下のように変更)。
    def OnPaint(self, event):
pdc = wx.PaintDC(self)

try:
dc = wx.GCDC(pdc)
except:
dc = pdc

dc.DrawEllipse(10, 10, 100, 100)


すると、以下のようにアンチエイリアスがかかった表示になる。
paintDC_after.png

透過もできる。
    def OnPaint(self, event):
pdc = wx.PaintDC(self)

try:
dc = wx.GCDC(pdc)
except:
dc = pdc

#red
dc.SetBrush(wx.Brush(wx.Colour(255, 0, 0, 64)))
dc.DrawEllipse(10, 10, 100, 100)

#blue
dc.SetBrush(wx.Brush(wx.Colour(0, 0, 255, 64)))
dc.DrawEllipse(30, 60, 100, 100)

#green
dc.SetBrush(wx.Brush(wx.Colour(0, 255, 0, 64)))
dc.DrawEllipse(60, 10, 100, 100)


表示。
paintDC_tr.png
posted by 右京 | Python

オセロのゲームを管理するクラスとview関係のクラス

オセロの盤関係のクラスの続き

ゲームの管理を行うクラス。最低限の機能だけ実装してあるよ。
class Game(object):
def __init__(self, board):
self.board = board
self.initation()

#初期化
def initation(self):
self.board.initation()
self.turn = Board.WHITE
self.isFinish = False

#ターン変更
def changeTurn(self):
if self.turn == Board.WHITE:
self.turn = Board.BLACK
else:
self.turn = Board.WHITE

#駒を置く処理
def put(self, x, y):
if self.isFinish:
print 'finished'
return

if self.board.put(x, y, self.turn):
self.changeTurn()
if self.board.check(self.turn) == False:
self.changeTurn()
if self.board.check(self.turn) == False:
self.finish()

#終了時の処理
def finish(self):
self.isFinish = True

nWhite = self.board.count(Board.WHITE)
nBlack = self.board.count(Board.BLACK)

if nWhite > nBlack:
return Board.WHITE
elif nBlack > nWhite:
return Board.BLACK
else:
return Board.NONE

#盤面の取得
def getBoard(self):
return self.board.board


view関係のクラス。これも簡単な実装で済ましている。手抜きとも言う。
#coding: utf-8

import wx
from models import Board, Game

#1つのマスを表すクラス
class Cell(wx.Panel):
def __init__(self, parent, x, y, game):
wx.Panel.__init__(self, parent, -1)

self.game = game
self.x = x
self.y = y
self.SetBackgroundColour(wx.Colour(116, 139, 5))

self.Bind(wx.EVT_LEFT_DOWN, self.OnMouseDown)
self.Bind(wx.EVT_PAINT, self.OnPaint)

#クリックしたときの処理
def OnMouseDown(self, event):
self.game.put(self.x, self.y)
self.GetParent().repaint()

#描写処理
def OnPaint(self, event):
pdc = wx.PaintDC(self)
try:
#アンチエイリアスをかける
dc = wx.GCDC(pdc)
except:
dc = pdc

color = self.game.getBoard()[self.x][self.y]
if color == Board.BLACK:
dc.SetPen(wx.BLACK_PEN)
dc.SetBrush(wx.BLACK_BRUSH)
elif color == Board.WHITE:
dc.SetPen(wx.WHITE_PEN)
dc.SetBrush(wx.WHITE_BRUSH)
else:
return
dc.DrawEllipse(0, 0, self.GetSize().GetWidth(), self.GetSize().GetHeight())

#メインフレーム
class Frame(wx.Frame):
def __init__(self, game):
wx.Frame.__init__(self, None, -1, size=(450, 500))

self.game= game

sizer = wx.GridSizer(Board.LENGTH, Board.LENGTH, 1, 1)
for i in range(Board.LENGTH):
for j in range(Board.LENGTH):
cell = Cell(self, i, j, game)
sizer.Add(cell, 1, wx.ALL|wx.EXPAND)

self.CreateStatusBar()
self.setStatus()

#menu周り
menuBar = wx.MenuBar()
menu1 = wx.Menu()
menu1.Append(101, "&New Game")
menu1.Append(102, "&Exit")
menuBar.Append(menu1, "&File")
self.SetMenuBar(menuBar)

self.SetSizer(sizer)
self.Refresh()

self.Bind(wx.EVT_SIZING, self.OnResize)
self.Bind(wx.EVT_MENU, self.NewGame, id=101)
self.Bind(wx.EVT_MENU, self.Exit, id=102)

#再描写
def repaint(self):
self.setStatus()
self.Refresh()

#リサイズしたときの処理
def OnResize(self, event):
self.Refresh()

#新規ゲーム
def NewGame(self, event):
self.game.initation()
self.repaint()

#ゲームの終了
def Exit(self, event):
self.Close()

#ステータスバーの更新
def setStatus(self):
w = game.board.count(Board.WHITE)
b = game.board.count(Board.BLACK)

if game.turn == Board.WHITE:
turnText = '○のターン'
else:
turnText = '●のターン'

if self.game.isFinish:
finishText = ' 終了しました'
else:
finishText = ''

self.SetStatusText(turnText + ' ○' + str(w) + ' ●' + str(b) + finishText)

if __name__ == "__main__":
app = wx.App(0)
board = Board()
game = Game(board)

frame = Frame(game)
app.SetTopWindow(frame)
frame.Show()
app.MainLoop()


AIはそのうち・・・。

ソースは以下からどうぞ。
models.py
views.py
posted by 右京 | Python
×

この広告は1年以上新しい記事の投稿がないブログに表示されております。