wechat.el是用Emacs Lisp打造的微信公众平台开发框架,基于elnode。源码已经托管在Github上:https://github.com/redraiment/wechat.el,现已收录在oschina。
" F6 P7 @0 g$ \2 Z借助Lisp语言强大的可定制性,使得开发一个公众平台的应用犹如编写一段剧本一样简单!例如本例——开窗游戏,展示了如何给予wechat.el实现自己的应用。- , ^- M( C7 t2 I1 w4 t; S6 T
- <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;">;; 定义新的游戏地图 a- q r9 x$ T
- (def-map "/game/5x5.el" ; 对外开放的URL
4 w/ ~+ g5 [# g6 D/ j - 'tutorial-room-0) ; 默认的入口
! V4 u, M0 y9 C! U3 E0 L3 R. L - + O2 q( Y3 T5 B1 C' C4 D8 C
- ;;; 游戏大厅
* g) R3 b! j f - (def-room living-room) d8 Z. d9 d8 [% X7 E/ C( T- ^
- ;; 进入该房间后的提示语( {5 n; {' W R2 [' [& G" v
- "1. 教程
; a3 @, n8 b2 `; z! x7 K* ^7 A - 2. 入门(3x3)' F9 j5 i; B) g$ K' V6 h6 i' S
- 3. 初级(5x5)
/ A. P5 V& W" p, Z { - 4. 中级(7x7)& s8 v' }8 s% @8 G; F
- 5. 高级(9x9)
- Q6 A7 y0 b, g6 T+ N - 0. 关于作者$ u- z0 z7 K, a/ v1 o
- 请选择1-5开始新游戏:"8 Z* d/ t/ L. ~0 S+ v
- ("0" about-room) ; 期望用户输入的信息以及相应的后续房间名
4 A( N5 ]- I- X) W h6 l! J - ("1" tutorial-room-0), G# r$ \& s# i" x1 b
- ("[2-5]" game-room-init) ; 用户输入信息可用正则表达式匹配
# X/ `3 u; C) E' s* Y, K3 t% V( }1 k! V - ; 相应的返回也可以为函数,动态返回房间名2 s1 _) D& v0 ~5 n
- (t living-room)) ; 如果条件为t,为永真0 n0 V- C6 A+ V; k2 u: B! s
- * E4 s% P4 s' \- B4 ~, o
- ;;; 作者信息0 U& m" e1 L; T* F6 ~
- (def-room about-room
& s- J- t1 Z* N/ i) }% K) z# ? - "作者:redraiment1 z$ e5 ~9 `. @1 g( c- O. F
- 微博:http://weibo.com/redraiment- X2 `- S5 O4 A5 E8 p
- 有任何建议,欢迎在微博或微信上联系redraiment。
* Q3 }- N3 P1 h - 请输入任意数字返回游戏大厅。"3 `3 C* f9 v; M; @. ]) \( w
- (t living-room))/ r" Q7 B) S- _0 J- ]
- 0 \( m- [1 L+ f+ Q" }
- ;;; 教程: a0 Z- V6 X: P$ H
- (defvar *wechat-5x5-tutorial-rooms* 0
7 N# {9 z# i! w5 Q - "The number of tutorial rooms"), G) Q/ D6 `0 G5 v+ ~6 w7 F9 W
- 6 n- H: }, D: [
- ;;; 简化教程的定义
3 F3 x$ @9 ^" x. y, [ - (defun string-last-line (content)
7 H% N6 G% e0 a/ Q - "多行内容组成的字符串中的最后一行") I7 y/ ~0 g" U
- (with-temp-buffer1 N0 p D) ]" a
- (insert content)
! c: J: u! n4 e( b" o - (buffer-substring (line-beginning-position)
, f1 Y# O7 Q+ C+ g2 L$ c6 S - (point-max))))
8 x; A% O' k1 s- U X2 a
: ^" t$ ]/ o( l4 B$ i- (defun def-tutorial-room (prompt)) d; E$ w& E- w4 C5 N& w# v
- "根据提示语自动生成教程房间。
4 }5 ?- e$ l; _6 J4 s- F - 4 t; z, w( g2 {7 h1 F
- 1. 提取最后一行作为问题;9 E2 P, l# S, b* S
- 2. 分析问题,获取期望用户输入的内容;$ H% z- w* d8 ~
- 3. 定义教程房间和重复提问房间。"8 \3 x X4 A3 o" W# b6 y
- (let* ((room-name (concat "tutorial-room-" (number-to-string *wechat-5x5-tutorial-rooms*)))6 d) k" C3 A" Z
- (repeat-room (concat room-name "-repeat"))
8 k4 j/ u y# Q7 v$ k$ o l - (next-room (concat "tutorial-room-" (number-to-string (incf *wechat-5x5-tutorial-rooms*)))). a+ @6 a0 D2 d6 g8 W$ A3 R2 x8 S
- (question (string-last-line prompt)). Z% B/ g2 N9 J5 A5 |
- (except (if (string-match "请输入“\\([0-9a-zA-Z]+\\)”" question)4 [1 x2 G" Y6 o; O
- (match-string 1 question)))$ k* ], ~% c" o ?) V6 r
- (doors (if except
0 T& `5 ]4 K; `$ R6 `. y - `((,except ,(intern next-room))5 G' B6 S% o3 ~2 ?+ J
- ("q" living-room)
V& \( L0 x3 S- r - ("Q" living-room)
6 r6 j. x+ }) r: v/ C - (t ,(intern repeat-room)))
5 x' f" B; h) L/ j- \. R - '((t living-room)))))
. I# R' I. I' c6 v( ^ - (def-room-raw (intern room-name) prompt doors). B6 {9 Q) y, m8 d5 i
- (def-room-raw (intern repeat-room) question doors)))3 _+ g+ `; v" _
1 ^, y/ i' X, K/ m* L: z) L- (defun def-tutorial (&rest prompts)
0 ^" \7 y& X( `9 t" M& b5 G- a - "批量生成教程房间。"
+ L2 T7 Z9 ~+ A, r/ o" M4 K; A. C - (dolist (prompt prompts)3 d' b7 v! {) N7 p/ i( h/ U6 U
- (def-tutorial-room prompt)))' \# s, z, b/ d, @9 C0 H, ?
- ! H3 _/ h( N0 |1 ~4 z
- (def-tutorial+ a# z5 l9 p8 [( }
- "欢迎体验微信版的开窗游戏!为了让您尽快熟悉游戏的规则,请根据教程提示一步一步完成要求的操作。注:任何时刻,您都能输入“q”来退出本教程。
& A! H* Y1 j8 t N; Q: e# n - 1. 教程
9 s4 s, G e, Q) y- d2 \ - 2. 入门(3x3)
% ]; ~; b$ ~! [! f6 B7 }$ X4 j! O7 z7 ^ - 3. 初级(5x5)
& C. |; G/ o8 F" i* Q; y - 4. 中级(7x7)0 a2 a. j' z7 n
- 5. 高级(9x9)
( O7 _3 ^6 ~6 O8 U8 ~1 O% { - 0. 关于作者! F3 \) x6 T9 _) U
- 请选择1-5开始新游戏:
: G1 r/ {0 c4 a - 您现在正在游戏大厅里。& N' K2 \# M6 F! H
- 请输入“2”进入入门级房间": M' W9 B! c: d. T" `% G
- " ①②③0 I$ \# o2 Q0 C; w5 y
- 1 ■
, [, c2 M% @% g- b" ]6 ~ - 2■■■
5 M, ]+ }8 c v5 Z" ~ C - 3 ■
) ?7 `2 t7 I0 y) w4 [2 s! |* { - 进入房间后,您就会看到一个如上图所示的3x3棋盘。其中黑子代表打开的窗户,白子代表关闭的窗户。您可以输入任意一个棋盘上的坐标,来开启或关闭某扇窗户。游戏的目标是开启所有窗户!
+ f- y3 y8 Y6 h; c G2 @' m% o - 请输入“22”来关闭第2行第2列的窗户。"5 f& K; o2 ]3 Q' E6 [2 C' x9 L
- " ①②③
) ~' ~: D' c# K& C/ e: e/ F% z - 1 4 g) v0 L6 H$ ~& h( U
- 2 - e* d2 }: h7 H' J
- 3 & Z+ y) Q0 D% [! m
- 你可能被吓了一跳,怎么所有的窗户都被关闭了?我忘了告诉您:这些格子是被按了机关的,只要一个窗户被开启或关闭,它的上下左右四扇窗户也会连锁反应,被开启或关闭。, l- C% d* A0 D% X. y, ^" r# q. _: W
- 请输入“11”,试着开启左上角的窗户。"
0 x7 N/ Z/ h% D - " ①②③
d% y% b; H$ x. X - 1■■ 6 l0 ~' H5 ]9 K
- 2■ , g- ]5 F/ G* Z. [, u& s1 v! e1 k
- 3
0 O+ A$ P9 A b, n! ?7 B - 因为连锁反应,11右边和下面的窗户也被开启了。但因为11在左上角,没有上面和左边,因此这回总共只开启了三扇窗户。
* G8 o5 R6 v- T0 E8 x6 y; M - 请输入“13”开启右上角的窗户。"
g$ O1 m" A, r4 I - " ①②③
/ X% k/ s& g) P) r7 Q' B - 1■ ■
) C( s4 w+ K9 r$ X3 _8 y' p( s - 2■ ■
7 c( q6 j8 G# a# }; X - 3
0 N! B# L3 T$ _& U4 n7 o/ ]6 f - 第1行第2列上的窗户因为本来就是处于开启状态的,这回因为13的连锁反应,又重新被关闭了。" E- o2 O9 D" o$ y4 @( I
- 请输入“31”开启左下角的窗户。"
6 E3 |8 w! L# n" Z, n - " ①②③" w3 ~9 V9 L) d Y E5 p5 P
- 1■ ■; [' x( T9 n5 l3 b8 y
- 2 ■! `' x: v+ \; B! q5 b. k
- 3■■
% v' `! P3 y- G2 p - 此时,总共有5扇窗户被开启了。3 _- e4 a0 O7 U1 T, H9 r
- 请输入“33”开启右下角的窗户。"( U# G- L% y( A7 c* l$ C0 d+ O
- " ①②③! X6 p1 T3 d/ A k
- 1■ ■
2 \( T- k7 K! h/ x% _ - 2
1 ]2 l2 X5 I l& j2 Z: m - 3■ ■
1 h) f5 U* d4 [ - 现在,只有四个角落的窗户被打开。
3 d' z/ c6 D" E6 Y- y2 C; Q - 请输入“22”完成最后一击!"
& i4 f/ O0 B$ S+ k' M) v) P - " ①②③
) A: r, K2 w* M: m0 {4 V- s - 1■■■
" _+ K0 E, v9 J" k - 2■■■
5 i. a# J. [. e( }# t- Y - 3■■■
+ N& m! v* c+ w8 j; a4 F. R - 您已完成教程的所有内容,输入任意内容返回大厅,开始您的开窗之旅!")
7 l5 {( a2 z( M+ Z! Y - $ U3 l5 r6 q8 g+ b7 b
- ;;; 棋盘$ w3 e" F4 E+ I/ E r7 @
- (defconst *wechat-5x5-white-chess* 12288% q4 l: h$ i8 @
- " ")
- J: u h* _( ?6 M4 t5 ] - 3 Q: _7 u# Z. d7 o8 N# M) k
- (defconst *wechat-5x5-black-chess* 9632- n* c/ n V8 J4 h" P* A
- "■")5 _ v" u. ^) b0 G/ \
) ^ R' d* K8 I2 `5 V2 M6 G5 D- (defmacro with-board (&rest body)
' f* \" o8 b1 o+ |8 v b u - `(with-temp-buffer: ?& c' F( S' n5 U- s U3 A
- (unwind-protect$ ?( @3 L* F% H& Q
- (progn2 K; r7 e, I4 F" y
- (if (session "board")' ~$ j* M( M. H0 @
- (insert (session "board")))
2 N* o" S- ]4 J2 z9 e - ,@body)
. u: A: G% o2 m& y - (session "board" (buffer-string)))))
, v! U( @, n7 f0 ~- [8 ~
: T% ]# q, h* t- m- (defun board-init (size)
0 w: h6 J0 Q. A# J0 J - (session "size" size)
( C9 q- t* w. w6 K - (session "step" 0)( w) z. {0 e! m) z. u$ g
- (erase-buffer)1 R8 O* r( ?/ } l: a& a" f+ [
- (insert (format (format " %%.%ds\n" size) "①②③④⑤⑥⑦⑧⑨"))' B9 N. M: ?( w
- (dotimes (row size): I, b i) w! y* ]' V
- (insert (format "%d%s\n" (1+ row) (make-string size *wechat-5x5-white-chess*)))))
9 k, d# v6 D2 N - 1 u5 `. b1 D% R+ B8 u% K7 S1 q
- (defun board-contains-p (y x)
+ D% N' y: C7 d5 z- h - (let ((size (session "size")))" g; U4 w, c, V' M$ [# [# Q x' Z
- (and (<= 1 y) (<= y size)
- c7 J- h5 D1 i - (<= 1 x) (<= x size))))3 p% f: |+ o: w% D t
- ! b8 L6 n5 n; s8 W1 |% o; \7 E7 U1 L, S
- (defun board-toggle (y x)
7 b B( y3 ]& z% i% D* d - (when (board-contains-p y x)
, P9 [* e8 a6 l - (goto-line (1+ y)) m8 P# p8 ?6 k; J1 K
- (beginning-of-line)% \5 M% O/ ^" |3 K
- (forward-char x)
- c* `" y3 ?; \ - (insert (if (= *wechat-5x5-white-chess* (following-char))
8 e4 g1 }. L- k - *wechat-5x5-black-chess*
: _) P+ b. x1 f* C* P# ~ - *wechat-5x5-white-chess*))
; L# W2 ~0 }3 H- K - (delete-char 1)))
1 E& l3 k3 x* ?0 m" N8 S9 m - 5 w) v ?' J$ L q
- (defun board-put (y x)# s K0 t2 S; w" m Z
- (dolist (dir '((-1 0) (0 -1) (0 0) (0 1) (1 0)))# C. k% c8 b! v- e' q; y$ M0 C) o
- (board-toggle (+ y (first dir))
& t Y) u2 l: D. c$ k; C8 L - (+ x (second dir)))))' ^( y. B3 B* W1 P- l$ K* u3 S7 R
- ' ~) ~# U- j% \
- (defun game-over-p ()2 T$ U1 P% k" F' u9 X3 E
- (beginning-of-buffer)5 m4 h; f' B+ u. U8 {/ m% x2 _0 f+ V
- (not (search-forward (string *wechat-5x5-white-chess*) nil t)))
' M3 L: [% ]! |8 g0 W! w
; B! U' L: g2 h& c7 ?- (defun board-show ()
: n' T. t% y! o) a0 ? - (with-board( k) F0 E; ? X
- (concat (buffer-string)
# l9 u8 |4 x' ^. V9 }! b9 \0 ^ - (if (game-over-p)6 }1 x7 v+ d7 V6 m+ G) h& z
- (format "共%d步,输入任意内容返回大厅" (session "step"))
/ K* {8 a* j, n$ E1 E7 S& K - (format "第%d步" (1+ (session "step")))))))
+ S) n& R5 z( O+ A# ]' z3 y - ! K8 m& @9 M+ d
- (defun board-position-parse (cmd)
3 }; U4 J8 P% F6 ?( c9 f M - (if (= (length cmd) 2)
2 X/ R) r1 B; X0 X2 ~1 D8 | - (list (string-to-int (substring cmd 0 1))
5 y* y0 |8 H& f4 v4 t7 M4 p& l - (string-to-int (substring cmd 1 2)))
1 |" |2 M# r0 S - '(0 0)))4 ]9 p' b" L; F2 s( Q& D
- e4 c, B8 m# F: Q
- ;;; 游戏房间. \$ b+ f2 T: X5 E+ j9 a2 d6 |
- (defun game-room-init (cmd)
: @& [1 ^4 a j( t) l* C - (let* ((middle (string-to-int cmd))
3 O# v3 ]$ F1 b7 v! i; k9 z, m - (size (1- (* 2 middle))))
# _3 B7 @4 i$ l+ g$ Z4 R( F! B - (with-board, v) ^' H8 f+ O% @# D
- (board-init size)/ d) R7 P9 [0 K' `3 l
- (board-put middle middle)))5 J/ {% @0 o$ l6 K% _
- 'game-room)
! P1 D, R& a @6 M. c/ T% G - & ~( Y" t6 i! D5 s
- (def-room game-room
, b& B+ m' r/ S - #'board-show
8 k5 P E8 e+ ?0 y) J1 B; x - (t (lambda (cmd)9 j; ^5 f% O9 K1 z
- (with-board- L; }6 E. z& L, S
- (if (game-over-p)
2 @. b: l: k4 e$ R1 i, v - 'living-room1 v, [$ G8 j: k( h
- (destructuring-bind (y x) (board-position-parse cmd)
% |" e+ ]8 g% {( }9 g - (when (board-contains-p y x)- U0 F% }6 b- s5 G
- (board-toggle y x)5 D* S& F9 z/ _9 @( q+ d
- (session "step" (1+ (session "step"))))
) n8 |5 V# W9 j2 x; z - 'game-room))))))</pre>
复制代码 |
上一篇:微信扫描登录下一篇:微信红包
|