wechat.el是用Emacs Lisp打造的微信公众平台开发框架,基于elnode。源码已经托管在Github上:https://github.com/redraiment/wechat.el,现已收录在oschina。$ ]/ r) @' \- g- h3 K
借助Lisp语言强大的可定制性,使得开发一个公众平台的应用犹如编写一段剧本一样简单!例如本例——开窗游戏,展示了如何给予wechat.el实现自己的应用。- + I& c% G) K. t# _$ b
- <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;">;; 定义新的游戏地图% U3 A. h* u- S
- (def-map "/game/5x5.el" ; 对外开放的URL
5 \# j: A7 p; m. g% X - 'tutorial-room-0) ; 默认的入口
: G3 W9 |) Q$ l/ p6 s - 6 e6 Y. @) s6 z8 j0 g
- ;;; 游戏大厅0 v# I- ~* v8 O; A `/ r
- (def-room living-room! h! ~/ W. e7 u8 p
- ;; 进入该房间后的提示语( ?6 B8 W2 F3 S3 ]/ R0 t8 R8 y
- "1. 教程
3 `' K$ R, H( u# \* O8 D0 h' k& u - 2. 入门(3x3)2 c/ ~# `( M$ d* \+ |: p- M
- 3. 初级(5x5)
3 X4 s* X4 I; }" w* T8 O - 4. 中级(7x7)
3 b% ?3 F& @, s- q- q - 5. 高级(9x9)0 y5 E }/ g6 [+ ~( E0 I2 i& b; p* z
- 0. 关于作者
# m4 ?+ w3 G8 m: N: c - 请选择1-5开始新游戏:"; Q, n- j) K5 J* W: S$ o
- ("0" about-room) ; 期望用户输入的信息以及相应的后续房间名# X* l' y& ]% w- S8 B/ O; x
- ("1" tutorial-room-0)8 U7 \; y2 M( v2 |
- ("[2-5]" game-room-init) ; 用户输入信息可用正则表达式匹配, d5 W: O2 W: c) R5 T0 H+ U
- ; 相应的返回也可以为函数,动态返回房间名4 _' L( q5 W/ U* ]6 e4 d7 @: N
- (t living-room)) ; 如果条件为t,为永真1 R' Z n3 h3 H$ o# I$ i+ ~; S
" F6 e, M8 A) W' A3 C. o- ;;; 作者信息+ k$ p$ f; S0 k+ M% N
- (def-room about-room6 r* f- h# b/ _2 P- y* }$ v7 `& \+ R% m
- "作者:redraiment
1 ^ A h+ i0 p/ i7 U, ~% c7 q - 微博:http://weibo.com/redraiment- ]" s" x. M" y; q+ }
- 有任何建议,欢迎在微博或微信上联系redraiment。- D% N# E7 w( J; r7 H( \8 N9 G, V
- 请输入任意数字返回游戏大厅。"
& S- U0 [# N z$ \9 P2 m! l3 z - (t living-room))
6 N) }/ c/ S& L2 Y( G0 n2 m - 0 `8 @& b/ p8 I o! Z' g
- ;;; 教程
) E1 t' ~( l* Z4 y - (defvar *wechat-5x5-tutorial-rooms* 03 s4 m# l! d$ h5 ~6 m
- "The number of tutorial rooms")( |- W* j0 |; z" ]
& x4 ~0 U1 N+ P) R9 N! c- ;;; 简化教程的定义8 b: L5 G, q) w# V1 {0 Y
- (defun string-last-line (content)1 c2 g, o& s0 }1 y0 V9 g# |4 x
- "多行内容组成的字符串中的最后一行" ^+ [& t; }9 a2 O
- (with-temp-buffer
, u' _& A2 F9 ?! V) k9 X. q8 W* L: o - (insert content)
4 T: C( Q- ^, M2 E - (buffer-substring (line-beginning-position)2 I4 \( d5 t+ c8 S, H4 o
- (point-max))))
( o# R# S8 T1 S' Y - - o5 } f) M1 O2 G+ \1 i5 A
- (defun def-tutorial-room (prompt)! N# @+ B; ?9 k
- "根据提示语自动生成教程房间。
8 o9 J% N8 ?5 ~8 |$ Y N9 P
: J* k- P' t+ ]! Z! H$ c1 [9 w- 1. 提取最后一行作为问题;
# [7 D% ^2 m+ Y+ c' x& v7 ~# d/ F - 2. 分析问题,获取期望用户输入的内容;2 Y" x: @: j3 \4 Z' c |
- 3. 定义教程房间和重复提问房间。"7 W" m/ @$ t% r% X% b
- (let* ((room-name (concat "tutorial-room-" (number-to-string *wechat-5x5-tutorial-rooms*))) o- g. `: \- T, j; u/ @
- (repeat-room (concat room-name "-repeat"))
7 u2 J! W3 o1 i( \2 `& P7 d# f - (next-room (concat "tutorial-room-" (number-to-string (incf *wechat-5x5-tutorial-rooms*))))9 l/ r& k( N" v1 Z6 V
- (question (string-last-line prompt))
& A; R7 [% K" v1 ` - (except (if (string-match "请输入“\\([0-9a-zA-Z]+\\)”" question)6 a. c) [# O$ |9 N
- (match-string 1 question)))2 E& k/ ~ W) d! k+ J
- (doors (if except r( Y- H5 D/ g% G* ~
- `((,except ,(intern next-room))
) k* J6 J+ B. m/ L' Q - ("q" living-room)
; N4 z# w$ f) {/ u# R! R - ("Q" living-room)
) f+ U% V! _1 O' x4 A) l% }2 s - (t ,(intern repeat-room)))
( ?; @0 o1 k5 i% M L - '((t living-room)))))
2 Z6 u7 Z( G+ z& y- s - (def-room-raw (intern room-name) prompt doors)
( @2 T3 E, S8 I6 E% K7 x - (def-room-raw (intern repeat-room) question doors)))
4 f# ^) Q* G) c0 I - . w' W8 U2 s( l# o1 v
- (defun def-tutorial (&rest prompts)
6 M. `5 B$ ?/ ?5 l4 Z - "批量生成教程房间。". C. w2 U8 u# \: U" a. s
- (dolist (prompt prompts)$ X/ i3 A5 R8 T7 l4 ~
- (def-tutorial-room prompt)))
8 b* I& O% V$ e- A) ]; x - 2 v& t. Q3 q4 s" C! T
- (def-tutorial( R8 X$ i1 e) g5 W: S, ^8 r
- "欢迎体验微信版的开窗游戏!为了让您尽快熟悉游戏的规则,请根据教程提示一步一步完成要求的操作。注:任何时刻,您都能输入“q”来退出本教程。% p/ K8 N* P6 ?& B e
- 1. 教程, d+ ]* m0 E7 _, n( z3 ^& d0 F
- 2. 入门(3x3)
/ C7 v- J- d! t7 `7 l3 ?7 ?' S - 3. 初级(5x5)% x( @2 t, L3 a% J! E3 B8 N1 b
- 4. 中级(7x7)
5 B. q' w. U0 D# O - 5. 高级(9x9)
{$ M4 ]5 Q8 m \0 \+ a - 0. 关于作者; A' i# n4 \; ~1 J$ O/ u/ N c
- 请选择1-5开始新游戏:! }5 c% a5 N- v$ ?' h) A
- 您现在正在游戏大厅里。
+ ]% t* \5 K1 V/ g - 请输入“2”进入入门级房间"
" t( _; A7 B/ C8 k# I( J/ b! X7 z - " ①②③
+ {- U c. A( |3 a - 1 ■
# g3 V: }8 f% [" j& s' n- f/ g; @ - 2■■■# w& h+ x. P( C9 |; N& f4 L% B! V
- 3 ■
2 d! x/ E- j3 f4 p% x - 进入房间后,您就会看到一个如上图所示的3x3棋盘。其中黑子代表打开的窗户,白子代表关闭的窗户。您可以输入任意一个棋盘上的坐标,来开启或关闭某扇窗户。游戏的目标是开启所有窗户!1 P* i+ w% }+ d! y: L" ?
- 请输入“22”来关闭第2行第2列的窗户。"
$ H$ p( Q( Z8 \1 i) J - " ①②③
/ }' `" K% U8 K3 Z2 Y4 p* Q - 1
. N5 p& Q' O+ V" h9 C8 y - 2
% H$ [6 c! `7 `& T3 B2 A - 3
6 q6 G8 O+ M& W - 你可能被吓了一跳,怎么所有的窗户都被关闭了?我忘了告诉您:这些格子是被按了机关的,只要一个窗户被开启或关闭,它的上下左右四扇窗户也会连锁反应,被开启或关闭。* w. y; O0 i+ K9 |2 k* ^" i
- 请输入“11”,试着开启左上角的窗户。"4 {- t! h! \( y
- " ①②③4 ^5 `0 g2 U* Y" Y$ j9 M
- 1■■ 3 o# E4 ?/ e/ q, j- I0 [: W
- 2■
6 D& R: L2 P8 s - 3
& d$ |9 H0 C% { - 因为连锁反应,11右边和下面的窗户也被开启了。但因为11在左上角,没有上面和左边,因此这回总共只开启了三扇窗户。
; c2 G4 V2 Y" y9 Z6 L- ?5 _+ u - 请输入“13”开启右上角的窗户。"
4 f* z% h) k- u' ?: t- F" U - " ①②③7 H( B8 b3 S* G
- 1■ ■
& l2 p1 ?# y+ R( E - 2■ ■
; \* d6 p x/ ?& G0 H: F( d3 O - 3 2 L1 @4 U. A1 q% I3 r
- 第1行第2列上的窗户因为本来就是处于开启状态的,这回因为13的连锁反应,又重新被关闭了。( W: S+ k4 Q6 n9 s8 T+ _9 D
- 请输入“31”开启左下角的窗户。", S* D. H# L* c$ V* D' K
- " ①②③" x; K \9 K* b/ Z7 l+ ?
- 1■ ■
5 L3 | L9 s% \$ W - 2 ■
% C, `5 b9 N/ w6 A$ z/ @+ @8 ^3 x - 3■■ % _6 r$ O6 \7 `# g" b/ {1 j: J, U* l
- 此时,总共有5扇窗户被开启了。
s( m6 { X5 t6 p+ h - 请输入“33”开启右下角的窗户。"
+ O- {. \) m7 j - " ①②③' X3 h( E- K B1 g
- 1■ ■% V7 ^2 t$ H% ~
- 2
9 N8 |7 G: M& A# ]4 X% k - 3■ ■
' ?9 c- j! z: W- J8 \ - 现在,只有四个角落的窗户被打开。
2 J: O& r' r' ~0 w2 q - 请输入“22”完成最后一击!"
( R1 u; T+ |8 a' M: F$ f - " ①②③: g$ H5 L1 v+ Y+ y3 p. h3 o
- 1■■■
G. ?. u# j1 z) L6 w, @ - 2■■■
9 i- E2 E$ U/ b7 G - 3■■■# u9 J1 H& Z7 l( ?# }
- 您已完成教程的所有内容,输入任意内容返回大厅,开始您的开窗之旅!")& B. B* }* `: H! d3 ?9 e
- ) |! p( @# l9 |, j7 d
- ;;; 棋盘: Z, s1 ~3 B5 f
- (defconst *wechat-5x5-white-chess* 122881 M% d5 k. k1 Q- R; e
- " ")
% O+ O) ~* {: b
0 ^$ H) Y4 _3 M; s- (defconst *wechat-5x5-black-chess* 96322 N5 X Z1 q6 o% d
- "■")- Z o. i& q6 w% |" U; |: C/ l
- / ~' C0 L7 b$ y
- (defmacro with-board (&rest body)2 N; v5 y7 ?1 u* @$ {1 j/ C- ~
- `(with-temp-buffer
5 J$ |! U% T: U2 T( u& E - (unwind-protect
: [! _+ `) ]3 `3 b2 v5 y - (progn
+ |% d2 F" g& E& ^ - (if (session "board")" @- F, d9 b0 J$ Q
- (insert (session "board")))
Z* D. F7 e* B6 Q - ,@body)7 G& Z: b9 q l
- (session "board" (buffer-string)))))1 S) |* j) d" I; _3 W p3 S' B
- ( M. I* ?% I$ y! Q) o% ]8 q; W( v
- (defun board-init (size)
7 b D. d4 ?0 s2 A" B+ S. l: I2 H0 g% s - (session "size" size): [1 \8 L# o+ |9 h" G7 a
- (session "step" 0)
: A5 ~! R; V( U/ C - (erase-buffer)
# E' F# P) ?& z C- n- x l - (insert (format (format " %%.%ds\n" size) "①②③④⑤⑥⑦⑧⑨"))
; t+ x5 |' q, D; F: R. B4 J - (dotimes (row size) m& F* ^) r* u# o' s( Q) i$ c
- (insert (format "%d%s\n" (1+ row) (make-string size *wechat-5x5-white-chess*)))))3 s$ @: E p* T
Z2 Q8 |2 r6 T: ]# ^) ^8 T! H- (defun board-contains-p (y x)
T. t4 u4 }* o - (let ((size (session "size")))
7 G9 w0 Y& h* l& k8 j: M8 Q1 s% P - (and (<= 1 y) (<= y size)
- O. u! z g% e - (<= 1 x) (<= x size))))
7 I$ q9 p" Q9 D7 U - & I) L: U' P2 B! s
- (defun board-toggle (y x)+ k A1 w$ v# R9 Q2 R) T9 M' w
- (when (board-contains-p y x)
3 g' q# {% Z C, ]8 w - (goto-line (1+ y))/ u! m9 C: y* e5 A' M2 j, H
- (beginning-of-line)3 t! n& c4 j/ z, r2 k7 C
- (forward-char x). W! Z5 n" U$ u' l* I1 m# `
- (insert (if (= *wechat-5x5-white-chess* (following-char))0 D4 x3 c7 U( \/ m S# I7 W: C
- *wechat-5x5-black-chess*3 v l# n7 K* u: p9 s/ I- c; V
- *wechat-5x5-white-chess*))7 f) E% O1 J4 ~4 P1 D0 i
- (delete-char 1)))
$ Q. C- c5 i# ^2 R* s) I+ s
5 H6 f2 \: ^6 Y8 N( `9 p B& @- n- (defun board-put (y x)
0 u* A0 |6 l* M+ W6 g' c& ? D/ g - (dolist (dir '((-1 0) (0 -1) (0 0) (0 1) (1 0)))
1 {+ ~6 F- M; i - (board-toggle (+ y (first dir))
9 e2 q0 Q8 T$ x+ x2 C8 ` - (+ x (second dir)))))' ]5 ?0 T0 A& w5 m) ^% T! H, P
- " U5 L- Q" P- h% @
- (defun game-over-p ()
9 Q! I5 J, x$ C! n2 [ - (beginning-of-buffer)
1 j$ v6 u& w1 }' m) q - (not (search-forward (string *wechat-5x5-white-chess*) nil t)))
7 G; N' h# {2 z - M, ~* j* c* v
- (defun board-show ()& f+ ]2 N( G, N. r
- (with-board
' t' S" e3 K* s- m - (concat (buffer-string)
! P/ g* q- N8 |7 @' M& G0 r; I - (if (game-over-p)
0 Q E+ }; A. K$ g9 [: z - (format "共%d步,输入任意内容返回大厅" (session "step"))+ e. B" _ {9 r+ ^. Q
- (format "第%d步" (1+ (session "step"))))))). _1 \. c8 m+ C$ ^) k3 i
- 5 B6 r" i3 J$ t) ~& {4 t$ |+ j! ]
- (defun board-position-parse (cmd)" ?5 ?8 T' O- l) c
- (if (= (length cmd) 2)
% d: f0 r1 S: b) O" J - (list (string-to-int (substring cmd 0 1))4 j. G2 O$ d# | r& S3 M
- (string-to-int (substring cmd 1 2)))4 ?, q6 }" v! z9 }- F
- '(0 0)))& H: {( q" ` N1 P5 o9 V
- 4 x* h- s; s% I: h: C' y' ]! R
- ;;; 游戏房间
' e1 d' x( Y8 y% E- G9 u - (defun game-room-init (cmd)4 |* [0 {9 j/ o
- (let* ((middle (string-to-int cmd))
# L# r8 u. Q* M9 O$ R5 c - (size (1- (* 2 middle))))- t: z5 |+ d/ T D! I9 ^8 a- b8 m
- (with-board% w1 C& S; d( l% N- V
- (board-init size)
: n+ a! F& H. v, \ - (board-put middle middle)))
6 Y b) Q5 N. j/ a! m% D x6 v - 'game-room)$ t! Z6 o5 u2 t9 W# A) S( W0 Y
- 4 U1 X8 }! Y8 S8 ^9 c7 a# c7 J
- (def-room game-room3 U+ j$ f, C( h
- #'board-show; R- \5 Q) Z) G( i) _8 m5 ?
- (t (lambda (cmd)( m$ b; U+ v X% n% j1 Z
- (with-board: n0 L4 R3 Y1 S
- (if (game-over-p)
% x/ a& P: K* Z3 J4 [3 h - 'living-room) c' [0 w& |* u) F% v: |
- (destructuring-bind (y x) (board-position-parse cmd)0 u3 h/ i" H( P5 m
- (when (board-contains-p y x)
% p z: I: i" j$ o/ e - (board-toggle y x)1 \0 f* b2 ]4 i; }; T/ i2 g/ Z
- (session "step" (1+ (session "step"))))
3 E9 u7 y; z. | u - 'game-room))))))</pre>
复制代码 |
上一篇:微信扫描登录下一篇:微信红包
|