wechat.el是用Emacs Lisp打造的微信公众平台开发框架,基于elnode。源码已经托管在Github上:https://github.com/redraiment/wechat.el,现已收录在oschina。
, n% E8 t7 o; H" l. k' n借助Lisp语言强大的可定制性,使得开发一个公众平台的应用犹如编写一段剧本一样简单!例如本例——开窗游戏,展示了如何给予wechat.el实现自己的应用。
4 p9 Y! r6 I4 D5 F) |2 y( u: E- <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;">;; 定义新的游戏地图
7 f4 C1 D' m: Y5 `# A Y, K7 j - (def-map "/game/5x5.el" ; 对外开放的URL* j! ^8 V1 m# Z& @2 B6 V5 U
- 'tutorial-room-0) ; 默认的入口
1 F1 i7 j- @& S) h6 V
; t8 S! {; ^* d8 t: p$ ?0 m0 y' m- ;;; 游戏大厅
5 H% @2 v# Y7 l$ R+ [7 [ - (def-room living-room. y6 @+ T6 e1 _0 ?) m. y! Q
- ;; 进入该房间后的提示语' g* s8 g% T& J+ ^& f2 z; f3 z
- "1. 教程! ~) I! ~) u) F4 J6 j5 z' A
- 2. 入门(3x3)4 G' g% @- l8 g3 g0 ?, Q$ M8 V
- 3. 初级(5x5)) i2 G+ \) s1 H( K
- 4. 中级(7x7)- n( q2 a g+ ~8 J' X* ?! ]
- 5. 高级(9x9)
, p1 A% ^+ j7 o - 0. 关于作者/ z7 B* q1 E& w; v' S9 _: u" Y
- 请选择1-5开始新游戏:"
7 B& Q( Q. N4 _) V - ("0" about-room) ; 期望用户输入的信息以及相应的后续房间名
' M/ Y% `& y6 t- {$ z+ d/ d - ("1" tutorial-room-0)
r5 M W }; L9 u$ a - ("[2-5]" game-room-init) ; 用户输入信息可用正则表达式匹配
' W* g# \: ^% h% l8 ` - ; 相应的返回也可以为函数,动态返回房间名2 L v0 K( @( k
- (t living-room)) ; 如果条件为t,为永真
! X) n/ O2 b2 B7 b& h# r
( t: l3 I3 ~" u( C3 Y, W3 |- ;;; 作者信息( _" a v9 f( N" @- u8 Q
- (def-room about-room8 D+ h( a# ]5 D' ], \: R1 h' W, p
- "作者:redraiment ]% R3 W( |5 m: T( E- m
- 微博:http://weibo.com/redraiment
3 u4 E, [: E" v$ Q4 w0 H$ d - 有任何建议,欢迎在微博或微信上联系redraiment。4 M' q) x" ^& p
- 请输入任意数字返回游戏大厅。"9 c+ G0 O- t4 v) m3 J
- (t living-room))
. d; P: V! f+ q% N - $ s8 s4 U5 D: ?. z; q
- ;;; 教程0 I1 i( W3 {; ], F( ^: I) R
- (defvar *wechat-5x5-tutorial-rooms* 0
7 ?4 L' G# i. X - "The number of tutorial rooms")' ^; J! z* b6 t7 ?9 q
- : @) K( N3 E; T
- ;;; 简化教程的定义& J) T: [) v2 w( _' m" z9 ]
- (defun string-last-line (content)# P2 R% i5 x2 ]( Z4 e
- "多行内容组成的字符串中的最后一行"
' {- w/ @! f! V* W4 { m' { - (with-temp-buffer! J$ f" x- n+ ~5 {! b$ w
- (insert content)9 y5 W) a+ E4 n6 L% T5 }( i" M
- (buffer-substring (line-beginning-position)9 D! s0 q8 W2 p
- (point-max))))
2 }& [& |% y% W. C, ^2 `( K - ; ]8 N3 D/ `% V( M. c% r1 @* D. T
- (defun def-tutorial-room (prompt)
7 m; D5 V& r0 q- {3 Z8 a6 [ - "根据提示语自动生成教程房间。: @2 [* }; H+ l: |2 S) ?% n( S' Y
- 2 X6 r8 t, p3 x! L1 Z
- 1. 提取最后一行作为问题;9 b5 _7 v( S1 t- H v) l
- 2. 分析问题,获取期望用户输入的内容;
$ |0 d! m7 S1 Q- j9 B - 3. 定义教程房间和重复提问房间。"! i7 T) I2 O& F: h9 ~. b4 W
- (let* ((room-name (concat "tutorial-room-" (number-to-string *wechat-5x5-tutorial-rooms*)))$ R* s9 N3 V# @
- (repeat-room (concat room-name "-repeat"))
. F6 @% i$ E& E2 n" F" m- y; Q - (next-room (concat "tutorial-room-" (number-to-string (incf *wechat-5x5-tutorial-rooms*))))8 Q' H1 m+ K# a* n1 Q
- (question (string-last-line prompt))
7 a" p9 c# c9 N {3 k. C6 ] - (except (if (string-match "请输入“\\([0-9a-zA-Z]+\\)”" question)
$ [3 b8 c0 f3 n2 N- W( V( s5 A7 h - (match-string 1 question)))1 x* K, L% o( u
- (doors (if except
# ]( Q/ o) } f/ Z1 U4 J - `((,except ,(intern next-room))
: L; @$ f3 a8 T% Z; W, c' S( B - ("q" living-room). a5 ]/ z' ~* T# c U* J4 X
- ("Q" living-room)
0 p# g5 L+ x) G, v7 `% E" _7 u1 s - (t ,(intern repeat-room)))
6 j! V/ v0 J& O$ ~9 k& l - '((t living-room)))))
6 T) p1 H* Z: W9 } Q - (def-room-raw (intern room-name) prompt doors): o" n0 M' X# ~1 Q/ e
- (def-room-raw (intern repeat-room) question doors)))
. @: l$ z. o1 s, a C' R( O$ B
# T' a# ~6 R/ [5 g4 Y/ E- W/ T, S- (defun def-tutorial (&rest prompts)! a5 y- H5 B# T" `
- "批量生成教程房间。"3 [# s4 Y& ]% x
- (dolist (prompt prompts)
" e3 m" G7 G6 b [) ]9 v& L* n5 D - (def-tutorial-room prompt)))) V/ ?, ?- v% }6 S; u
- 5 I ~' A& f3 N2 \: x7 L7 T) [
- (def-tutorial
' I3 C- \/ k6 k+ a- v- B% a - "欢迎体验微信版的开窗游戏!为了让您尽快熟悉游戏的规则,请根据教程提示一步一步完成要求的操作。注:任何时刻,您都能输入“q”来退出本教程。
2 t1 K( B5 R2 r: I9 M9 k+ Q - 1. 教程4 B% U- s- P4 y" o ]
- 2. 入门(3x3)* K$ C% ~% s+ }" H
- 3. 初级(5x5)
7 i" i. {& b4 f0 v0 M - 4. 中级(7x7)7 H3 B* s0 n* Z& V& s: S
- 5. 高级(9x9)) k1 I: z" T. v+ g G
- 0. 关于作者* f$ g; {' R$ W0 N: N# C
- 请选择1-5开始新游戏:* s( D/ m& d- K8 b7 u: T& s
- 您现在正在游戏大厅里。
* p& ^( O6 A. }1 @1 Z( Z# c - 请输入“2”进入入门级房间"
8 v, u0 @1 K0 Q* L1 J - " ①②③
, C! z2 W6 G, c! e. { G* }* ~0 Q - 1 ■ 8 i; B! n) \: J
- 2■■■
+ {( `, x% d9 @3 X: T8 ~. Z - 3 ■ $ C, d) z5 t% u5 S, U; s% `$ x
- 进入房间后,您就会看到一个如上图所示的3x3棋盘。其中黑子代表打开的窗户,白子代表关闭的窗户。您可以输入任意一个棋盘上的坐标,来开启或关闭某扇窗户。游戏的目标是开启所有窗户!' y+ w* Q# l, ^
- 请输入“22”来关闭第2行第2列的窗户。"4 o h1 O, ^2 v, E
- " ①②③7 y& d% l: _/ x5 i1 f5 t7 c q
- 1
( w+ m. S1 p7 `$ r - 2 $ B5 T/ c8 S( w: A5 I- E# Z
- 3 ( M% K5 V' @; k0 ]
- 你可能被吓了一跳,怎么所有的窗户都被关闭了?我忘了告诉您:这些格子是被按了机关的,只要一个窗户被开启或关闭,它的上下左右四扇窗户也会连锁反应,被开启或关闭。
" t( d( f2 O9 I# ]: ~6 D$ r9 C - 请输入“11”,试着开启左上角的窗户。" C6 k* |6 { a Y& _
- " ①②③
( J+ a8 m; a$ m" C; ~ - 1■■ $ `7 `, [+ S1 M
- 2■ + [7 t6 i/ i9 w: R# {" ~
- 3
2 J! z% U1 k N3 m7 A Z. T% | - 因为连锁反应,11右边和下面的窗户也被开启了。但因为11在左上角,没有上面和左边,因此这回总共只开启了三扇窗户。* n' S% H8 F0 n
- 请输入“13”开启右上角的窗户。"
' r5 b4 B: o$ p, m1 l+ A - " ①②③
; L9 Y5 o# k4 J' k# V7 M: p - 1■ ■
9 T( T) O3 s% Z. g. e x3 t9 p: Y - 2■ ■# ^ d! ?3 W( O4 ~0 a
- 3
* B V! ^! D2 ?5 R/ K - 第1行第2列上的窗户因为本来就是处于开启状态的,这回因为13的连锁反应,又重新被关闭了。0 s& Q: e# a7 \9 [$ A& q
- 请输入“31”开启左下角的窗户。"
( A, J. y" ?4 z( {0 z - " ①②③( ]' x% q2 |+ ~/ p4 |/ J
- 1■ ■8 q! j$ _& f+ K: c
- 2 ■) _/ N5 {/ k" X8 ~1 e: G' y
- 3■■
\" {9 V* H4 d* `. |8 |' L - 此时,总共有5扇窗户被开启了。/ W/ ` |, Q; Z3 V
- 请输入“33”开启右下角的窗户。"
3 J5 p9 }$ V; R$ y - " ①②③6 q! x( b; a; C7 E. b
- 1■ ■* g. [& C P+ ?9 D) S
- 2
. H4 W4 s( G8 \# P* O: l) f! t - 3■ ■! q3 h; E; m, p% d3 ^
- 现在,只有四个角落的窗户被打开。
1 l, b+ n( I" G - 请输入“22”完成最后一击!"
) o& g m. v+ K+ D* s - " ①②③0 n$ l6 Y4 ?' B2 c% t
- 1■■■
- b' a3 s+ F2 Y9 t& a: V$ k: ^% G - 2■■■' t& e/ T" r8 E2 b3 }( B
- 3■■■
0 d) l p6 L1 X4 n3 F$ U/ m$ T - 您已完成教程的所有内容,输入任意内容返回大厅,开始您的开窗之旅!")
; _, r! i( f0 F! I6 e
/ ]6 f- m3 g! x- M2 h- ;;; 棋盘
" G5 R6 ~9 h1 q; \7 J* j1 q2 L - (defconst *wechat-5x5-white-chess* 12288
# N# N0 R s$ r; c: O7 X A4 i - " ")
# x3 m6 o0 R; z: h1 p1 i7 r
. O5 w7 b) c4 d2 w( n- (defconst *wechat-5x5-black-chess* 9632) _- L, w0 S! z9 A% [& x. k/ C; c
- "■")
9 [; a' h5 G: J# I5 {" u
" U. H$ I5 Q4 e" W1 {- (defmacro with-board (&rest body)
' ^# O# D( h; J, x0 D - `(with-temp-buffer* S/ D" K# S& V
- (unwind-protect, W' S) Z3 L/ q& J- ~
- (progn
! `" b/ g _' K! K4 C! ]$ Y0 Y - (if (session "board")
& h3 O3 J; d( U - (insert (session "board")))1 v$ B+ l, ~: o/ P8 v7 |7 W
- ,@body)% i/ l' h0 E ?" b* \ O% E! b' p
- (session "board" (buffer-string)))))
5 k' [3 }6 ~- u! U. M
: e/ S$ p6 e2 a. p3 k6 W5 s- (defun board-init (size)
4 ?& w% F1 M7 x+ b1 D5 u1 E - (session "size" size)) k1 e; h, i! Y8 [8 e% }. T4 e. U
- (session "step" 0)" K y- V k" L9 P. `9 t- b2 {
- (erase-buffer)
. E e8 L# K% D" G2 g: s - (insert (format (format " %%.%ds\n" size) "①②③④⑤⑥⑦⑧⑨"))
: Y f0 u0 D0 \) g. m4 |& V4 L - (dotimes (row size) T* e, N8 s5 C/ b2 q) _# X7 O% u
- (insert (format "%d%s\n" (1+ row) (make-string size *wechat-5x5-white-chess*)))))
" P! J1 c6 O ?' @ - , L$ L7 ^' ~% \& a1 _2 s( P8 r0 N
- (defun board-contains-p (y x)
, `. ^; S- R+ S$ d6 h D. f - (let ((size (session "size")))
) |+ u6 ?. s; Y - (and (<= 1 y) (<= y size)6 l: O0 C. z1 @1 x4 C* d) P+ j6 G
- (<= 1 x) (<= x size)))) ^7 }7 ^! p# F6 c" F% O; D
- 2 P! |( }$ @& l
- (defun board-toggle (y x)
% ~2 j6 W; t# X+ c1 | ^ - (when (board-contains-p y x): t/ x7 ^( r$ J9 k% Z
- (goto-line (1+ y)): @( Z; P4 X- v7 ~
- (beginning-of-line)# Q8 c* Z, |; t2 s! ~
- (forward-char x)6 r0 f, W/ f3 w& N: n7 |
- (insert (if (= *wechat-5x5-white-chess* (following-char))+ }) V* {2 i0 @0 N2 D( w) J( y' |
- *wechat-5x5-black-chess*
3 _. o0 h) n" X& E6 j7 n, Z - *wechat-5x5-white-chess*))
3 l0 l6 ]4 ^9 H. @# J$ h - (delete-char 1)))" Y$ R5 H: | C* I7 w! |
- & X1 `' |* q4 R' W
- (defun board-put (y x)! h3 Z% Q3 X, t( A2 G
- (dolist (dir '((-1 0) (0 -1) (0 0) (0 1) (1 0)))
$ E5 S% f* \( D( ]% H, t6 C - (board-toggle (+ y (first dir))
+ n7 j' \3 [) Q. v; I# Q" Z, y - (+ x (second dir))))): U/ \ L: w1 l, d2 U5 ~
- , `- C' |; L1 X% F* V3 @: o
- (defun game-over-p ()4 Y+ d% @, d$ G" X: m m
- (beginning-of-buffer)
. n2 `, {) u2 U2 J4 ` - (not (search-forward (string *wechat-5x5-white-chess*) nil t)))# h/ f" q; [4 x: a& ^. M5 r
- % `: Z( X0 t, m4 z3 |
- (defun board-show ()5 ~; z: y. l7 O
- (with-board7 u$ R) y' t6 q$ p# h
- (concat (buffer-string)
, W/ D5 c6 j5 A% ]# ?% ? - (if (game-over-p)/ X6 L7 \, P; h5 c# I
- (format "共%d步,输入任意内容返回大厅" (session "step"))6 I/ R! d0 \! }9 Y# v {
- (format "第%d步" (1+ (session "step")))))))! z* c' z4 |( @9 [) d5 `9 [
- % q- _ E- ^" T9 f
- (defun board-position-parse (cmd)+ ?& E1 D# u0 y% u" R
- (if (= (length cmd) 2)
: o; o: o; C+ G) ~1 | - (list (string-to-int (substring cmd 0 1))
* W# _) V' O1 u. ] - (string-to-int (substring cmd 1 2)))
G- c% [& N6 V8 d( N - '(0 0)))
3 C* f5 K3 d7 I9 L - : R# f d" x) f$ h6 _: t/ W
- ;;; 游戏房间
3 T1 w4 [+ v5 u8 U' f% Y - (defun game-room-init (cmd)- s% z8 F" r% C5 b. v
- (let* ((middle (string-to-int cmd))0 M' U2 i( w$ e+ n( r
- (size (1- (* 2 middle))))( C' F; @7 \; i6 a" U8 k
- (with-board8 d, H) N5 I7 N2 z
- (board-init size)
. _" H+ g' V0 Q+ C/ Z$ S' P - (board-put middle middle)))
5 ?7 C& J& k! f2 F' A2 @: o6 e5 A8 J1 g - 'game-room)2 S) \# _2 A! w: o5 n
- 5 L8 F% {; u) [# F- G+ P# M+ t
- (def-room game-room1 w, {5 ?; M1 z2 j4 o
- #'board-show
9 \6 s/ P( }$ M% k( G - (t (lambda (cmd)
: c: A! N2 T' w& s5 J4 B: G& p - (with-board
3 g3 C M/ ?' k. q. J0 H/ n - (if (game-over-p)( V) y' Z6 q# q& D
- 'living-room y0 W2 a6 a n! U2 B/ \- K
- (destructuring-bind (y x) (board-position-parse cmd)9 g) R1 D" \: \& ?2 B" b ?
- (when (board-contains-p y x)
; {( J; y4 u8 b5 \4 @5 T/ B - (board-toggle y x)7 s+ V3 x7 `9 ~4 a C7 i5 b: g
- (session "step" (1+ (session "step"))))
5 V! p! p( d8 w* I S- F* j - 'game-room))))))</pre>
复制代码 |
上一篇:微信扫描登录下一篇:微信红包
|