wechat.el是用Emacs Lisp打造的微信公众平台开发框架,基于elnode。源码已经托管在Github上:https://github.com/redraiment/wechat.el,现已收录在oschina。& E# F) Y; N/ m, s7 }8 c p
借助Lisp语言强大的可定制性,使得开发一个公众平台的应用犹如编写一段剧本一样简单!例如本例——开窗游戏,展示了如何给予wechat.el实现自己的应用。
$ t9 `+ i/ \2 @- <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 I+ J7 P5 ~' O" u& u5 ]5 {
- (def-map "/game/5x5.el" ; 对外开放的URL# x* e5 Z: H/ g9 g3 m3 s0 t
- 'tutorial-room-0) ; 默认的入口0 b, f0 }' A8 i t4 f5 [
- 8 @9 s" d1 q3 Y3 j- s6 y
- ;;; 游戏大厅: B2 T2 j& O+ V0 o* @# ?
- (def-room living-room# }! z* a6 ~# _: F1 s& ]7 E
- ;; 进入该房间后的提示语, P" r0 i6 A$ m6 v
- "1. 教程0 Q2 P$ ]" Z4 |& B/ k9 e
- 2. 入门(3x3)% x! l: O4 k" W! t. F
- 3. 初级(5x5)
4 o- w' f# w1 h$ c! Q - 4. 中级(7x7)
1 O+ I5 M1 R$ e, r" i6 m$ \, I - 5. 高级(9x9)
- Y7 G9 h( ^, M" _0 r; i/ d - 0. 关于作者% _5 E9 J' a) y+ O/ w* g
- 请选择1-5开始新游戏:"
: ]1 @6 _" e5 z - ("0" about-room) ; 期望用户输入的信息以及相应的后续房间名! Z+ h# S, [% s( K: j
- ("1" tutorial-room-0)
* M+ o$ k5 e' m: t2 `& l$ f9 O% \ - ("[2-5]" game-room-init) ; 用户输入信息可用正则表达式匹配+ C6 H( c' x, o k, x( W% q
- ; 相应的返回也可以为函数,动态返回房间名
2 r, p! m+ b9 I( n - (t living-room)) ; 如果条件为t,为永真
, _+ o+ w: P- i9 s n% r
5 D2 \5 M& n! S4 Q1 |- ;;; 作者信息3 ^/ ?$ ? D& D5 g; p
- (def-room about-room7 j, }* {+ u3 |7 q9 [/ U7 _
- "作者:redraiment1 A9 C2 f( s6 F% E) R1 [( T, [
- 微博:http://weibo.com/redraiment: Q4 x, ~& I* ` r" q& Y
- 有任何建议,欢迎在微博或微信上联系redraiment。
4 c8 S$ l* M$ f) e. p - 请输入任意数字返回游戏大厅。") k- i9 F, P5 s: Q4 U
- (t living-room)). [! T& _3 j: {
- . u6 ]& m5 W% g" o/ T, U3 R
- ;;; 教程
3 ?* S$ |! N" O Y - (defvar *wechat-5x5-tutorial-rooms* 0
+ \& v# c+ K+ k! K - "The number of tutorial rooms")& H: q' S T4 l
+ r( a( `# P' d g2 a- ;;; 简化教程的定义
! z. c1 }8 j* V - (defun string-last-line (content)
6 |4 `( {- l9 m- P3 E - "多行内容组成的字符串中的最后一行". v. [- t; _4 `% R2 Z: w5 u+ D. o
- (with-temp-buffer5 T" `/ Y u, D" m/ L, A0 f+ Y8 b
- (insert content)
' a' T% O" S! w4 J6 i - (buffer-substring (line-beginning-position)/ w H7 P6 X$ o5 G
- (point-max))))" |/ [* e' i2 w7 {2 \# ^7 d
- / U: p0 [4 [! l0 u: [) R& L
- (defun def-tutorial-room (prompt)1 p* `! N* G0 E% f& L
- "根据提示语自动生成教程房间。& C1 R# K7 A9 Y) P( o- T
- 5 m y/ \& b; L: ]) ]5 q
- 1. 提取最后一行作为问题;7 L1 F: S* U6 e7 T4 S9 r
- 2. 分析问题,获取期望用户输入的内容;
- ]" r* E3 }- F R5 k - 3. 定义教程房间和重复提问房间。"! }* q& A, U5 Y
- (let* ((room-name (concat "tutorial-room-" (number-to-string *wechat-5x5-tutorial-rooms*)))2 m7 t( o% _& c3 Z. q! ?
- (repeat-room (concat room-name "-repeat"))
. t! a% p. C, _3 j - (next-room (concat "tutorial-room-" (number-to-string (incf *wechat-5x5-tutorial-rooms*))))% p6 \4 t" J* o8 O( L
- (question (string-last-line prompt))! y$ V Q; R: N; z
- (except (if (string-match "请输入“\\([0-9a-zA-Z]+\\)”" question) Z1 ~/ y2 p- B. W' s
- (match-string 1 question)))' i6 j* j! o1 ~
- (doors (if except, H: `9 z# Z2 Y. v, D, [
- `((,except ,(intern next-room))0 x# T& W+ c `' B( m; g6 L6 h
- ("q" living-room)
1 W) ?# [3 [! r - ("Q" living-room)) E* C5 u m/ b( P" Z) z
- (t ,(intern repeat-room)))- D6 ?( Y/ d2 E, I
- '((t living-room)))))4 o" y! o; x" i0 b' `8 r4 F& G
- (def-room-raw (intern room-name) prompt doors)6 Z" ?( p, t( O4 e7 k
- (def-room-raw (intern repeat-room) question doors)))( w) U" C/ U4 r4 O% d$ x
- + r' }, p6 P! }& V7 Z7 @
- (defun def-tutorial (&rest prompts)
: U: ~! |" L1 w7 n; L$ s! l - "批量生成教程房间。"( G& ?& u# W8 @+ Q& o5 y$ r
- (dolist (prompt prompts)
7 M& e' h( i# {4 t/ k - (def-tutorial-room prompt)))+ e( v2 O* m( `( y0 x7 a
6 @! C# S( ~, a- F- (def-tutorial; x: [$ Q) ]0 y( C& Q
- "欢迎体验微信版的开窗游戏!为了让您尽快熟悉游戏的规则,请根据教程提示一步一步完成要求的操作。注:任何时刻,您都能输入“q”来退出本教程。5 w0 @2 _1 f. ?$ l# ]
- 1. 教程0 ]/ v7 L. x! f _3 j
- 2. 入门(3x3)) J; Q* O9 j+ a. T
- 3. 初级(5x5)8 l& {7 G, \) a$ c( O I' F
- 4. 中级(7x7)1 k. w4 N/ }& u5 d
- 5. 高级(9x9)
+ p! g9 Y( {! j7 Y5 d9 w! |$ d - 0. 关于作者
8 e6 Z: q) I1 o) L0 } - 请选择1-5开始新游戏:: b) b3 ]+ w% j) |, K4 r+ {) K
- 您现在正在游戏大厅里。
- b/ T, M* `3 u - 请输入“2”进入入门级房间"! ~# ^3 z% p4 {# q/ U5 F7 ]% l
- " ①②③1 C% b( g( C i' Z- K( C2 w" [
- 1 ■ : o' b5 P2 h! }1 U: C
- 2■■■
4 a4 H/ m: d; A% C+ k - 3 ■ # I& Y) ^9 l4 l6 `
- 进入房间后,您就会看到一个如上图所示的3x3棋盘。其中黑子代表打开的窗户,白子代表关闭的窗户。您可以输入任意一个棋盘上的坐标,来开启或关闭某扇窗户。游戏的目标是开启所有窗户!) L$ V7 t, J8 d3 [* H- a) `
- 请输入“22”来关闭第2行第2列的窗户。"
( [1 z$ u/ f( N/ B - " ①②③+ h, S t3 T1 O7 m* t5 j
- 1 ! i& \, [ H( e2 R
- 2 2 q0 r+ y1 h$ ~: W2 G
- 3
: ~% a' k: y3 {7 }. u - 你可能被吓了一跳,怎么所有的窗户都被关闭了?我忘了告诉您:这些格子是被按了机关的,只要一个窗户被开启或关闭,它的上下左右四扇窗户也会连锁反应,被开启或关闭。8 U2 U( U3 Y6 t' {7 g
- 请输入“11”,试着开启左上角的窗户。"
* G3 c' `) b" J2 _! E - " ①②③
+ z1 L; k( z( B - 1■■
- W) G' K. _: z3 u! Z/ ~* V' p) ^ - 2■ ) }# H, W" p% k- K. k1 P
- 3
' T w% z1 ?' \1 p9 ^ - 因为连锁反应,11右边和下面的窗户也被开启了。但因为11在左上角,没有上面和左边,因此这回总共只开启了三扇窗户。
$ Q& n) c# j( X - 请输入“13”开启右上角的窗户。"5 a4 u0 X" h$ E
- " ①②③
/ D- H3 [. Q' @% b& y - 1■ ■
5 I: D9 O$ w6 B$ X - 2■ ■
1 A& j7 \! d S) P4 _ - 3
/ ?+ e( k/ C. ]5 ?# ? - 第1行第2列上的窗户因为本来就是处于开启状态的,这回因为13的连锁反应,又重新被关闭了。- O% ^/ d( J+ N, N
- 请输入“31”开启左下角的窗户。"" F" _3 a/ E g: \9 s' N
- " ①②③4 h" ]# L6 S: v" {# q1 R, p
- 1■ ■8 y" g" Q$ B. Q8 a
- 2 ■; {, _7 K/ c: h
- 3■■ 6 p B, J8 U( s# b
- 此时,总共有5扇窗户被开启了。+ Y+ \" R- N" }5 v% N) m0 _3 ?
- 请输入“33”开启右下角的窗户。"2 g. {+ X5 F/ F! f
- " ①②③' N; K0 o1 I5 K/ j* a
- 1■ ■1 S6 o; c2 C- S0 l- b# T- }) E
- 2
& B7 Z! k% \+ M6 l' w- ~( ` - 3■ ■+ L8 z2 ^1 u* p( P- I7 X* |* R* O
- 现在,只有四个角落的窗户被打开。
$ k- @" B, d* B! V' H c1 g# l1 ~ - 请输入“22”完成最后一击!"
$ ^: N0 C" o0 A! l! F0 L" N - " ①②③
2 [3 g) r2 j$ c - 1■■■
" h2 d# L Z z- a. H" a - 2■■■
% l$ @% ^( h3 R8 U - 3■■■. h z; j% I G: u2 R7 K; x
- 您已完成教程的所有内容,输入任意内容返回大厅,开始您的开窗之旅!")
5 K+ _9 q: A% H: [) m7 i" p
8 h6 w& l' k# D$ R; j1 x4 H+ M- ;;; 棋盘% v$ Q* G! x" L: o. J$ o
- (defconst *wechat-5x5-white-chess* 122886 G% f! v! l' n+ E0 k+ n
- " ")
w0 b" k6 l( O0 z# w3 k& ?
4 C, W0 l1 Q7 m O- (defconst *wechat-5x5-black-chess* 9632! \( N! s4 Y9 X! T q
- "■")7 j* [ E/ I" J' a" U$ q$ J
$ z* s6 S% s: J" e/ ~ l0 k- (defmacro with-board (&rest body)
R0 n; B9 D! X m' q - `(with-temp-buffer7 C3 J# I) ^, A/ T3 r0 k
- (unwind-protect& E. a" j$ ~" N3 E9 k5 U
- (progn
' h/ c, [6 C7 U K# o - (if (session "board")
& Z! r% C. d: b+ u: B - (insert (session "board")))
# Q w1 e: }( ^" |7 ` - ,@body)& J8 U; B/ x4 T# L: j* W& R
- (session "board" (buffer-string)))))' x6 t* G: C7 N" V6 W8 [
- ) |" c, [9 `# }- S- l4 |
- (defun board-init (size), z3 Y5 i2 r: m; h! ~7 b* w
- (session "size" size)
# d- F" t p: Q" B z+ [ - (session "step" 0), s5 Z: F) E& F# B! M. q( }
- (erase-buffer)- X; O. `9 t3 S4 w
- (insert (format (format " %%.%ds\n" size) "①②③④⑤⑥⑦⑧⑨"))
: V9 n( K, x1 u3 A - (dotimes (row size)
. [8 p' @: |$ \' F9 t - (insert (format "%d%s\n" (1+ row) (make-string size *wechat-5x5-white-chess*)))))# L4 B% i( U- b$ {- c0 r" n
, }* q }4 A/ H& @- (defun board-contains-p (y x)' j1 i v: E/ r( w* M- h0 B9 h
- (let ((size (session "size")))# a+ J# R* K% a# ?$ F
- (and (<= 1 y) (<= y size)
$ \( a( Y7 l0 W - (<= 1 x) (<= x size))))) V" {1 p0 u/ Y, P! Q
- ( {/ g! Q8 i: H2 Z; I) J
- (defun board-toggle (y x)
, f, t0 V* J) W T8 ^. c! L - (when (board-contains-p y x)- W, u8 X/ d6 t2 g
- (goto-line (1+ y))
! v3 V1 S3 V b) v' b, { - (beginning-of-line)
: L: Y' L u w4 H6 G - (forward-char x)
" \" E/ S. n* L - (insert (if (= *wechat-5x5-white-chess* (following-char))
R) t9 G ?: m - *wechat-5x5-black-chess*
I8 b! |: Q2 p' f9 o- T - *wechat-5x5-white-chess*))9 l, C5 u G( j" A
- (delete-char 1)))" Y) J6 a5 g- G8 Z, y
- ' A J# h, u( T% `' J \4 L
- (defun board-put (y x)4 G3 J$ l4 ~" K+ \. P, q" u$ p
- (dolist (dir '((-1 0) (0 -1) (0 0) (0 1) (1 0)))5 j& h0 g6 O/ W2 Z$ H" a1 C$ ?$ H
- (board-toggle (+ y (first dir))5 e# D1 Y3 d, [% J$ t
- (+ x (second dir)))))
! D/ Y1 q* u5 D0 J - 8 o, u* j4 a h
- (defun game-over-p ()/ o& U. m7 S6 L+ x. z; }; Z
- (beginning-of-buffer)0 t$ G; e3 t7 ^9 L d
- (not (search-forward (string *wechat-5x5-white-chess*) nil t)))& P0 j& f3 k! B2 D: m& `
5 S, c" P0 s% a- (defun board-show ()
# w7 j5 z* P/ x e% i - (with-board$ H! b, u: }* p: h! p% b7 V9 p
- (concat (buffer-string)9 ]' f" j- p& n' ^4 S+ D4 f; |# [% v8 O! @
- (if (game-over-p)! E( C1 ^- h$ w: n7 B: A. W
- (format "共%d步,输入任意内容返回大厅" (session "step"))0 a z8 E. k; Y
- (format "第%d步" (1+ (session "step")))))))
& s0 N- C8 w( K7 [/ Y) P+ \ - - U3 y4 B% a: i6 a& J
- (defun board-position-parse (cmd)/ n9 u2 [) ]# T* `1 n; a W5 B
- (if (= (length cmd) 2)/ r" V9 ?2 j- `
- (list (string-to-int (substring cmd 0 1))
2 C' U1 b* ?; [4 o/ }0 V) r+ P - (string-to-int (substring cmd 1 2)))
$ g+ O/ L) O; m8 Q' a - '(0 0)))
% O! m/ E3 l W" `1 t7 O" C. p' o - 4 y0 g! p+ l5 \' x" e/ g2 `8 n
- ;;; 游戏房间
j! s1 i0 G) I5 d6 ~ - (defun game-room-init (cmd)" r* q9 e/ }7 W0 S! D, B
- (let* ((middle (string-to-int cmd))
7 |) i/ \: _9 w x- v6 l - (size (1- (* 2 middle))))0 B! ~2 b Q4 j' H
- (with-board4 n/ P, q3 \+ y6 ?
- (board-init size)) X% u4 _& ~3 Q1 w
- (board-put middle middle)))2 [) I4 e' Q! l
- 'game-room)
" C& [7 ]+ H5 x- h
) E8 |. Z7 \. d, K/ J# b2 L- (def-room game-room# {/ q$ J; a- i/ _
- #'board-show
& l# t' O9 y1 g# F# j$ L - (t (lambda (cmd)- `1 W+ N; x9 u, r7 g
- (with-board
# M7 @/ m( ^- r. @# B4 h - (if (game-over-p)$ o8 M. J) {. O6 j- k3 H) _; \. h
- 'living-room0 `9 s$ `# b1 d: D2 d
- (destructuring-bind (y x) (board-position-parse cmd)
* A8 \4 W- O7 |( [ ? - (when (board-contains-p y x)- h( i/ C) ?8 o, q$ z% B
- (board-toggle y x)7 B' Z. j+ U3 C% a, H, N" Q
- (session "step" (1+ (session "step"))))9 }/ }: w+ a; Z1 Q7 G
- 'game-room))))))</pre>
复制代码 |
上一篇:微信扫描登录下一篇:微信红包
|