wechat.el是用Emacs Lisp打造的微信公众平台开发框架,基于elnode。源码已经托管在Github上:https://github.com/redraiment/wechat.el,现已收录在oschina。
, H) R' ]+ E, n) O: m' a6 B借助Lisp语言强大的可定制性,使得开发一个公众平台的应用犹如编写一段剧本一样简单!例如本例——开窗游戏,展示了如何给予wechat.el实现自己的应用。
8 X1 X: i9 n- }- <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;">;; 定义新的游戏地图5 S. f! a" h7 B6 d: z$ {& ]
- (def-map "/game/5x5.el" ; 对外开放的URL9 j+ W! R/ Z- |: W. \+ \/ B
- 'tutorial-room-0) ; 默认的入口2 K9 O; r; d4 g3 Y
$ q0 B; O# B3 R6 ]5 X- ;;; 游戏大厅
8 W; u0 p& \9 Q# W/ y+ O; M/ |6 m - (def-room living-room
! p/ Z! u3 M' o3 a. ?; r - ;; 进入该房间后的提示语
) q' H4 ^8 V$ y0 I5 @( ] - "1. 教程9 ?( m3 R; Q$ n0 r! _# d/ P( o
- 2. 入门(3x3)
/ n7 m' H' }0 \$ @6 {& ?0 o - 3. 初级(5x5)
$ K7 V { z t l/ U - 4. 中级(7x7)8 Q# |* x# \5 g
- 5. 高级(9x9)& Y3 B: o1 E" m- L% S; J% @5 N
- 0. 关于作者
; w8 K% F/ z% a* ^ - 请选择1-5开始新游戏:"
3 v: \" H5 [3 F" ~2 A5 f0 | - ("0" about-room) ; 期望用户输入的信息以及相应的后续房间名
5 u' W/ F2 z/ k" p0 n8 H - ("1" tutorial-room-0)
% M6 V/ z+ }3 n' R7 F - ("[2-5]" game-room-init) ; 用户输入信息可用正则表达式匹配
3 g2 F6 R! n) R - ; 相应的返回也可以为函数,动态返回房间名8 m! {+ r8 y" @3 g8 b7 A+ Q
- (t living-room)) ; 如果条件为t,为永真( z7 G# \* t8 q& Y) [
- 0 y8 W$ z1 W m4 U0 x
- ;;; 作者信息
; k) w* ^; h1 [. [1 c; d - (def-room about-room
5 n J9 s/ U- G$ Y2 v - "作者:redraiment
. \. \& c: n! G7 z2 G - 微博:http://weibo.com/redraiment
7 u8 ^+ a- D( u/ Z( S! e - 有任何建议,欢迎在微博或微信上联系redraiment。
6 f' c' x* c/ r - 请输入任意数字返回游戏大厅。"
j. |0 l; h9 P5 i: Q - (t living-room))" A7 ~% C ~* T' m; n% r; A
/ q% [6 M" l4 L+ ^8 ?- ;;; 教程7 i% w/ x. \! k. q1 s: M
- (defvar *wechat-5x5-tutorial-rooms* 08 V; ~# P+ [1 E
- "The number of tutorial rooms")
3 \, s3 N! X6 ^/ V$ O - 4 \+ ~; k0 m7 T& ]$ L
- ;;; 简化教程的定义. D) |( | `/ p# F8 b
- (defun string-last-line (content)* I3 y% F0 ^% K! w$ r9 b# p& W
- "多行内容组成的字符串中的最后一行"! P* K1 t* Q! `/ b; c' R
- (with-temp-buffer; t, ]- }; Q ^0 P2 p3 U& u
- (insert content)
1 p" }- @" N6 X; w8 O* [ - (buffer-substring (line-beginning-position)
, ]7 j+ r+ Q- F: l; w! S - (point-max))))" c- `0 [+ G6 L# h
- ( X! y1 G/ r$ S( e. b
- (defun def-tutorial-room (prompt)* } r3 N$ p4 t4 b* f
- "根据提示语自动生成教程房间。
; c0 j5 s$ |7 P6 \* b: c! A2 q7 j
\! [& l, D& I: b/ U) a& {2 G% ?$ A- 1. 提取最后一行作为问题;/ j, d# D# I. m# Z' q- I* o. g
- 2. 分析问题,获取期望用户输入的内容;
3 c7 x2 o0 D/ J; C% R* O2 t - 3. 定义教程房间和重复提问房间。"! \* r+ n& ?, S) Z
- (let* ((room-name (concat "tutorial-room-" (number-to-string *wechat-5x5-tutorial-rooms*)))7 r5 b' u8 G3 _" {5 v' q2 f9 |5 L V9 ~2 Z
- (repeat-room (concat room-name "-repeat"))
. T; \3 y l5 A" L+ F; ~1 x* h2 d - (next-room (concat "tutorial-room-" (number-to-string (incf *wechat-5x5-tutorial-rooms*))))
- I3 \3 h! C' x Y& i# ] - (question (string-last-line prompt))
# P9 T+ s# G2 e3 i V, N - (except (if (string-match "请输入“\\([0-9a-zA-Z]+\\)”" question)
7 R$ N+ P( O# m) ?. w; L, P* p - (match-string 1 question)))
- n2 q+ a0 y( N, }3 T% p - (doors (if except
- J5 b% t& {! y/ u - `((,except ,(intern next-room))
$ }# N$ q& H- f) S. a - ("q" living-room)# q/ q- W. d& g7 t) y/ M
- ("Q" living-room)
8 q% j5 B6 b0 @; c+ K# Q - (t ,(intern repeat-room)))) l. ]3 k" Z5 z/ n# i
- '((t living-room)))))
* I2 Z. L8 T) K- K7 [; h - (def-room-raw (intern room-name) prompt doors)
5 ~7 j- T; X* d1 | - (def-room-raw (intern repeat-room) question doors)))+ a; c& X4 [$ n4 f6 m2 H1 H4 f+ e
* @9 g& p+ H. y9 l3 y; ?- (defun def-tutorial (&rest prompts)+ V+ c3 O! V/ W0 h
- "批量生成教程房间。"0 O3 I6 U; y( Z. d' O/ z
- (dolist (prompt prompts)2 r9 C" s& `2 L3 ^# o- s- u. L
- (def-tutorial-room prompt)))
! x' F1 y6 y/ B9 ?4 k - ( {; p1 m- n( O( s2 n4 ]0 n
- (def-tutorial8 l9 e% w8 y% X: \9 X$ S8 `
- "欢迎体验微信版的开窗游戏!为了让您尽快熟悉游戏的规则,请根据教程提示一步一步完成要求的操作。注:任何时刻,您都能输入“q”来退出本教程。: g1 a5 `! L3 |" [
- 1. 教程
8 I, C/ J0 O- k& P& P - 2. 入门(3x3)
0 s" e; ?& D0 e3 P7 a - 3. 初级(5x5)
" Z) i4 j$ m8 F) m' k, Z - 4. 中级(7x7)+ j Q/ P/ k1 X) I6 r3 d
- 5. 高级(9x9)
) @7 e" \; ~2 i3 Z5 R6 l; E( u, ^" q; S - 0. 关于作者: v3 X0 _+ T; P' \; x
- 请选择1-5开始新游戏:/ U6 f. B2 t: p4 i8 m
- 您现在正在游戏大厅里。
$ @+ V9 ~) ^' k% D" L5 y4 U - 请输入“2”进入入门级房间"
8 L+ M c3 I E5 n9 D - " ①②③
7 V! h @) I9 I" X6 E! W0 R - 1 ■ ; [. ]/ N! E+ C
- 2■■■6 x$ @1 o& q2 t/ @3 B" K
- 3 ■
/ K% C9 J- Z4 f - 进入房间后,您就会看到一个如上图所示的3x3棋盘。其中黑子代表打开的窗户,白子代表关闭的窗户。您可以输入任意一个棋盘上的坐标,来开启或关闭某扇窗户。游戏的目标是开启所有窗户!
0 E6 d0 v: q# T& E8 f - 请输入“22”来关闭第2行第2列的窗户。"6 R' y( W! ^; C Y
- " ①②③
) C1 z1 S0 s/ m0 q* e6 x* { - 1 , Y* H; n2 M* x& d
- 2 / B. u$ ^& d+ ^4 \7 @! T) _
- 3 5 v3 c. I( o" D
- 你可能被吓了一跳,怎么所有的窗户都被关闭了?我忘了告诉您:这些格子是被按了机关的,只要一个窗户被开启或关闭,它的上下左右四扇窗户也会连锁反应,被开启或关闭。
7 k$ x% @& U8 Q - 请输入“11”,试着开启左上角的窗户。"$ @: b* a$ u" J7 e
- " ①②③
5 j# p; E7 ?; `7 _+ P A6 p - 1■■
; j7 x7 |% J" L2 F& l* v2 J - 2■ & `& G7 |. L8 V: `
- 3
: \- d4 F9 T0 ^" a5 A, k - 因为连锁反应,11右边和下面的窗户也被开启了。但因为11在左上角,没有上面和左边,因此这回总共只开启了三扇窗户。: ^2 M* _$ k( ]( O3 N }& p
- 请输入“13”开启右上角的窗户。"9 @4 L) v" H+ Z" q
- " ①②③8 f0 n8 M& r5 V
- 1■ ■ A0 `% ^1 \8 l9 v( ]
- 2■ ■
, e3 w; r" r- B) d+ ]: S& B- } - 3
& r' W8 p' f0 e) W S: N - 第1行第2列上的窗户因为本来就是处于开启状态的,这回因为13的连锁反应,又重新被关闭了。
% w( ?2 o- U/ X( v6 @ v9 u2 h - 请输入“31”开启左下角的窗户。"; J4 N& |; d! b, S1 N
- " ①②③& E* O) O% G' F4 p1 g7 y3 S* T* K! f
- 1■ ■
2 j; t4 u% {* Z) f' u - 2 ■
' a1 Z' i- t1 B2 j- I. e4 x& m; y - 3■■
5 k5 e" I: g) b- r0 ~ - 此时,总共有5扇窗户被开启了。) K/ b7 W" e. R! Z) o/ M3 M. c
- 请输入“33”开启右下角的窗户。"
- }4 Y2 L z( k, n) j$ o# u5 x - " ①②③# i* \) c7 C' A# {5 L2 c Z) B
- 1■ ■! X) w" w. B! y4 O- Z! ]$ \ J4 d
- 2 * O" ^9 B0 l0 M4 Z5 Z" ~; k
- 3■ ■
* P+ ~! T* L- Y4 y0 b6 I - 现在,只有四个角落的窗户被打开。1 B& ?" R4 d. D5 |6 N) b" W
- 请输入“22”完成最后一击!"
, e6 a t W6 @7 s8 } - " ①②③8 _2 R5 F+ _2 m2 j" @3 U- p& x) g, z
- 1■■■- w9 t5 \- {" a
- 2■■■
- v; Y% f& H N2 C& x- @& A - 3■■■
: p5 k; O/ ^- t5 E/ i+ K - 您已完成教程的所有内容,输入任意内容返回大厅,开始您的开窗之旅!")
: h, P" `- X7 R9 P" g( g
% \1 k7 P* H. u6 |. g/ M# S$ a. E7 G# Q- ;;; 棋盘( [) U% `3 Q/ M$ Z& H1 L+ e+ H4 y0 V/ z
- (defconst *wechat-5x5-white-chess* 12288
2 @9 |8 o3 s" y9 p1 f) B - " ")
$ y% b5 L+ |. _3 B6 B i9 l; K1 Y - ( s( `# g: V; L: _3 T. ?. B
- (defconst *wechat-5x5-black-chess* 9632
8 C C2 X3 I+ [8 P# J0 k( w+ L/ F - "■")
. h) t% g* r. y6 S" u
9 j: \ T" Y' I5 z5 b+ ~/ q- (defmacro with-board (&rest body)
2 g0 O3 T, P1 r. K& r) r - `(with-temp-buffer& R& a; w+ `4 H/ e/ M! B2 i% v
- (unwind-protect
: s! }: \( I$ A K F" z - (progn; ]' U! [' @- X6 F: |# ~
- (if (session "board")# h; E8 y9 g* q0 ?4 y
- (insert (session "board")))# e% }1 s# A/ I2 m
- ,@body)$ V: `$ G6 ~ x+ u0 _
- (session "board" (buffer-string)))))& `, T/ h( l$ h, u# V% c
% Y( P0 M# h h- P8 `: x: m5 i- (defun board-init (size)
% C" s( d' X: \2 J2 o3 u, | - (session "size" size), s7 O; O8 Z( v
- (session "step" 0)
$ t8 A. k4 n) x9 B - (erase-buffer)
- T7 }" }0 a* J$ {+ f - (insert (format (format " %%.%ds\n" size) "①②③④⑤⑥⑦⑧⑨"))- y' C1 Z4 n0 {& z4 I7 ^. S& U
- (dotimes (row size)& i: n; D0 I! N- x
- (insert (format "%d%s\n" (1+ row) (make-string size *wechat-5x5-white-chess*)))))
' @9 a* m; _* C9 z/ n9 K! x0 E
; g ?. k; ^5 A4 {0 a- (defun board-contains-p (y x)
9 B$ Y* T' k) |& H8 ] - (let ((size (session "size")))
3 O1 Q4 g* @4 T0 ? - (and (<= 1 y) (<= y size)
7 X0 U0 v: C" ^ - (<= 1 x) (<= x size))))
- y7 ~5 v: U1 c* \ - 0 N: ]; y2 i! D3 x; q9 _
- (defun board-toggle (y x)
9 w0 C# ^1 o! B3 Y3 Y' G8 b - (when (board-contains-p y x)
' o9 w) w5 d& ^ d# Y - (goto-line (1+ y))
; B- r" I% G I6 _0 g% Y) h3 A6 E" }! q - (beginning-of-line): S- ?! U) ]2 h& P
- (forward-char x)% W6 t; e% b$ G/ w* |
- (insert (if (= *wechat-5x5-white-chess* (following-char))
1 E t0 a8 r8 L) u' t8 S8 q - *wechat-5x5-black-chess*
2 [& O( O* R7 p7 l3 {$ L2 l - *wechat-5x5-white-chess*))
+ F% u o# `* V l - (delete-char 1)))
* }; D6 ?1 ?$ x6 X) `% N, U4 | - 5 _5 ?& A# m) }/ b' n% j
- (defun board-put (y x)
' r+ `6 N7 S, @' |$ q' Y - (dolist (dir '((-1 0) (0 -1) (0 0) (0 1) (1 0)))
% g/ W$ u; A* I7 k; s4 m( F- J7 Z - (board-toggle (+ y (first dir))# f, A2 z* W. f; Y* F
- (+ x (second dir)))))+ ?7 Y9 m4 P4 E% f
: F4 l! x* }; Q- (defun game-over-p ()4 l9 K, y! M: D& }5 W
- (beginning-of-buffer)0 _7 h. O, }2 i+ G/ a6 V" d
- (not (search-forward (string *wechat-5x5-white-chess*) nil t)))
7 K8 @8 F3 d4 a
2 t# h, e8 j- I9 P- R- (defun board-show ()% L1 p3 D! g" A$ p' f u$ s
- (with-board2 G$ } m* w$ b1 M$ P
- (concat (buffer-string)2 I. p" k1 { B5 @; h
- (if (game-over-p)- y0 q/ E: Q4 v. e
- (format "共%d步,输入任意内容返回大厅" (session "step"))- |2 W# z( n% F
- (format "第%d步" (1+ (session "step")))))))
$ p2 k% z5 e! t6 ` U& F - 1 ]1 k9 p$ j; U- K5 ^) Z5 ^
- (defun board-position-parse (cmd)
! g0 ]' P# N3 u, S4 I9 Y0 ~ - (if (= (length cmd) 2)* k5 O3 Z) i. G
- (list (string-to-int (substring cmd 0 1))
- L# C8 S* b& y$ B+ R - (string-to-int (substring cmd 1 2)))( i: I9 {( S5 u( C% k0 t
- '(0 0)))
0 E; b: \$ N+ r% g
5 H8 b. x' F$ `2 r4 v- ;;; 游戏房间
; e" J% g4 P% N \ - (defun game-room-init (cmd)2 P0 E8 w- r* b9 K2 D
- (let* ((middle (string-to-int cmd))' m% e! h% x" N/ P- }8 P6 G
- (size (1- (* 2 middle))))
: P; h0 V. R- |8 g3 k' V; p1 { - (with-board$ K5 C/ K1 C3 A$ ^
- (board-init size)
4 Y R$ }4 ^8 O# u - (board-put middle middle)))# e6 D. E v* z$ ^: C
- 'game-room)
7 |0 E A" ^9 w( X - - Z3 ^: W. `! G6 s( V
- (def-room game-room
0 w* T4 Z0 q# E4 {1 Z - #'board-show+ H* h/ X6 X) b; N6 b# L
- (t (lambda (cmd)& ?; l/ U8 D: ?6 S; W* `$ S8 y
- (with-board" w, _) ^: I6 e; m
- (if (game-over-p)7 C5 D: B4 x- U! I
- 'living-room
# s; Z) Z' R6 y' | - (destructuring-bind (y x) (board-position-parse cmd)8 p" I0 X+ g' S, w# L
- (when (board-contains-p y x)
4 W& Q% j( [5 o+ N- Z+ {! `( F+ H - (board-toggle y x)
3 R* ^1 Q4 e l6 ~ - (session "step" (1+ (session "step"))))$ ]: h, V4 P. w* N) R
- 'game-room))))))</pre>
复制代码 |
上一篇:微信扫描登录下一篇:微信红包
|