wechat.el是用Emacs Lisp打造的微信公众平台开发框架,基于elnode。源码已经托管在Github上:https://github.com/redraiment/wechat.el,现已收录在oschina。
8 p2 R7 P! D) \: d$ g借助Lisp语言强大的可定制性,使得开发一个公众平台的应用犹如编写一段剧本一样简单!例如本例——开窗游戏,展示了如何给予wechat.el实现自己的应用。- ! I8 x; e" b0 |1 b* ?' m/ ?
- <p> </p><pre style="color: rgb(0, 0, 0); text-transform: none; line-height: normal; text-indent: 0px; letter-spacing: normal; font-style: normal; font-variant: normal; font-weight: normal; word-spacing: 0px; orphans: 2; widows: 2; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px;">;; 定义新的游戏地图
6 p! |0 f0 f5 z/ \ s - (def-map "/game/5x5.el" ; 对外开放的URL
7 u4 y9 v/ }; u# B' R7 \- f - 'tutorial-room-0) ; 默认的入口
/ ^9 p! B1 y' e- _ {; Y8 S4 D! r - " P. \! G* P8 V8 x
- ;;; 游戏大厅; A8 e9 x) n/ \7 V L. }
- (def-room living-room( X0 i3 h) V7 C& d( n4 \! Y
- ;; 进入该房间后的提示语; ]: H$ ]# N$ G0 v' f2 r
- "1. 教程7 ?. n u5 Q+ L
- 2. 入门(3x3)0 b" B: w5 R' L2 J2 g# z0 `2 @
- 3. 初级(5x5)4 z2 s8 z% P9 ^6 K' |, Z) n! Y
- 4. 中级(7x7)& r7 T6 e. x" Q. f6 Y7 d; X& R
- 5. 高级(9x9)% _9 F9 `/ V/ J8 L9 A
- 0. 关于作者9 j: v" V" `+ }. K# `3 s5 H
- 请选择1-5开始新游戏:"7 ^* t6 w# p9 W' ]" N y( p9 P
- ("0" about-room) ; 期望用户输入的信息以及相应的后续房间名4 ?3 e8 G4 _8 t% I( q; E; B' I6 e, R
- ("1" tutorial-room-0)
4 X: C1 G1 G* h* e' X' A j. d% V - ("[2-5]" game-room-init) ; 用户输入信息可用正则表达式匹配: d& x) P9 ?. s% h0 j! R2 x7 @
- ; 相应的返回也可以为函数,动态返回房间名3 n- }: g9 \" C: s5 C; p1 g* N; c
- (t living-room)) ; 如果条件为t,为永真( d# n/ y0 }3 O u2 T& E
; U9 t) s, o& { \- ;;; 作者信息$ m! {/ i, `+ p v: W4 {# t
- (def-room about-room
" F/ ]: c1 T5 Y6 B/ ? - "作者:redraiment! G8 [& Y5 _3 P+ f4 _, h
- 微博:http://weibo.com/redraiment @3 K+ k1 N* d% ?0 \, P
- 有任何建议,欢迎在微博或微信上联系redraiment。
8 ]9 D# O- n' Q0 R; t! P. T - 请输入任意数字返回游戏大厅。"6 X7 I6 B( i1 L& t
- (t living-room))9 J2 _, H; h' P1 @% t+ t
- & h" H; B: z7 j' M3 I% x
- ;;; 教程/ ~8 q: O9 F: z' H2 l* _9 K( }6 {2 E
- (defvar *wechat-5x5-tutorial-rooms* 0% a c; l( X. l' i/ a4 x2 L) z
- "The number of tutorial rooms")
+ M9 A7 z3 t' G" I8 p9 t
8 {6 ?# v; w( ^" V% U- ;;; 简化教程的定义' A* X2 L) s$ D( Y2 n6 k
- (defun string-last-line (content)' y* o \& Q+ j/ v/ {
- "多行内容组成的字符串中的最后一行"0 B& F2 Y. N+ g$ S7 p4 r9 F
- (with-temp-buffer/ d0 |' W- ?' w- w
- (insert content)
# j, V: i% g$ G4 X - (buffer-substring (line-beginning-position)0 F2 G) I) P, j! K9 w/ g7 C+ e
- (point-max))))
& G/ Z; D; y* _5 o
! a' K! @2 U- j# S- (defun def-tutorial-room (prompt)4 A5 v, ^% L6 j- t) n6 z3 v# v$ J6 o
- "根据提示语自动生成教程房间。' J' b7 @: {. ~
- ) N2 t% R& ~$ k* i; `
- 1. 提取最后一行作为问题;" w, k B- f; C. a, E- Q
- 2. 分析问题,获取期望用户输入的内容;
! z# S V$ H) z% \ - 3. 定义教程房间和重复提问房间。"
6 z4 \9 y4 i$ \5 \8 |8 s L - (let* ((room-name (concat "tutorial-room-" (number-to-string *wechat-5x5-tutorial-rooms*)))
& ^; u$ `4 U' i+ K7 V8 J. R - (repeat-room (concat room-name "-repeat")) D; z0 u# N; P6 s2 ]) B: m4 X% t3 x# `
- (next-room (concat "tutorial-room-" (number-to-string (incf *wechat-5x5-tutorial-rooms*))))* r! g! q/ I0 o4 f
- (question (string-last-line prompt)): b8 G4 H# q+ U* c* p
- (except (if (string-match "请输入“\\([0-9a-zA-Z]+\\)”" question)
, X. M" J3 x1 ~: ~ M - (match-string 1 question)))8 X' }( n6 h+ w" m1 D6 F# S
- (doors (if except# g( Y+ [' q- |) i
- `((,except ,(intern next-room)); Q& m% Z" c1 T
- ("q" living-room)& a0 c- W1 R, J. s: s( t2 {1 i D
- ("Q" living-room) d% x+ P4 Q! R$ B
- (t ,(intern repeat-room))): u1 y* o) D3 E8 y9 u- i
- '((t living-room)))))
* w3 K% u' l& L0 z9 b: Q0 z$ R3 z - (def-room-raw (intern room-name) prompt doors)
" R1 r- G1 d" V - (def-room-raw (intern repeat-room) question doors)))% W/ }" ^2 N' |- ~1 z; }
- # w3 h/ i1 ]# U. f# g2 E
- (defun def-tutorial (&rest prompts)
# ]9 x2 W. g. \5 f# v" P; | - "批量生成教程房间。"
1 K4 b& q& k3 B; Z - (dolist (prompt prompts)
$ K& h/ ` s. S F( h/ V7 o - (def-tutorial-room prompt)))
9 d6 E5 F2 I, ?5 O# |! o5 E, V) | - # l x+ S. q8 o( m9 R3 b- Y' R
- (def-tutorial6 c- h! E1 m0 d t r1 C4 I
- "欢迎体验微信版的开窗游戏!为了让您尽快熟悉游戏的规则,请根据教程提示一步一步完成要求的操作。注:任何时刻,您都能输入“q”来退出本教程。
, p) g9 k. a/ ^ - 1. 教程
# k" F! h5 C& R5 K: t; i - 2. 入门(3x3)6 P" b/ [9 d( K P1 Q* S% M7 G
- 3. 初级(5x5)
" y7 m4 h! e0 S6 Z6 ]) G% c - 4. 中级(7x7)
; ^7 E- r( K, s. _" Y0 K. ?: c - 5. 高级(9x9)3 }0 F" d, u. a' g8 `$ d9 r' X
- 0. 关于作者
8 { q; S. c# r" u% ? - 请选择1-5开始新游戏:! \( t+ _, E1 l& H. ?0 Q7 v
- 您现在正在游戏大厅里。
9 ]" {% y- R1 b- w4 O6 k - 请输入“2”进入入门级房间", ^* w( {/ Y b: Z- Y4 h
- " ①②③
( i; u. C1 _, H+ B! u* ~: L - 1 ■
% U7 J8 C( S0 @+ C% ^ - 2■■■
p6 {) R) Q( M0 e - 3 ■
# n( O! [& \( H. G! ~8 D) x4 \: Z - 进入房间后,您就会看到一个如上图所示的3x3棋盘。其中黑子代表打开的窗户,白子代表关闭的窗户。您可以输入任意一个棋盘上的坐标,来开启或关闭某扇窗户。游戏的目标是开启所有窗户! o9 c$ H) l% I: n- x$ ^. H2 H
- 请输入“22”来关闭第2行第2列的窗户。"5 Z( K8 O% [4 T( L: N. _8 g
- " ①②③
0 W9 ?* C% {: z6 I& Y# e - 1
1 c7 ?2 @( F2 t0 | - 2 . `- F9 b1 d$ t1 p _$ Y2 Q1 d! C
- 3
* ~- e" }; r1 b$ m1 f( ] - 你可能被吓了一跳,怎么所有的窗户都被关闭了?我忘了告诉您:这些格子是被按了机关的,只要一个窗户被开启或关闭,它的上下左右四扇窗户也会连锁反应,被开启或关闭。
# A; h3 X, N, B u" L - 请输入“11”,试着开启左上角的窗户。"
1 s/ [# \9 z- Z& R9 ` - " ①②③
/ X* h2 E. q L/ N - 1■■
* G4 d( O. t" @$ R - 2■
: A& h' p: z4 S& |" o% B2 Y. Y7 Q - 3 4 f8 [; F. Y9 L
- 因为连锁反应,11右边和下面的窗户也被开启了。但因为11在左上角,没有上面和左边,因此这回总共只开启了三扇窗户。
8 m0 K+ Y( c7 d$ q& X - 请输入“13”开启右上角的窗户。"
. x. g9 O- z. N i* g7 ~8 ` - " ①②③
3 ^, }0 z3 x) a/ B5 a9 O* c - 1■ ■1 o6 ~1 h6 d* t) i3 I
- 2■ ■0 ]4 F! v- h: ]# l, a
- 3 ) S6 x5 J' B3 Z6 I5 e
- 第1行第2列上的窗户因为本来就是处于开启状态的,这回因为13的连锁反应,又重新被关闭了。
; m8 G+ y- M" r" X) l4 x - 请输入“31”开启左下角的窗户。"5 U$ z- L, h1 V
- " ①②③
; B9 \3 `2 B, T. M; |% E4 Q! ] - 1■ ■0 g* h! H9 J, G# Q' m8 E
- 2 ■: ~) x4 ^" ?" `% j* ]
- 3■■ $ C) E0 E9 Y5 D. J) O' N+ t
- 此时,总共有5扇窗户被开启了。) \5 R A' i! z- S
- 请输入“33”开启右下角的窗户。", L; S" G+ i- \& N
- " ①②③
' W D: e' z3 R, h& e* v - 1■ ■1 ~* Q4 X; P( f6 \" w- z+ f2 \5 d
- 2
$ D h8 a# z0 h - 3■ ■# @; M( b5 U& `( z4 B7 d2 F/ r, T
- 现在,只有四个角落的窗户被打开。8 y3 m$ s( G: q8 W' R
- 请输入“22”完成最后一击!"
2 X+ ?+ S1 U7 I; {6 i' l; O - " ①②③+ ?; Z; Q" I& p1 Q3 \ G
- 1■■■
! t3 W/ G# ^8 u; z7 v - 2■■■5 ?& `4 \- R) o5 x9 k( R C
- 3■■■: C* t5 q9 m! p% K
- 您已完成教程的所有内容,输入任意内容返回大厅,开始您的开窗之旅!")
8 e1 K+ Q: P- ?4 d4 d* K1 m
F0 W5 k8 V' m5 K+ E' Y2 I* k! ]- ;;; 棋盘
' C' s4 l _5 t" e9 }: @1 ]# h - (defconst *wechat-5x5-white-chess* 12288; h# j: N# {# n" o( e
- " ")1 c r# ], _ {( E/ ]' @
% P: }5 t' G D- (defconst *wechat-5x5-black-chess* 9632
2 t$ H/ O1 x% R; ^9 |" L5 }- v2 @ - "■")/ T) o4 c* D* H" ?& P! R* ^, t8 P
- 1 P- ~3 ]) T7 [+ m
- (defmacro with-board (&rest body)
. ~% Y* j2 x/ K2 j" P. t) Z - `(with-temp-buffer
) R$ E- w8 T$ E4 Q8 ^1 L - (unwind-protect/ P, t& r4 w3 i7 B
- (progn
+ y- @9 _2 c- I8 c1 c2 G! I. s* @1 W - (if (session "board")# w" ]8 Y: D j* `5 V
- (insert (session "board")))
/ m) K8 k7 r% l5 P2 K+ }, {% p. ~ - ,@body)+ M. f/ v! ` k7 n5 H$ @& R7 |% }. W! P
- (session "board" (buffer-string)))))
9 Q( H; g) w8 z/ J - & |( @+ B/ t$ q4 s9 W# X3 R
- (defun board-init (size)
o4 M$ B4 [2 Q4 O - (session "size" size): d9 Q" Z* ^. t! B
- (session "step" 0)( g0 a1 O3 a* \
- (erase-buffer)
+ P) I$ f* L$ P+ K* p( Y - (insert (format (format " %%.%ds\n" size) "①②③④⑤⑥⑦⑧⑨"))3 j& R7 z T+ M6 v4 j5 k7 U
- (dotimes (row size)
& K7 H0 n0 z# P- a: \; ?/ Y$ {) f - (insert (format "%d%s\n" (1+ row) (make-string size *wechat-5x5-white-chess*)))))
! i7 K2 n& c+ b q
$ m2 h' h1 d! _/ v9 b- (defun board-contains-p (y x)9 G3 n% q w3 u8 q/ S9 G
- (let ((size (session "size")))
1 V8 \9 C9 X$ r7 B - (and (<= 1 y) (<= y size)
6 \ V1 t' D7 {+ \1 d D/ w - (<= 1 x) (<= x size))))
0 {$ ^% q: N6 ] E
* z; L+ I. n) v4 |/ s! [$ R( m- (defun board-toggle (y x)
7 q; Y* P. ?7 T% E- S" V - (when (board-contains-p y x)
) G+ `, j+ r& o7 O2 [% z' p - (goto-line (1+ y)), h% w1 f8 @- u) P- v: x
- (beginning-of-line)& k. o/ k- G; k& ?4 \; e
- (forward-char x)- \% B# {) M; w4 @ d( Y
- (insert (if (= *wechat-5x5-white-chess* (following-char))
1 I4 n6 U" t5 ~& N/ ^7 w - *wechat-5x5-black-chess*- b$ F3 m' Q7 T2 R
- *wechat-5x5-white-chess*))
2 f& i" p. ^0 s/ N/ I - (delete-char 1))) {5 j3 a( C1 a O% m U( O/ r
0 R& w0 G6 x/ q) m- (defun board-put (y x)
0 _0 h, J" [( L - (dolist (dir '((-1 0) (0 -1) (0 0) (0 1) (1 0)))2 u6 ~ E5 N, M3 ]
- (board-toggle (+ y (first dir))
. p( g5 z4 Q3 x% V& W9 o7 Q5 w$ ? - (+ x (second dir)))))
/ w4 e9 b$ L* T2 O q - : ~: b& e b( i N5 S
- (defun game-over-p ()
/ B4 F' }8 L4 i* {5 T - (beginning-of-buffer)
8 S, {- T( J, x, k# Q: p4 D* h - (not (search-forward (string *wechat-5x5-white-chess*) nil t)))
7 S+ p8 b; O: I# u! K - ! ?2 q( u; v" J# F2 |5 `! C6 N
- (defun board-show ()
& ^* Y* m8 a8 \ - (with-board% d5 ^+ w: G! e( z L' I
- (concat (buffer-string)
3 M* K$ Y) K' f7 @+ _% D - (if (game-over-p)
3 o# L: G( Z; I5 \9 k4 S - (format "共%d步,输入任意内容返回大厅" (session "step"))# h. U2 I; J# I- X
- (format "第%d步" (1+ (session "step")))))))
% i3 U2 o3 \9 l* K2 u+ P6 T6 Q
5 K5 N# `4 l9 k! }! ~, A- (defun board-position-parse (cmd)3 O3 \" `9 H/ q2 q! A) g E8 _
- (if (= (length cmd) 2)
2 B+ ?# C n, M/ m) K( C - (list (string-to-int (substring cmd 0 1))0 o# M' C! I% Q5 G
- (string-to-int (substring cmd 1 2)))' r2 u: d( b1 t' T; h+ v8 u3 y
- '(0 0)))
9 J1 ~, A/ L) D9 C - # K1 M/ \( I/ M0 {/ Q. |4 g
- ;;; 游戏房间 M# F6 A- m9 h ], T9 c
- (defun game-room-init (cmd)& U/ U2 F, U: _& E2 Q# B" q
- (let* ((middle (string-to-int cmd))& |; @, ]5 {( \) d0 A, L
- (size (1- (* 2 middle))))
6 l3 o# q0 N, T; T3 ? - (with-board! F- o! O2 l2 Q& t; D) e) _( b
- (board-init size); f0 Y J/ v! x9 D/ M" ?$ A# N
- (board-put middle middle)))
+ S4 h6 i9 e9 w3 B- ~. ?/ i" e0 \ - 'game-room)
7 |& U7 m1 {- g0 g. n - & T/ [% D( ?/ v
- (def-room game-room& l) X! n+ B4 Q
- #'board-show0 u% w# \/ i1 z& U8 Y! z3 u
- (t (lambda (cmd): @1 I7 _% s: J# k
- (with-board
: X/ N7 K' y9 q6 ] - (if (game-over-p)
& U' z) W, h& W$ ~* y; [' n w+ l - 'living-room
" ? a) z! L1 e - (destructuring-bind (y x) (board-position-parse cmd)
* ]# ]8 z6 l ^9 Q - (when (board-contains-p y x)
% F8 G. A% o; d' Y - (board-toggle y x)( w9 p3 s, ~. j* \6 f
- (session "step" (1+ (session "step"))))
3 i2 C% g8 V2 |0 L) r3 @1 Q - 'game-room))))))</pre>
复制代码 |
上一篇:微信扫描登录下一篇:微信红包
|