wechat.el是用Emacs Lisp打造的微信公众平台开发框架,基于elnode。源码已经托管在Github上:https://github.com/redraiment/wechat.el,现已收录在oschina。# L" r$ P$ H0 q8 ]2 s, ?' w3 l
借助Lisp语言强大的可定制性,使得开发一个公众平台的应用犹如编写一段剧本一样简单!例如本例——开窗游戏,展示了如何给予wechat.el实现自己的应用。
$ r3 t# p: S, u. J2 I& P- <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;">;; 定义新的游戏地图1 _0 \) [3 R) \$ o# |
- (def-map "/game/5x5.el" ; 对外开放的URL" s, y' [+ S6 Y+ b3 {
- 'tutorial-room-0) ; 默认的入口
% O. j) o% E+ V& j' X! J0 _( I - ) `4 ?/ A' P1 ^) ]7 |
- ;;; 游戏大厅
) ~& B, S3 D0 v8 Q1 ^ B0 ?1 D - (def-room living-room
. k4 ^* n% k$ i0 A9 v7 G4 _8 W2 v3 `4 Q - ;; 进入该房间后的提示语
; G7 @4 C2 W: U/ b# }, N2 [1 N - "1. 教程4 I: J! X! i4 w
- 2. 入门(3x3)/ ~5 i# B0 C0 q
- 3. 初级(5x5)3 F. t8 H. S1 I& b2 }& {' j
- 4. 中级(7x7)
! _+ g1 S2 m1 h - 5. 高级(9x9)0 \! h: T) w, @( t7 h' x6 D
- 0. 关于作者$ K5 F# g) `& z% P
- 请选择1-5开始新游戏:"7 Q$ a; X; N1 `* x t
- ("0" about-room) ; 期望用户输入的信息以及相应的后续房间名% |2 a- }* P# k& C. F0 e( Y
- ("1" tutorial-room-0)
2 b# X& f4 B" D( @8 d/ d - ("[2-5]" game-room-init) ; 用户输入信息可用正则表达式匹配6 A. ^. J* @6 E; H$ U5 D
- ; 相应的返回也可以为函数,动态返回房间名" c. F) g3 v5 D
- (t living-room)) ; 如果条件为t,为永真+ k' @6 v1 z3 t9 k/ d6 I( E4 f4 d
4 J0 m6 S9 V+ M6 Q4 J- ;;; 作者信息% E) D9 Z6 I# V& f- X0 o E# e
- (def-room about-room, b: I0 {1 V: H8 e1 @
- "作者:redraiment
f# @5 f. v* e+ s - 微博:http://weibo.com/redraiment
1 k( m; h- Q1 A+ H3 ?+ [ - 有任何建议,欢迎在微博或微信上联系redraiment。
- y; O4 w* Q: c0 ]+ k, @ - 请输入任意数字返回游戏大厅。"8 F2 I0 |8 G4 ^% C
- (t living-room))
- H2 X+ o" W. [" a4 j- V
2 B# X9 y1 w+ d) e- ;;; 教程* D' p) _9 P/ k( z8 q/ w' P+ n
- (defvar *wechat-5x5-tutorial-rooms* 0
3 \& M5 T7 u6 M( ^1 v! G8 o/ k - "The number of tutorial rooms")
6 \# h! O! s% g* |" {2 N& S# ]
( f7 i% k9 ^3 ^( p# |- ;;; 简化教程的定义: \( J8 I7 S' d7 W; O; ?
- (defun string-last-line (content)* v7 }9 M6 d$ {9 c; Y$ M1 H8 f5 J4 F$ n
- "多行内容组成的字符串中的最后一行" _2 }4 T' I2 Q8 _; w5 P+ i; d
- (with-temp-buffer
1 i/ X/ g4 T( G" S) W: B/ d' _6 ` - (insert content)
2 { g/ m! c+ r1 `4 \) W - (buffer-substring (line-beginning-position)3 M, E9 |+ w C0 ]! R
- (point-max)))), N' F9 q- ^5 v+ ^
- 2 M3 W: L7 E( s2 ?+ L! r5 `0 |
- (defun def-tutorial-room (prompt)
& l" y$ g+ p5 }+ f) p - "根据提示语自动生成教程房间。% E3 j8 c0 C/ M8 ~
4 j; c/ N# T O+ `' w- 1. 提取最后一行作为问题;
% H) M3 U% f5 @: n4 U4 ^4 j0 h5 T - 2. 分析问题,获取期望用户输入的内容;
8 T; d0 e H0 h; t5 g, P% Q/ k7 s - 3. 定义教程房间和重复提问房间。"
/ H0 r5 X9 s9 c/ R: n V) H& L( x - (let* ((room-name (concat "tutorial-room-" (number-to-string *wechat-5x5-tutorial-rooms*)))0 Y4 f; f# U! R% }: @
- (repeat-room (concat room-name "-repeat"))
+ O0 B/ D0 a( ~+ @- u( _! i: L - (next-room (concat "tutorial-room-" (number-to-string (incf *wechat-5x5-tutorial-rooms*))))3 |( F0 A' d8 ^
- (question (string-last-line prompt))
/ r9 a) q+ t# f) a5 t/ B2 F9 Q6 v5 [0 U9 b - (except (if (string-match "请输入“\\([0-9a-zA-Z]+\\)”" question)
% T4 ~2 P' ~8 s# y+ J' x6 z' f - (match-string 1 question)))
1 W# ?7 w& H" R" E$ _+ H! N - (doors (if except
, m0 R8 b+ C \8 M' b' _: n; L - `((,except ,(intern next-room))& U- Y: X! d# w
- ("q" living-room)1 T- J/ ?& P9 t/ C. Y% L! K
- ("Q" living-room)# V6 z$ L2 l. m. }! P
- (t ,(intern repeat-room)))4 g- i4 S- L1 o; Y% L7 z
- '((t living-room)))))- B" L8 q# g# @: f7 o
- (def-room-raw (intern room-name) prompt doors)# _1 O# b% _/ ^3 f
- (def-room-raw (intern repeat-room) question doors)))
- r$ X3 V6 ~9 r6 i! l1 J& T7 M
& U& f4 ]& ]7 q; g- {1 P, M7 p- (defun def-tutorial (&rest prompts)
' T" [) _9 p6 c* S# Y - "批量生成教程房间。"* N6 e( U5 S% W6 k
- (dolist (prompt prompts)9 H \$ u8 r# c. `
- (def-tutorial-room prompt)))
# ]1 p7 k0 c' J8 x3 [: n - $ S1 c! g( I% q3 b$ i% ^. D$ P
- (def-tutorial% y; v- j7 a# p$ R: [5 I
- "欢迎体验微信版的开窗游戏!为了让您尽快熟悉游戏的规则,请根据教程提示一步一步完成要求的操作。注:任何时刻,您都能输入“q”来退出本教程。6 k% \: f4 z ]- w! j
- 1. 教程
: u* h' G" ]8 U& n+ w2 C - 2. 入门(3x3)! e/ |/ E C; Y6 X
- 3. 初级(5x5)7 e) m% ], m8 x* O9 i# q% W
- 4. 中级(7x7)# @2 Y, U5 ~8 S; K; S
- 5. 高级(9x9)
7 B/ L6 K2 q I- l0 ^- t$ H9 } - 0. 关于作者
: O7 a' Z. ^/ H/ z# |" h8 T" ~4 ~ - 请选择1-5开始新游戏:' p% E3 Y; U7 z
- 您现在正在游戏大厅里。
1 v5 W5 q1 @+ ~( ]$ N0 a - 请输入“2”进入入门级房间"
1 _, q5 e# o/ ^6 o% } - " ①②③$ F, B1 U# h' K5 y
- 1 ■
) a5 t6 Q" F3 D* V; g! B - 2■■■+ ]2 U% l, x+ ~6 h
- 3 ■ 3 e% [- r' } K6 u O4 C
- 进入房间后,您就会看到一个如上图所示的3x3棋盘。其中黑子代表打开的窗户,白子代表关闭的窗户。您可以输入任意一个棋盘上的坐标,来开启或关闭某扇窗户。游戏的目标是开启所有窗户!
6 v$ B |" B+ |$ u- t - 请输入“22”来关闭第2行第2列的窗户。"9 ?% ?; Y7 G( k8 W1 N
- " ①②③
& z( ]9 e9 Y6 U5 s3 R3 x/ b - 1 - @/ B- z9 w5 _
- 2
; }/ o5 t: L* z - 3
: W& W+ H5 [( Q% R0 v- L6 T - 你可能被吓了一跳,怎么所有的窗户都被关闭了?我忘了告诉您:这些格子是被按了机关的,只要一个窗户被开启或关闭,它的上下左右四扇窗户也会连锁反应,被开启或关闭。
. H/ C; t# W' m2 N- ~ - 请输入“11”,试着开启左上角的窗户。"" n1 g9 z% k% A4 ]4 Z
- " ①②③
9 x. [& @" s& M6 G _: G% }: x. x6 e/ E - 1■■
! t* x; y4 F3 C0 Q. X0 R2 A* T - 2■ ; O: X6 @3 `% u) f) p
- 3 ; u7 n; ^2 f! f$ _4 v0 h) i' C6 T4 r
- 因为连锁反应,11右边和下面的窗户也被开启了。但因为11在左上角,没有上面和左边,因此这回总共只开启了三扇窗户。
( U! e% r1 L0 T d$ B% ^ - 请输入“13”开启右上角的窗户。"% e: ]8 C0 B, z# p- `2 P
- " ①②③
: b. F$ E9 J8 t+ ~: @1 h - 1■ ■
& o9 A( \3 `2 w3 h& _, B - 2■ ■( Q+ Z! [2 x9 H4 h% ?
- 3
6 R) j: y% @0 R) x9 f - 第1行第2列上的窗户因为本来就是处于开启状态的,这回因为13的连锁反应,又重新被关闭了。* s; s9 f4 e- D3 n
- 请输入“31”开启左下角的窗户。"
0 q7 y2 k: z- R9 o1 k6 N9 { - " ①②③7 S+ [' ~; M7 h9 j; u
- 1■ ■: G1 j; E! c3 ]2 Y. t9 ^! @& W
- 2 ■
% d- ^! s4 U1 o% ]# l0 v) @ - 3■■ ; Y) ?6 z8 w# Z" x
- 此时,总共有5扇窗户被开启了。
' D7 i$ X% G1 _' {7 |7 c: T - 请输入“33”开启右下角的窗户。"' _3 ?, x, ~, V& H
- " ①②③
' F e6 f% d; w" ]9 s2 x - 1■ ■+ }# \$ Z; `9 r" v: o9 [7 e3 r% t
- 2 # M: d& k( }3 t4 y6 M
- 3■ ■
. g. l8 D& u# @5 T7 R# u( [. Y - 现在,只有四个角落的窗户被打开。
3 A e4 ~% I, F8 Q1 U - 请输入“22”完成最后一击!"
9 T) `: k3 _+ X' d2 M$ v' m - " ①②③; q0 h3 w# T- k6 T0 M3 N, W
- 1■■■
& h; M. d* J3 h3 ~# `/ \ - 2■■■
2 A7 R. a, ]: L - 3■■■
7 L, X- z" Q2 w( i B1 b3 W - 您已完成教程的所有内容,输入任意内容返回大厅,开始您的开窗之旅!")8 w& m8 V7 k [# c; l6 W
' U' Y+ ]: D2 u5 n+ d) e1 V- ;;; 棋盘- K5 S: W2 N( i( X2 c/ P4 ~& i2 o& z4 i# d
- (defconst *wechat-5x5-white-chess* 12288
( {8 M' O/ m2 Y! W - " ")- K& W5 T* e( o `, V' ?( N
- ! f& y, c& {4 \# X0 t$ {
- (defconst *wechat-5x5-black-chess* 96321 _$ P3 r% e% b+ ^6 a3 p$ h$ ?
- "■")
$ Z& d& D, N; l2 W8 c; {
( R( n, { B4 A, g l9 H8 l- (defmacro with-board (&rest body)5 Z; Y! |- I2 ~
- `(with-temp-buffer
- ?1 G! U _0 c - (unwind-protect8 Y' Y3 B, ?9 b: }/ L5 B2 G5 ]
- (progn
6 R8 |( o: I ^& ?6 q E+ [ - (if (session "board")" @* w! L+ w, N- k; a; @2 H
- (insert (session "board")))1 J4 B- }+ n; j' p
- ,@body)
0 s3 r; E0 ~% s/ g+ u) C - (session "board" (buffer-string)))))) B- X1 H# E" k# j( \7 ]
- ; e, D, q% q2 H+ A
- (defun board-init (size)" P5 ^6 _3 L2 o) y# K% P
- (session "size" size)
5 q' \! M3 ]8 M1 [ - (session "step" 0)
- O, `/ j$ h: N5 n' k/ x+ ^ - (erase-buffer)
& I. V' w) X5 K: n - (insert (format (format " %%.%ds\n" size) "①②③④⑤⑥⑦⑧⑨"))
+ M( m9 u" ]) R6 i$ p - (dotimes (row size)
+ p! r3 Q2 i4 Z: i4 o - (insert (format "%d%s\n" (1+ row) (make-string size *wechat-5x5-white-chess*)))))
8 E9 r: i+ j9 U' s - + y0 x8 C5 [4 G1 H7 u
- (defun board-contains-p (y x)
$ K o" J+ W# P9 R' s - (let ((size (session "size")))& V0 K1 \: G7 I
- (and (<= 1 y) (<= y size)8 {3 ]8 f( | P7 D
- (<= 1 x) (<= x size)))), u/ C) t- D0 N. m. ]) q
- / {; c" ]9 H0 f0 b
- (defun board-toggle (y x)4 x6 Q- x! w# m3 T' \4 p0 a
- (when (board-contains-p y x)( q: W; p8 k; m" ^1 I: B( d
- (goto-line (1+ y))
+ ]" f) m; H( ^0 n0 } - (beginning-of-line)
$ ]. }; W/ s$ } - (forward-char x)& l9 Q b8 ]- M# b
- (insert (if (= *wechat-5x5-white-chess* (following-char)) O! R2 e, _- x* h* E% ^+ b
- *wechat-5x5-black-chess*
; V2 o$ N0 m2 [3 K - *wechat-5x5-white-chess*))
4 F% `8 r% e# b% p- J" } - (delete-char 1)))
0 o9 R1 M7 O0 {1 O F
$ J# L/ A3 | c( u. Q- (defun board-put (y x)
4 u7 ?( j% E5 P2 X" x; X! B - (dolist (dir '((-1 0) (0 -1) (0 0) (0 1) (1 0)))
/ k) K/ z, G! V$ B' P$ ?& Y [ - (board-toggle (+ y (first dir))& ^; b$ c& @* `0 y- W% A0 ]" y- |( ^
- (+ x (second dir)))))
$ k# D6 i/ p* S. i0 L+ _4 l# H Q - , K0 Y9 C; E }' d) G1 {
- (defun game-over-p ()
( j5 L: S# G% }4 t+ I - (beginning-of-buffer)3 k/ A# b" [8 ?$ m# y( J
- (not (search-forward (string *wechat-5x5-white-chess*) nil t)))+ O% h C$ l5 X2 Z! _0 w$ @
! i7 \" K+ a3 P% a* h; X0 A% I" t- (defun board-show ()
: N* a# f$ u: g - (with-board
7 ^9 Y# N( y% m3 \+ B - (concat (buffer-string)
7 X0 \6 ^2 S. [6 J& K9 a - (if (game-over-p)
$ J7 {' v9 ?6 L' {: }" h/ g - (format "共%d步,输入任意内容返回大厅" (session "step"))
- V+ k% i0 O' c" E( _% a5 c5 M - (format "第%d步" (1+ (session "step"))))))), r2 p, H# P2 d& h R
- % a8 X5 D0 d" s! a$ _, l
- (defun board-position-parse (cmd)
6 o4 y; @2 D1 s. {2 `% R - (if (= (length cmd) 2)0 ?7 w' a! ]) M6 v0 U& C
- (list (string-to-int (substring cmd 0 1))
4 N. @, u( U1 {1 G' N( U+ W - (string-to-int (substring cmd 1 2)))
: I4 P0 S( L* w2 t3 G4 K - '(0 0)))9 D4 T$ ^+ _* E) O) v( M
- * q1 M/ v# p2 r' g/ L
- ;;; 游戏房间
9 e1 f6 a- R/ l! u' z6 S2 q - (defun game-room-init (cmd)" O, W7 ^" t7 X+ V
- (let* ((middle (string-to-int cmd))! x$ `' {3 A& u, ^
- (size (1- (* 2 middle))))0 ^' e. ]5 S9 p7 r
- (with-board
) @ r9 j, T' F0 k2 y - (board-init size)% N% l# {& R+ ~
- (board-put middle middle))). P: q& N7 e- |: d6 a
- 'game-room), y3 O: B6 W9 Q5 j6 B
6 p0 z4 k1 B, Q. C" H- (def-room game-room
0 E- z3 W: q* H$ e" _/ [ - #'board-show( M# Q( D% {# v }8 L! S0 X
- (t (lambda (cmd)& H+ d- a1 e0 O! W b$ P! M
- (with-board
, T6 c' A6 f9 _$ g - (if (game-over-p)' s$ t: V$ t h
- 'living-room% x; U1 T6 }: p+ d
- (destructuring-bind (y x) (board-position-parse cmd)0 I8 |3 w3 i1 z% i. O8 m
- (when (board-contains-p y x)
; r8 D8 Z# z- W# p - (board-toggle y x)
7 E0 C% R- l) @' q: ^ - (session "step" (1+ (session "step"))))
4 @7 j* V8 I. I" H( r) L/ |" V - 'game-room))))))</pre>
复制代码 |
上一篇:微信扫描登录下一篇:微信红包
|