wechat.el是用Emacs Lisp打造的微信公众平台开发框架,基于elnode。源码已经托管在Github上:https://github.com/redraiment/wechat.el,现已收录在oschina。
# C3 U# m* y" v1 A$ g0 y借助Lisp语言强大的可定制性,使得开发一个公众平台的应用犹如编写一段剧本一样简单!例如本例——开窗游戏,展示了如何给予wechat.el实现自己的应用。- X* B0 }/ g+ h7 z
- <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;">;; 定义新的游戏地图
" F: M- o. ]* U0 r, M1 ^9 t - (def-map "/game/5x5.el" ; 对外开放的URL. a# X9 y+ ]) p0 f6 x( n5 [
- 'tutorial-room-0) ; 默认的入口1 D- ?6 p) K/ u- G0 D% ~ e/ e
- , f- u5 m# b. `. d3 k; V
- ;;; 游戏大厅
g* o, q( ]0 a4 z% ?# A - (def-room living-room
) c) K! Q7 O1 y% Z - ;; 进入该房间后的提示语1 X; w7 n. y6 E% M9 e5 f
- "1. 教程) q, b# q3 q6 M' T4 F
- 2. 入门(3x3)
4 w4 H& D: r& d - 3. 初级(5x5)0 O' u( h B2 N4 Y1 s
- 4. 中级(7x7)5 q% r& E! G6 t# i7 H: i
- 5. 高级(9x9)
( H, x4 t. @. _' o( u& y. g& \ - 0. 关于作者6 n& c c6 ?" `, `" o
- 请选择1-5开始新游戏:"9 k a$ W/ M; o3 a0 L2 `
- ("0" about-room) ; 期望用户输入的信息以及相应的后续房间名
X5 \! v3 A: }2 W - ("1" tutorial-room-0)
) F6 e, ^$ f3 F' `6 l7 e; _5 o - ("[2-5]" game-room-init) ; 用户输入信息可用正则表达式匹配
2 V) e0 l$ F2 I2 T9 { - ; 相应的返回也可以为函数,动态返回房间名
4 K( |. ^% N; v- b - (t living-room)) ; 如果条件为t,为永真7 v r' i8 x- ^' S3 u# K
- X$ [% \- p5 `' W4 s- ;;; 作者信息
" Z! u$ ?3 P4 P1 @ - (def-room about-room
( m- E) F) j! T5 n - "作者:redraiment
2 H) d7 W, H" x1 X4 _ ^9 }9 L - 微博:http://weibo.com/redraiment h1 }8 Y/ M8 C6 {# a- c
- 有任何建议,欢迎在微博或微信上联系redraiment。1 u/ ]% x: Q4 h
- 请输入任意数字返回游戏大厅。"% m2 o7 h* a( W/ s( v
- (t living-room))! B1 N6 f) z0 N, z4 V2 J9 v" x1 ^
& C* p+ N* ?8 M6 O) c& D; X3 t. a- ;;; 教程# W4 Y) `8 Q; O2 e4 p! H) N
- (defvar *wechat-5x5-tutorial-rooms* 01 a6 G* y$ {3 d$ }- s A
- "The number of tutorial rooms")) S! w) k6 W+ |+ j
- 6 s9 A) R- ^+ y. [5 s
- ;;; 简化教程的定义3 [$ D- d' h5 v. c p
- (defun string-last-line (content)) g0 n7 s6 _- J1 l; |
- "多行内容组成的字符串中的最后一行"% n! o5 L b1 Z# c2 g& c# j) k
- (with-temp-buffer
- J! _* u- z4 K. D9 h% }) X - (insert content). D' v6 j5 ]5 T5 D
- (buffer-substring (line-beginning-position)
7 u: x+ K. ?5 j# D - (point-max))))" e; z3 Y9 \; s0 V8 I
- ! |1 _; ~5 @* D( D6 T
- (defun def-tutorial-room (prompt); m6 P! M! z4 I+ j4 z+ b" [
- "根据提示语自动生成教程房间。
( M# {% r8 A5 c% Z$ m9 m C - ' G7 e: ?" X8 ^: G' l6 T4 ?
- 1. 提取最后一行作为问题;
. Z1 E$ w, H5 C2 u - 2. 分析问题,获取期望用户输入的内容;$ L& n1 S: s& n7 U- z
- 3. 定义教程房间和重复提问房间。"
. A0 c# S' K1 v, u2 b/ Y - (let* ((room-name (concat "tutorial-room-" (number-to-string *wechat-5x5-tutorial-rooms*)))
) X8 J0 c2 x+ ? - (repeat-room (concat room-name "-repeat"))
$ Y1 B8 j4 x5 v; m' `" B# B - (next-room (concat "tutorial-room-" (number-to-string (incf *wechat-5x5-tutorial-rooms*)))); |# A2 c' c9 n
- (question (string-last-line prompt))
5 n: D" J5 q; V/ m7 N: T% @! X - (except (if (string-match "请输入“\\([0-9a-zA-Z]+\\)”" question)
# M8 o; X& U* o7 | - (match-string 1 question)))& ^% o" e" T7 t7 S' N7 O1 ]
- (doors (if except
: j E+ ^3 i/ h1 [" T3 }: j5 r% M - `((,except ,(intern next-room))
; V! M: b/ r8 c e& W - ("q" living-room)
" I- b5 ~5 H8 n; L+ m2 z, X8 N - ("Q" living-room)
: z; |5 F% \) k: t9 Q1 n - (t ,(intern repeat-room))); t% j+ S- Z# {. t8 t1 r& k3 `$ f& x
- '((t living-room)))))
$ p( f1 A) l0 u - (def-room-raw (intern room-name) prompt doors)( V# u% v; L* |! e
- (def-room-raw (intern repeat-room) question doors)))
, f% X+ v: C- Z7 C; b - $ L E+ h, b4 b, g1 G, _. b
- (defun def-tutorial (&rest prompts)) x b1 e* `* l4 c$ H
- "批量生成教程房间。"; V& t) P. D" S/ }. E- E) ~
- (dolist (prompt prompts)
6 I' A% c9 g9 r- O - (def-tutorial-room prompt)))
! J& i+ a# F; B2 L+ @2 y
, i$ I' r% P) ~! |0 @0 H1 K- (def-tutorial+ G5 T& z% _ g0 P" Y& H
- "欢迎体验微信版的开窗游戏!为了让您尽快熟悉游戏的规则,请根据教程提示一步一步完成要求的操作。注:任何时刻,您都能输入“q”来退出本教程。) q/ _& g2 w q
- 1. 教程% R: K- L8 S2 ^5 W; z9 B
- 2. 入门(3x3)2 C' s: \( G" G: A, k4 C) O7 F
- 3. 初级(5x5)
; k- g/ r* X) h5 q% T5 P6 f5 W - 4. 中级(7x7)
, f- T& S! J% W6 V/ ] - 5. 高级(9x9)1 P" k" J( {+ D( `9 G0 ?
- 0. 关于作者
( L+ \# k3 d4 t - 请选择1-5开始新游戏:
- @. h3 j/ ]; M r - 您现在正在游戏大厅里。, o% w! Q% j5 _5 G* `9 Q$ h
- 请输入“2”进入入门级房间"
7 Z4 f/ t2 l# v9 T- ? - " ①②③
" C" A% P4 P8 U V) j+ A9 V - 1 ■
5 w' | M. T# R# R& k, \9 H! C9 d+ U/ c - 2■■■
& l$ W; A! X% ~! K% N2 { - 3 ■
+ Y! S7 x8 _7 W; C$ q7 j - 进入房间后,您就会看到一个如上图所示的3x3棋盘。其中黑子代表打开的窗户,白子代表关闭的窗户。您可以输入任意一个棋盘上的坐标,来开启或关闭某扇窗户。游戏的目标是开启所有窗户!" Q) o& [" o- N. {
- 请输入“22”来关闭第2行第2列的窗户。"9 `( M+ q2 ?8 S s
- " ①②③, A. c. |/ I$ t% Z
- 1
& ^! j# Q# o3 I2 t# l+ p - 2
g7 V) Z# y+ E! _ - 3 % v6 i& O N7 R8 Y
- 你可能被吓了一跳,怎么所有的窗户都被关闭了?我忘了告诉您:这些格子是被按了机关的,只要一个窗户被开启或关闭,它的上下左右四扇窗户也会连锁反应,被开启或关闭。+ A( q& m; Y) L% e( J* j
- 请输入“11”,试着开启左上角的窗户。". K9 t7 q8 o% N& d7 B
- " ①②③
( L% _. @0 V w( P - 1■■ ' N7 e+ R9 o2 y) _
- 2■ 5 O% n, y5 x8 s1 l% L7 ?1 y; o
- 3 & Z3 u- C8 v% E5 |& V; i
- 因为连锁反应,11右边和下面的窗户也被开启了。但因为11在左上角,没有上面和左边,因此这回总共只开启了三扇窗户。: f! A3 t5 \' Z( r, f! A) s
- 请输入“13”开启右上角的窗户。"$ o5 j3 }& K. {9 ^9 G
- " ①②③
# V3 _9 T' Z* f1 O - 1■ ■
. g' ]; o% B) @ - 2■ ■) @$ J" d. D" B; v
- 3
7 g* L) p0 }' g- m - 第1行第2列上的窗户因为本来就是处于开启状态的,这回因为13的连锁反应,又重新被关闭了。
; n1 [- c: n2 I* i0 M, ] X! `# o - 请输入“31”开启左下角的窗户。"
7 V% c+ P! w0 d0 G8 r* _6 @ - " ①②③9 H# N4 J) C+ a
- 1■ ■2 Z+ K% f& D! U* T7 C
- 2 ■4 B$ b' Y/ L. _$ P- n) L: e3 ?- M. Y
- 3■■ 4 p. O# @$ q/ y7 D @6 o
- 此时,总共有5扇窗户被开启了。
4 f& U9 }( H. V6 ]' r+ ` - 请输入“33”开启右下角的窗户。"; [6 b/ Z8 y/ M% e4 a
- " ①②③! a4 @/ N* e% U! h% X+ V
- 1■ ■* B$ p5 K K0 S8 R1 H6 p' t3 V
- 2
9 `- m; l1 `; u( E5 {) q# ^4 A - 3■ ■4 H ~7 J6 ?8 p( {6 L- T
- 现在,只有四个角落的窗户被打开。* ? W) i8 x: H1 B# n: G' S" A) r* Z3 Q
- 请输入“22”完成最后一击!"4 R9 n' f7 ^/ O4 [' Y: b! O* b) j
- " ①②③" }- N# y% B2 P$ J6 I. L
- 1■■■
9 b6 ~* H' \ I$ p- M - 2■■■5 M% S, ^' h' C( l& B; i$ s
- 3■■■
; K$ B# t+ J- I) M6 l U4 I3 U - 您已完成教程的所有内容,输入任意内容返回大厅,开始您的开窗之旅!")$ n) N9 O, a/ C% y4 [9 z
- 4 {# B5 k2 j% `1 O
- ;;; 棋盘- M$ g8 p/ t! u p* h& M: t
- (defconst *wechat-5x5-white-chess* 12288+ [) |7 ? G: m/ k% h6 ~; r. c
- " ")
/ l3 g6 G) y q0 q! L5 r
) [$ b" K( I1 [9 k5 t9 H- (defconst *wechat-5x5-black-chess* 9632
3 F, q% Q8 q5 h1 q! J% C - "■")
z' w, W( o- u3 f s. @
# h, Q2 t9 f- ?- (defmacro with-board (&rest body)6 t7 G4 V3 e+ Q( |; e
- `(with-temp-buffer
% e5 s4 D# z1 Z1 ]9 e1 s: { - (unwind-protect. I( ]% H: D" l6 u% |+ N H
- (progn
3 H O, [0 J, E. g( t C - (if (session "board"). |7 S# I' e+ a( ~
- (insert (session "board"))); k% W9 Q$ F3 G* n: E6 Q
- ,@body)
6 A S0 ]: @: E, L( A# c5 [" [ - (session "board" (buffer-string)))))
' s' M# n4 C! U. J$ ] - + V2 l p0 y% H' P3 _6 L
- (defun board-init (size)
$ f% r. r; Q: L1 O: W$ k4 W/ } - (session "size" size): u( a7 q, \* [ U9 D
- (session "step" 0)
! u: e% D+ `7 j+ K+ P# I' V - (erase-buffer)
: S" e, q+ N0 W V' ~ - (insert (format (format " %%.%ds\n" size) "①②③④⑤⑥⑦⑧⑨"))" O$ X8 M# }- P6 c/ R( L6 M5 [
- (dotimes (row size)
2 y8 M6 A4 T. t2 X4 h' e' s - (insert (format "%d%s\n" (1+ row) (make-string size *wechat-5x5-white-chess*)))))% t: ^/ x/ _* y G) ]4 @
2 d$ s- H* ?3 \, A- (defun board-contains-p (y x)
0 C& [2 Q3 W8 U% g - (let ((size (session "size")))" r- _; J( x! U
- (and (<= 1 y) (<= y size)0 b& O5 @' |& q$ g9 U1 ?$ \6 ~+ f% e
- (<= 1 x) (<= x size))))
; N1 i7 s0 R$ Z0 d1 O f6 l* m - 5 m3 i5 D9 a- ^( c
- (defun board-toggle (y x)
v" f1 a" c, o, z! S - (when (board-contains-p y x)
0 I/ \$ _) f, {& u9 M - (goto-line (1+ y)): k9 t6 ~- ]+ x6 V
- (beginning-of-line); q# {* Z0 m9 x" ?7 e, h7 d
- (forward-char x)+ H! G o( ]6 C2 z. r# l
- (insert (if (= *wechat-5x5-white-chess* (following-char)). {# S+ s# z# x# B- b- v9 |
- *wechat-5x5-black-chess*
0 f. m' M1 j; s - *wechat-5x5-white-chess*))( `& I2 ]" l( A
- (delete-char 1)))! Y. P$ u; k: d6 [ ~
: v' `* Z: a* t; ]( D- (defun board-put (y x)
+ c( Q$ m1 h; m - (dolist (dir '((-1 0) (0 -1) (0 0) (0 1) (1 0)))6 ^4 e$ \$ t' } d
- (board-toggle (+ y (first dir))
! Y' C! i: L t; @ - (+ x (second dir))))): T& i3 v7 u7 f/ n7 G
0 [; O% s& M* A- ^ V7 x" Z- (defun game-over-p ()
4 Z! s& h) a& B' x! z - (beginning-of-buffer): ?- r5 q* O9 |$ F* |# t$ k
- (not (search-forward (string *wechat-5x5-white-chess*) nil t)))
! b' U. _( b: m* H2 V, m
1 J$ E* j3 `+ E9 R3 u' X- (defun board-show ()
7 [* ] I/ {) ]. }, E - (with-board
/ e1 ]) c8 x9 w. {$ V - (concat (buffer-string)
( U$ Y& I! }/ ~. u( @7 U; ^ - (if (game-over-p)
4 q @6 \; |' c- P; P - (format "共%d步,输入任意内容返回大厅" (session "step"))8 i7 U& N$ i6 L$ z6 L. v. D, r
- (format "第%d步" (1+ (session "step")))))))
' b1 u* k( M& Z# J$ F - % g# ^, T" P+ o6 r6 N. G
- (defun board-position-parse (cmd)( c! z, H+ w) {5 \' r
- (if (= (length cmd) 2)8 k1 D) B4 c: M0 f/ G
- (list (string-to-int (substring cmd 0 1))7 M$ F" A) W+ x9 K, v
- (string-to-int (substring cmd 1 2)))
0 E% l; d" x3 k( I1 t: N6 h; Z8 o - '(0 0)))
6 Q* ]# g+ R( `& p1 X - 2 e7 E3 y& ?5 `: M' m/ N
- ;;; 游戏房间
. W2 p2 X1 k9 B' H - (defun game-room-init (cmd)- ^, a/ Z( e3 `+ r8 q, U: n
- (let* ((middle (string-to-int cmd))+ X0 V8 `' a( x4 V' e
- (size (1- (* 2 middle))))* [% o; }8 G( X5 S
- (with-board
5 q# a2 V$ N( k1 \$ R: R* v* e1 Z9 e - (board-init size)) i& `1 j5 q; ]7 j5 O9 [
- (board-put middle middle)))& a) i. [6 H' P2 k9 r
- 'game-room)
/ R3 b6 Y, ?" |/ ?8 z
4 c6 M& h5 y& b4 F5 J1 l/ {- (def-room game-room
; d( O6 `* ` B - #'board-show
7 i2 _& Z6 g( X! J - (t (lambda (cmd)+ A! F1 T1 D; {# X% U' G
- (with-board' ~. F' o+ L" j5 B
- (if (game-over-p)
5 ^& p2 F" ?( P0 ^ - 'living-room: A, f6 m/ y0 l' r5 X
- (destructuring-bind (y x) (board-position-parse cmd)
; r; M! W2 d% [6 s6 {3 _1 }4 r - (when (board-contains-p y x)! F# X5 ~! z( q. \
- (board-toggle y x)
1 P' \* w' N b- j - (session "step" (1+ (session "step"))))
3 _0 P4 F5 E/ u8 O. i6 D8 f - 'game-room))))))</pre>
复制代码 |
上一篇:微信扫描登录下一篇:微信红包
|