wechat.el是用Emacs Lisp打造的微信公众平台开发框架,基于elnode。源码已经托管在Github上:https://github.com/redraiment/wechat.el,现已收录在oschina。
/ v r$ ^6 y# r: N0 M借助Lisp语言强大的可定制性,使得开发一个公众平台的应用犹如编写一段剧本一样简单!例如本例——开窗游戏,展示了如何给予wechat.el实现自己的应用。
+ F* ^/ n6 @% O- u- <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;">;; 定义新的游戏地图/ r- @* o! ~. [
- (def-map "/game/5x5.el" ; 对外开放的URL
- E" `5 z9 L/ Z7 b5 C' K" o - 'tutorial-room-0) ; 默认的入口
, a- x8 H3 y$ d
) n5 f- h V4 {- ;;; 游戏大厅- J" F, |0 Y; e9 q% T
- (def-room living-room
% n3 B* k4 I! r5 d2 e* Z7 K - ;; 进入该房间后的提示语
6 P/ Y+ n- r6 c. U7 l% K - "1. 教程3 q) K4 [5 \# v) I3 h4 D: L
- 2. 入门(3x3)* ^2 A$ x* M: r2 s' W) Z4 W& @
- 3. 初级(5x5)
; b' L7 f1 l) p& ] - 4. 中级(7x7)
- f+ O5 h2 B* g* d+ F* l) p - 5. 高级(9x9)
* D: ]/ A% v Z& b1 ^ - 0. 关于作者
0 T; R. I; ?) `3 x! p& h - 请选择1-5开始新游戏:"8 X1 T* r: t) T: S+ t
- ("0" about-room) ; 期望用户输入的信息以及相应的后续房间名" S0 n2 |6 X5 y5 X, b: E3 r D
- ("1" tutorial-room-0)6 d k( J) N3 m( m
- ("[2-5]" game-room-init) ; 用户输入信息可用正则表达式匹配0 n3 [( A+ k$ F) K
- ; 相应的返回也可以为函数,动态返回房间名
/ X6 Z; b I0 C9 h0 C - (t living-room)) ; 如果条件为t,为永真
9 L* m& J4 n+ J, p8 N% ]& C6 [ - 5 H8 V/ l, r7 ?1 u3 y# Y
- ;;; 作者信息: R2 B O! b& w5 M, r; E/ P/ b
- (def-room about-room
! J0 b( x* m q N3 J - "作者:redraiment
/ O+ n+ j$ [+ Z' x7 u - 微博:http://weibo.com/redraiment
6 Z! V" ]0 O3 S; Q. P% W - 有任何建议,欢迎在微博或微信上联系redraiment。
/ K/ v/ @* U5 J" r" _ - 请输入任意数字返回游戏大厅。"$ }- I) _- A3 g2 }" [9 M0 [, R7 ~
- (t living-room))
4 f- C* v* Q: h7 m9 ~, U - 2 O) t( V: m9 {7 A& x9 ]$ P, Z
- ;;; 教程
' p) X2 ~' A0 m; y- W+ I - (defvar *wechat-5x5-tutorial-rooms* 0
& G( Y; A: \, [% V' D( { - "The number of tutorial rooms")- I* D1 q( J4 _1 X/ t$ T* D/ E/ L
3 Q% b' {5 B. z( Q! O2 H- ;;; 简化教程的定义
- k2 R1 @* I" N! J/ y. z% Y- x - (defun string-last-line (content)
( p9 F4 D# y1 |# ~2 x - "多行内容组成的字符串中的最后一行"
* y) _7 z2 I0 m - (with-temp-buffer. o ?* [9 M: p" q9 b% ^# L
- (insert content)7 q7 |" N$ F! S( d# P) p
- (buffer-substring (line-beginning-position): m/ F( k. c9 |3 r" H. q0 `
- (point-max))))# E6 [* x! U: J0 l, I
! [! L7 v: z; C1 W- (defun def-tutorial-room (prompt). S- M$ q7 d1 V+ n% |
- "根据提示语自动生成教程房间。5 [% z" p3 P9 E; o( @+ d# R
- 0 h/ k( a* B8 z: z G5 `" J. p
- 1. 提取最后一行作为问题;
3 T5 T& R8 r. ~; e5 h) b - 2. 分析问题,获取期望用户输入的内容;; e1 v3 R3 \) U3 }4 R1 z9 F
- 3. 定义教程房间和重复提问房间。"
5 `( P/ [6 Y( p ^0 b - (let* ((room-name (concat "tutorial-room-" (number-to-string *wechat-5x5-tutorial-rooms*)))
: h& H- }8 @: s Z - (repeat-room (concat room-name "-repeat"))% x# P" k9 {, U5 N
- (next-room (concat "tutorial-room-" (number-to-string (incf *wechat-5x5-tutorial-rooms*))))% j! Q0 Q2 T1 U) P
- (question (string-last-line prompt))
) t" g- [! ^- n: K2 E9 `' J9 _ - (except (if (string-match "请输入“\\([0-9a-zA-Z]+\\)”" question)+ j. e4 O: e) b r
- (match-string 1 question)))
: _7 f0 D# s0 ^* Q - (doors (if except
+ t0 d X& }, c - `((,except ,(intern next-room)) t. t6 Y' |; Z O9 t8 x
- ("q" living-room)
( d9 V; b* m0 C - ("Q" living-room)
' p4 r' ^8 ?. p) ^ - (t ,(intern repeat-room)))5 B4 s" S& I* v D( E* I% X+ L& }. ]* j
- '((t living-room)))))
& Z( v& O! y2 B/ Y2 u - (def-room-raw (intern room-name) prompt doors)
$ v- @8 p2 b# l* D - (def-room-raw (intern repeat-room) question doors)))
( o1 B1 e; Q6 n O2 e - , i c" u3 H5 W/ v
- (defun def-tutorial (&rest prompts)- z/ c) V1 U# t& \
- "批量生成教程房间。"- M! k7 w" E: [# b3 D: k
- (dolist (prompt prompts)
0 f/ y0 r; p% O4 L9 d! C - (def-tutorial-room prompt)))
( T/ G3 q: n" @) n( @/ `
' i" b) N, Z' K) ]% q/ ~1 N- (def-tutorial
% d- ]" b; }/ i D3 x) p - "欢迎体验微信版的开窗游戏!为了让您尽快熟悉游戏的规则,请根据教程提示一步一步完成要求的操作。注:任何时刻,您都能输入“q”来退出本教程。' Z3 e! M! I& @ G u% P
- 1. 教程
1 {; U$ n0 I- B! u - 2. 入门(3x3)) p0 |6 R* @# a2 H* g
- 3. 初级(5x5)
. G/ v7 ^. \/ \) }2 b - 4. 中级(7x7). ^' o5 ]. R. q6 e7 X4 _6 s
- 5. 高级(9x9)
7 ]8 i! V! ]) G; f. j9 Q- x - 0. 关于作者4 Z! T- w0 h; s* c5 u7 x% z
- 请选择1-5开始新游戏:% V* j @* }# ?/ }* R3 N
- 您现在正在游戏大厅里。% }& n- V, N; K" w" d9 {7 w
- 请输入“2”进入入门级房间"
& h6 m% B4 M( i! p8 `* t - " ①②③
* X) s- h+ [; @6 P( e+ Q4 M. a6 ^ - 1 ■ ; ]; u) S& x! }; T0 a
- 2■■■% w0 c4 e$ E9 U8 W6 s1 T5 C" G$ q
- 3 ■ - i( s* ~) R1 }/ j8 w. o
- 进入房间后,您就会看到一个如上图所示的3x3棋盘。其中黑子代表打开的窗户,白子代表关闭的窗户。您可以输入任意一个棋盘上的坐标,来开启或关闭某扇窗户。游戏的目标是开启所有窗户!4 Z0 W' n# j: |( ?1 u9 T: s
- 请输入“22”来关闭第2行第2列的窗户。"
, A8 b ^' ]6 E/ T+ S; W# p9 `9 {3 [ - " ①②③
( ]8 P: }: K4 }/ y - 1 : I4 g1 `0 g5 {# y6 ?5 D
- 2 1 E# S2 _/ q3 a* }( |1 i4 r6 F
- 3
' D/ u, P# U- w: s9 S9 H8 E - 你可能被吓了一跳,怎么所有的窗户都被关闭了?我忘了告诉您:这些格子是被按了机关的,只要一个窗户被开启或关闭,它的上下左右四扇窗户也会连锁反应,被开启或关闭。
, ?# d6 Z7 n0 n2 @; _ - 请输入“11”,试着开启左上角的窗户。"9 j. }! P: l8 J N( a
- " ①②③
. B; [; x+ P$ A" _( k! @8 D6 q - 1■■ ; Z* Y" ^& q' v
- 2■
, Z2 B$ X% T- m' b$ Q( P" k p - 3
v/ E2 x9 v4 S8 Y - 因为连锁反应,11右边和下面的窗户也被开启了。但因为11在左上角,没有上面和左边,因此这回总共只开启了三扇窗户。8 x6 C: r1 t8 W8 y; _
- 请输入“13”开启右上角的窗户。"
4 I# }1 f; W7 F! p6 K - " ①②③
% O7 n9 z$ A6 R2 q - 1■ ■
k" o& H- j) w - 2■ ■
6 @9 T' Q# }4 B+ v, Z' q - 3 6 h# F: g* n9 J q1 q& L$ P& Q
- 第1行第2列上的窗户因为本来就是处于开启状态的,这回因为13的连锁反应,又重新被关闭了。
G$ ?2 L! z$ n! [* i8 M - 请输入“31”开启左下角的窗户。"
4 z) O$ |0 |+ D, _* J; n - " ①②③
) j# V! S7 v' g: ? - 1■ ■4 a2 Q4 u/ K: m; Q! `
- 2 ■
9 ?5 R+ l: l0 i7 O) u - 3■■ * r4 V W' r! c# \1 J
- 此时,总共有5扇窗户被开启了。
+ M# M8 z# I4 | - 请输入“33”开启右下角的窗户。"# h5 B8 u& N/ e6 D
- " ①②③) j2 r+ K e, g! u
- 1■ ■( G$ V# d4 c- N$ z9 ?' J' g6 G" W: G4 I
- 2 2 y! V/ r) o5 Z) {7 I9 Q
- 3■ ■* s8 x: P0 |3 p4 k* A
- 现在,只有四个角落的窗户被打开。1 n4 f. h4 b9 Q5 ], \
- 请输入“22”完成最后一击!"
1 n8 i/ d4 ? V8 o3 u/ M' z! ? - " ①②③5 F1 I0 S/ y4 p) R/ y5 a
- 1■■■
h) |' y* w4 j/ d; U - 2■■■5 Y" ?0 N9 l+ J0 {
- 3■■■
1 s7 R1 ]. [9 v% N" ^0 c7 [* i+ ~ - 您已完成教程的所有内容,输入任意内容返回大厅,开始您的开窗之旅!")& v7 v! C8 O6 L
- 3 L: ? s2 N- T$ T- V
- ;;; 棋盘( f6 _6 d) L( R3 a! w* g" O
- (defconst *wechat-5x5-white-chess* 12288/ [+ r# L" D0 Y- q
- " ")
" X) ?; T' O! ^5 I1 j8 b* `" P
/ L1 X5 L8 z4 k+ m4 s& E0 Z9 W- (defconst *wechat-5x5-black-chess* 9632; `! k9 ]8 l8 D/ }4 K
- "■")
# t& T: N7 \( q
W1 ^+ j: R: ^; e* X/ ~0 F" H* F- (defmacro with-board (&rest body)
* v- C: E: l6 ]8 T) P - `(with-temp-buffer1 q4 Y6 L$ U0 L. d
- (unwind-protect
9 @, A7 S6 G% l$ G- F/ C - (progn5 s# i5 J* N- \6 k, A: H
- (if (session "board")
. D! w8 A& V" _ - (insert (session "board")))
/ e8 l# C. J7 w) } - ,@body). L! D9 R8 }5 J3 p }
- (session "board" (buffer-string)))))
2 R" j) D5 U6 j3 Z; } o
# P* E( M( e4 q( K$ u) |) U7 O- (defun board-init (size)
* |/ @) r5 g$ ^) c/ I) L2 O- p. \ - (session "size" size)% f% I4 Y: J' F9 y; J% H
- (session "step" 0)
8 H: q1 H) Y' e' V i9 o E - (erase-buffer)
& J" L3 H6 n$ Y1 R3 @9 Y$ W - (insert (format (format " %%.%ds\n" size) "①②③④⑤⑥⑦⑧⑨"))- {- b9 u% L0 J7 S- l
- (dotimes (row size)/ x$ e2 x1 m/ f
- (insert (format "%d%s\n" (1+ row) (make-string size *wechat-5x5-white-chess*)))))* P+ q; S8 D. o( H; y0 r$ R
- 6 S, V" g5 }5 p. }: u j
- (defun board-contains-p (y x)
* @+ N. V- ^( o. w% N! N, i( O0 o - (let ((size (session "size")))2 n ^& N) s) S* p# V& ]
- (and (<= 1 y) (<= y size)
# P: s, O8 c1 \& b - (<= 1 x) (<= x size))))
" C5 l+ h- c# n6 W
- `. E! w- L7 C1 k, n" Y- (defun board-toggle (y x)! ~7 @& v2 T# K1 G+ U: D! `
- (when (board-contains-p y x)
4 a' w' T z: E% h7 D - (goto-line (1+ y))
/ ~. j# F' e0 G - (beginning-of-line)4 j& y! `' e$ t
- (forward-char x)
" t9 X+ s3 E9 I( h - (insert (if (= *wechat-5x5-white-chess* (following-char))
" L9 ]+ G8 O; l' T' z# m/ S- t - *wechat-5x5-black-chess*
( S2 g! |3 n- X: z8 t - *wechat-5x5-white-chess*))
& z1 e/ ~# W9 \ h4 a6 U" h - (delete-char 1)))
" W0 r" x! ]: q( j' k' o% I - ; l5 p# e) ]$ [) A( N# ^
- (defun board-put (y x)
* r0 ]3 H$ G( z: \/ u - (dolist (dir '((-1 0) (0 -1) (0 0) (0 1) (1 0)))5 ^( {* p1 R( r/ B1 E6 p' @3 X- }
- (board-toggle (+ y (first dir))8 a" B M/ B' `
- (+ x (second dir)))))
" B7 i/ M4 E9 `+ b
8 t2 [" o3 Z7 c# p4 p1 @; l- (defun game-over-p ()6 F: ~% Z/ e9 F @5 D! ]" R/ o
- (beginning-of-buffer)
6 D: l9 s, h' J6 d. v2 p* m7 M - (not (search-forward (string *wechat-5x5-white-chess*) nil t))), X. b, {# y3 ^! V' c
( [5 i0 m' W2 z/ a' h# {- (defun board-show ()8 [# f; R& M0 f5 G1 X
- (with-board. f6 ^& S' l7 m$ P% O x* `
- (concat (buffer-string)
( \$ C# k8 d5 @" y- o0 b7 \ - (if (game-over-p)
- D8 F4 @# u: e2 x' F9 i - (format "共%d步,输入任意内容返回大厅" (session "step"))/ o* V4 M8 P; t8 |7 ], ^
- (format "第%d步" (1+ (session "step")))))))0 Q- g, j$ [+ L) u
- 0 u( k5 `' e' X- E( m
- (defun board-position-parse (cmd)& S! @3 w; h8 c9 H
- (if (= (length cmd) 2)
. J8 r* F; i* R* m% t - (list (string-to-int (substring cmd 0 1))+ I V# Q1 T! e% ^* x4 \' Z+ J# G+ x
- (string-to-int (substring cmd 1 2)))
5 S) J1 f3 z* M6 b( W2 w2 Z - '(0 0)))
& Y; f# I" L1 u1 T. d% \
. v# n8 E% J- G! } e6 J- ;;; 游戏房间
! W4 J E7 H X3 l - (defun game-room-init (cmd)% a* i4 X. S# ^0 z9 |: w
- (let* ((middle (string-to-int cmd))
' d- X- }7 h! l& u2 i+ P4 ] - (size (1- (* 2 middle))))
3 |, ]- U1 B m' I5 m - (with-board
( v7 [* q; t" _/ l* }$ t1 A - (board-init size)+ S) N1 v5 z! t
- (board-put middle middle))) n* {2 C8 J, o1 g! Q B
- 'game-room)
2 e; z6 D# G {3 ] M" e - 6 z' G$ f" a3 l t
- (def-room game-room
S e1 C8 A1 \+ Z" P - #'board-show$ E5 d( G9 U# v ^! |
- (t (lambda (cmd)5 t5 T3 I. [$ T( k8 M' S T/ y
- (with-board
' S H, W( V( ]" V( x - (if (game-over-p)
* p' c# g: V$ {- P1 U - 'living-room
% I* {1 ^5 A, `3 @3 j - (destructuring-bind (y x) (board-position-parse cmd)
# D) j& W! e" A' X: b. \1 S - (when (board-contains-p y x)3 l0 c, g9 K' j
- (board-toggle y x)
. ?# b* I# L$ z7 M- L - (session "step" (1+ (session "step"))))/ n' j* @% E0 N/ L
- 'game-room))))))</pre>
复制代码 |
上一篇:微信扫描登录下一篇:微信红包
|