wechat.el是用Emacs Lisp打造的微信公众平台开发框架,基于elnode。源码已经托管在Github上:https://github.com/redraiment/wechat.el,现已收录在oschina。
# U9 T9 t8 b& a+ D' B+ E借助Lisp语言强大的可定制性,使得开发一个公众平台的应用犹如编写一段剧本一样简单!例如本例——开窗游戏,展示了如何给予wechat.el实现自己的应用。- , E1 ^, W, x- ^5 ~ C
- <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;">;; 定义新的游戏地图
- \9 W6 a; J' a - (def-map "/game/5x5.el" ; 对外开放的URL3 o( v {% J2 q& |' [7 u
- 'tutorial-room-0) ; 默认的入口
H b, d7 k `; y! A9 w* E( T
- A2 @* }- t, A, b- ;;; 游戏大厅+ Q: x3 t% o" S+ b, [ h. g* u2 X
- (def-room living-room
8 c! s0 T" j( Z% ^! d2 o# c - ;; 进入该房间后的提示语
! t8 R; h0 { K0 l t - "1. 教程! a' k1 @4 j5 o* N) t+ j
- 2. 入门(3x3)* Y9 g! F8 M4 `' U" b
- 3. 初级(5x5)! l* E# @" l3 d# w' j
- 4. 中级(7x7)
2 F. g2 L9 x5 v9 S# h - 5. 高级(9x9)
% v) R' O f4 @6 A - 0. 关于作者" f( h6 t$ d& N, `1 k
- 请选择1-5开始新游戏:"
; e* D/ G! l6 x: q# x- g* \ - ("0" about-room) ; 期望用户输入的信息以及相应的后续房间名
4 p2 z9 B. M4 o - ("1" tutorial-room-0)3 K( C3 D' |# K
- ("[2-5]" game-room-init) ; 用户输入信息可用正则表达式匹配/ k' Y: I# M2 w5 ]" I
- ; 相应的返回也可以为函数,动态返回房间名
% ^" J5 S. Y4 C. f- T - (t living-room)) ; 如果条件为t,为永真7 Y3 `0 F1 X7 E P) F; Z
- 7 K/ v+ ?9 i# B
- ;;; 作者信息% ~2 W0 K0 `5 H g5 W
- (def-room about-room$ w; y) v: A: O6 p6 t1 p! G7 w. Q! I
- "作者:redraiment
( X% {, M) r* t - 微博:http://weibo.com/redraiment, G" ~9 V- H# f9 F# q* Y
- 有任何建议,欢迎在微博或微信上联系redraiment。
; ]5 E; o* r! X4 h - 请输入任意数字返回游戏大厅。"7 u* ]4 P7 r" ^9 H7 X4 Z* H) A8 G
- (t living-room))
6 n0 r: s3 u5 i4 i+ G+ M - 1 y% q3 J5 i! Q1 c, ^* _* Q2 s
- ;;; 教程
! V! t* |, E4 ~" t - (defvar *wechat-5x5-tutorial-rooms* 0; u- V$ [( Y7 x' D3 H
- "The number of tutorial rooms")4 I! y6 I. M6 K6 r
- 5 ?) L& b/ d% g. V) h
- ;;; 简化教程的定义
" n8 y+ n. {- Q# r# g3 x- y% s - (defun string-last-line (content)
6 e; s! {+ p$ \0 [ - "多行内容组成的字符串中的最后一行"1 `/ ~9 O4 J6 N5 J. Q3 V% t/ f4 ^7 |
- (with-temp-buffer
! v3 c6 C' v4 K$ C: `+ ]2 n - (insert content)9 @' U/ Z0 H5 o# y `. G7 ]
- (buffer-substring (line-beginning-position)/ p5 m1 }$ t: ]) e7 m$ M
- (point-max))))& |6 G7 o) a& R$ J$ k
- ; ? F# M/ k. q) y. O' u7 a
- (defun def-tutorial-room (prompt)
; y9 n9 H, [' i' { - "根据提示语自动生成教程房间。
4 L" e+ \7 @! \( u$ l" |; i! v' r
, x% N! _ J$ j- 1. 提取最后一行作为问题;0 b* Q# f1 j, N5 L" D
- 2. 分析问题,获取期望用户输入的内容;
2 z+ H9 ^- V9 p m# y# M. ? - 3. 定义教程房间和重复提问房间。"4 b* A3 h5 B/ L/ N
- (let* ((room-name (concat "tutorial-room-" (number-to-string *wechat-5x5-tutorial-rooms*)))8 b& Y x3 p/ s/ L5 k8 O2 R8 ^: h: Y
- (repeat-room (concat room-name "-repeat"))
" N6 y; e5 J0 ~6 _3 j1 v! c& _ - (next-room (concat "tutorial-room-" (number-to-string (incf *wechat-5x5-tutorial-rooms*))))+ l `4 ~* R% o$ o8 a
- (question (string-last-line prompt))
" k% k7 M; o* a2 { - (except (if (string-match "请输入“\\([0-9a-zA-Z]+\\)”" question)
' f& w( x3 g4 K - (match-string 1 question)))
2 x# F! a: X* I. W: Q" u - (doors (if except1 g* [: [) Q9 a) Q7 R2 S% y
- `((,except ,(intern next-room))# S4 z+ L- ~/ ?3 U' `& \
- ("q" living-room)0 I8 M" a6 \4 j+ }+ Q1 s
- ("Q" living-room)) K3 N, k2 m" U9 T5 L6 w' w
- (t ,(intern repeat-room)))' U6 t; l+ a8 U @
- '((t living-room)))))" A8 ^* b ]& ^& V; Q: H
- (def-room-raw (intern room-name) prompt doors)6 I0 C1 L& ?& U+ `
- (def-room-raw (intern repeat-room) question doors)))3 g# ?1 _, `, p" r
) l! h: x' i9 m/ N/ B9 t. e' t* z- (defun def-tutorial (&rest prompts)
2 @7 c4 A; y# ~5 p1 Q - "批量生成教程房间。"
) U [2 q0 r9 ?0 Z8 A - (dolist (prompt prompts)$ N1 O' v+ }. Y2 g7 t* [( D
- (def-tutorial-room prompt)))
% ~) D" U% h0 i! c' q
: J; j6 M& @* P5 ^& ?6 B1 N$ H- (def-tutorial2 d) _. a1 W3 w. }
- "欢迎体验微信版的开窗游戏!为了让您尽快熟悉游戏的规则,请根据教程提示一步一步完成要求的操作。注:任何时刻,您都能输入“q”来退出本教程。+ A. w7 e- s( }
- 1. 教程# Y+ q4 S9 O2 e' J. W' t1 s" L0 z: J3 m
- 2. 入门(3x3)
" r8 p. I$ D6 _5 H - 3. 初级(5x5)8 D# k4 }6 @( |
- 4. 中级(7x7)
' g X6 T8 e- g - 5. 高级(9x9)" g6 K& ]0 _1 G
- 0. 关于作者
* {* |( [+ g3 y. v+ G( q - 请选择1-5开始新游戏:$ x" Z8 A- R, ^' a
- 您现在正在游戏大厅里。# ]3 P F- N, o9 O
- 请输入“2”进入入门级房间"& m2 ?! j0 g5 P9 y
- " ①②③( P5 R0 l& x, l& q& ~& m+ x
- 1 ■ 9 ~- Q2 u) B: Y: o/ j
- 2■■■: }9 J$ {. M+ R, N- j! Q. {' Y
- 3 ■
+ |: g, d& k& R; `* {3 h- I0 p% D7 l - 进入房间后,您就会看到一个如上图所示的3x3棋盘。其中黑子代表打开的窗户,白子代表关闭的窗户。您可以输入任意一个棋盘上的坐标,来开启或关闭某扇窗户。游戏的目标是开启所有窗户!
) b4 G4 j; w0 k. N+ I$ l - 请输入“22”来关闭第2行第2列的窗户。"; g8 {" [. `; Z
- " ①②③
/ q3 M* `7 E1 h1 V( v - 1 0 n; T/ b }, q" a2 N3 q+ P# H0 w2 ^
- 2
: [! W3 k4 n% X( ?6 c7 B - 3
+ S6 G4 K$ A3 C p$ t - 你可能被吓了一跳,怎么所有的窗户都被关闭了?我忘了告诉您:这些格子是被按了机关的,只要一个窗户被开启或关闭,它的上下左右四扇窗户也会连锁反应,被开启或关闭。
* e i6 `9 S; G- ~' ` - 请输入“11”,试着开启左上角的窗户。"
: u" F* x# e' q& b C; ~ - " ①②③9 d; J; o* n V$ k! ^! D: w
- 1■■ ! U0 K: b/ l, N- W
- 2■
0 I, X0 J3 [2 W q- [ z+ c( M w6 p5 } - 3
% e( v4 w8 n! M& N% r$ B - 因为连锁反应,11右边和下面的窗户也被开启了。但因为11在左上角,没有上面和左边,因此这回总共只开启了三扇窗户。: L6 I. h f/ ^3 V
- 请输入“13”开启右上角的窗户。"
/ N! w3 l/ [" n9 f - " ①②③, K) T9 t- j; M: X
- 1■ ■: H ~8 ]1 Q; @9 F0 e$ w' s- ]
- 2■ ■; d* C, ?- p. J3 A4 L
- 3
" I5 f& L/ h+ o/ D- P* P - 第1行第2列上的窗户因为本来就是处于开启状态的,这回因为13的连锁反应,又重新被关闭了。
8 s2 E: W+ |3 D; r% Q$ f( q - 请输入“31”开启左下角的窗户。"
6 O; H4 W2 e- w) n# C. ^3 Q - " ①②③
5 w/ d% s$ ?( z$ M7 C6 e5 I# Y5 K( l - 1■ ■
( E1 x) Z) r. \7 _* {' T; Z - 2 ■; v6 S5 b* U+ K+ {1 r3 |
- 3■■ 8 g- b0 @1 x1 l9 }# K
- 此时,总共有5扇窗户被开启了。
' c5 G' G1 ~ y m% B - 请输入“33”开启右下角的窗户。"
5 ]1 n! a. m, h( b' _! e3 ^ - " ①②③
9 y" U' ~0 t0 q$ U4 x - 1■ ■ f5 ]" k; U- L0 i m
- 2
/ r, l* Y# X! s5 C - 3■ ■
8 ]" T! r) l/ {+ i3 i7 k$ z - 现在,只有四个角落的窗户被打开。
6 _2 J* Q$ N$ l9 n - 请输入“22”完成最后一击!"; q* k# D1 o. O4 o U
- " ①②③8 ^! Q1 [' V4 f9 Q
- 1■■■
# K4 h$ Q4 K* D- I7 p l! g - 2■■■
% T6 B% U" B( h% x+ c! b1 I# b - 3■■■; L U0 V' H+ d; v
- 您已完成教程的所有内容,输入任意内容返回大厅,开始您的开窗之旅!"), ]9 D v& d- i" `( `% n
6 Z& U- Y8 J: U" z- ;;; 棋盘
7 U1 ^" m* e, v o v/ d - (defconst *wechat-5x5-white-chess* 12288
/ W# r) L0 K( O$ [8 n# v! I8 O - " ")8 i( X: d$ C4 D0 E# w; Z
- 2 Q8 G4 L" a8 {/ q3 M: V7 d8 J
- (defconst *wechat-5x5-black-chess* 96324 F* S4 T+ z( q3 P O
- "■")' v9 G0 S, F: y1 x3 `: v
2 ~9 C) j: R) z% Q+ ~4 r( q- (defmacro with-board (&rest body), Y7 `3 n8 p2 Q1 c9 `
- `(with-temp-buffer
% Y2 l' H1 R0 _7 Q' K - (unwind-protect
2 p2 O" |3 d4 V8 T6 Y# B) r - (progn8 [# ?" X( V6 H1 e% v, g# d( w n1 Y
- (if (session "board")9 h& h `2 Q1 x3 ~* ]
- (insert (session "board")))
- C, |! I# U; `. @9 E! J- D - ,@body)% K0 s. `' {1 I1 |* U( F
- (session "board" (buffer-string)))))+ k. d( q5 ~9 a
- 0 H" C" C' j, m% K# _
- (defun board-init (size)
: v% Z. c( p/ e, d9 r - (session "size" size)7 T/ G# q& \9 J* P5 T4 z
- (session "step" 0)
" m5 I$ _8 U2 f& p - (erase-buffer)' K; \" @$ y) E% F$ `% O* b. U
- (insert (format (format " %%.%ds\n" size) "①②③④⑤⑥⑦⑧⑨"))" g( u8 T9 F2 G3 g# T. Q
- (dotimes (row size)% ~! y: a+ J0 C7 P
- (insert (format "%d%s\n" (1+ row) (make-string size *wechat-5x5-white-chess*)))))3 F4 f: z7 v( h& F9 |- G
2 n; r, d# q9 w. X+ i- (defun board-contains-p (y x), N7 T- Q" r' E5 ^- {7 T
- (let ((size (session "size")))
1 a8 j) Q7 F. j, R$ ^ - (and (<= 1 y) (<= y size)% v0 l) q2 W4 v$ r
- (<= 1 x) (<= x size))))# D, q3 k9 l# C z6 Z0 z, O
' n |1 X$ u% y( V0 D& y# |- (defun board-toggle (y x)
: G2 b; h# l' F: S3 W) C8 k" C! k - (when (board-contains-p y x)
z/ X3 r# h/ T t( Y, G - (goto-line (1+ y))$ P2 t& _% C: m) e% ~+ v5 V6 l3 W5 E
- (beginning-of-line), _8 p9 _" b% M
- (forward-char x)
% W# \- F I) K2 ? - (insert (if (= *wechat-5x5-white-chess* (following-char))1 f" e. {% j( t$ s U9 O
- *wechat-5x5-black-chess*
1 Q2 I1 v) Q$ P4 ]1 { - *wechat-5x5-white-chess*))
5 E' z# @5 D, V - (delete-char 1)))% {2 Y1 w* K; a! R$ L
- ! K/ t) [& {* ]9 o& |; b/ C
- (defun board-put (y x)) B# Q7 J+ _: K0 j$ F9 P
- (dolist (dir '((-1 0) (0 -1) (0 0) (0 1) (1 0)))9 b( d ?+ m; e
- (board-toggle (+ y (first dir)). ~$ A( q: F3 ~
- (+ x (second dir)))))3 ~* d$ C5 r1 L0 F
- 4 p2 {0 ?. v% g* U2 E1 w$ c
- (defun game-over-p ()5 z- L& U+ W8 e8 z
- (beginning-of-buffer)
# v0 b) q- j4 b8 t6 H - (not (search-forward (string *wechat-5x5-white-chess*) nil t)))6 S. ?. P' |) G- d
- 6 X% U& N0 C% o7 g9 L
- (defun board-show ()
6 \2 V4 A$ b% ^( z3 ^( s, ^% v - (with-board
. ]+ |* v2 d/ K8 {, Y1 {5 b* ?9 D - (concat (buffer-string)
. s9 |5 A5 F% V+ Q* u: t - (if (game-over-p)
$ {% J. t7 h7 g' j2 _% q - (format "共%d步,输入任意内容返回大厅" (session "step"))
. c+ r3 g" i3 w, m; w - (format "第%d步" (1+ (session "step")))))))
5 T! Y: H; s# Y2 Q% | - 5 D$ F0 L: W- d$ e8 u2 P* Z
- (defun board-position-parse (cmd)/ @$ n- t8 g4 q) m. g
- (if (= (length cmd) 2)8 g; W: V% L' N* k7 Q6 Y, y3 @
- (list (string-to-int (substring cmd 0 1))
! s& e, [# M- i9 y& b0 Z - (string-to-int (substring cmd 1 2)))
9 v5 j2 x) G2 a. l; r3 k - '(0 0)))7 T: o7 t$ |3 P& x. c& W \$ @
% c) _6 e- \5 C& D3 q" d- ;;; 游戏房间
) z% \4 o. U; c8 B0 ` - (defun game-room-init (cmd)! c% M6 c3 U0 X) I: f3 C: h
- (let* ((middle (string-to-int cmd))5 R- _/ i* c& s6 r6 u
- (size (1- (* 2 middle))))
" h* ` U6 s2 q5 c n0 e* V - (with-board
Z8 g- s* ~3 r) V* Z9 O8 D9 I - (board-init size)( c6 D( Q" x9 A- R
- (board-put middle middle)))
/ P. m: e1 K% b: @. _ - 'game-room)
3 D, j3 R h; @7 v! Q. M" P4 p
+ }" J: m# ^8 N( @7 w. @/ g5 Z6 k4 h7 K- (def-room game-room6 b e6 V' G, E$ N+ u) y- m9 s
- #'board-show& r# _* f1 C0 S7 c8 q
- (t (lambda (cmd)
3 a8 V) ~) Q% ?/ J9 @ - (with-board
+ Q* s9 `, @! {/ \7 p - (if (game-over-p)
6 H3 U- P' R s, w+ E4 n, h - 'living-room# s$ v5 ^( Y" q- D) c, `- ]$ Q
- (destructuring-bind (y x) (board-position-parse cmd)& J* S+ A1 p' d) E" x8 ]
- (when (board-contains-p y x)% @( H5 ^0 n+ F# `, U
- (board-toggle y x) q' U# p2 M2 [. K0 @
- (session "step" (1+ (session "step")))). D" P6 {+ L5 Y3 @0 Q0 d3 k1 F1 f
- 'game-room))))))</pre>
复制代码 |
上一篇:微信扫描登录下一篇:微信红包
|