Skip to content

Instantly share code, notes, and snippets.

@youz
Created April 1, 2010 09:11
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save youz/351580 to your computer and use it in GitHub Desktop.
Save youz/351580 to your computer and use it in GitHub Desktop.
A CommonLisp Implementation of the programming language "ModanShogi".
;;; ref. http://github.com/yhara/ShogiModan
(eval-when (:compile-toplevel :load-toplevel :execute)
(unless (find-package :modanshogi)
(defpackage :modanshogi
(:use #+:xyzzy :lisp
#-:xyzzy :common-lisp))))
(provide 'modanshogi)
(in-package :modanshogi)
(export '(parse-kifu run compile-and-run))
(defvar *delimiter-chars* "*△▲")
(defvar *operator-chars* "と歩金銀桂香龍馬玉王飛角")
(defvar *operators*
#(:mov :add :sub :mul :div :mod :push :pop :putc :putn :jumpif :jumpifp))
(defvar *column-chars* "同123456789")
(defvar *row-chars* " 一二三四五六七八九")
;;; conditions
(define-condition kifu-error (error)
(kifu)
(:report
(lambda (c s)
(format s "kifu-error at :~{~A~}" (kifu-error-kifu c)))))
(define-condition runtime-error (error)
(op col row stack cond)
(:report
(lambda (c s)
(format s "runtime-error~%~A~% on ~S(X: ~A Y: ~A)~% stack:[~{~A~^,~}]"
(runtime-error-cond c)
(runtime-error-op c)
(runtime-error-col c)
(runtime-error-row c)
(runtime-error-stack c)))))
;;; parser
(defun readinst (is c)
(let* ((chars (list #1=(read-char is nil nil) #1# #1#))
(inst (mapcar #'position chars
(list *column-chars* *row-chars* *operator-chars*))))
(when (some #'null inst)
(error 'kifu-error :kifu (cons c chars)))
(list (svref *operators* (caddr inst)) (car inst) (cadr inst))))
(defun parse-kifu (source)
(let ((table (make-hash-table :test 'eql))
(i 0) insts last)
(with-input-from-string (is source)
(do ((c #1=(read-char is nil nil) #1#))
((null c))
(when (find c *delimiter-chars*)
(case c
(#\* (let ((label (read is)))
(setf (gethash label table) i)
(push (list :label label 0) insts)))
(t (let ((inst (readinst is c)))
(when (= (cadr inst) 0)
(setf (cdr inst) (cdr last)))
(push (setq last inst) insts))))
(incf i)))
(values (nreverse insts) table))))
;;; evaluator
(defun evaluate (insts jumptbl)
(do ((insts (apply #'vector insts))
(reg (make-array 10 :initial-contents '(0 1 2 3 4 5 6 7 8 9)))
(stack (list))
(end (length insts))
(cur 0 (1+ cur)))
((= cur end))
(let* ((inst (aref insts cur))
(op (car inst))
(c (cadr inst))
(r (caddr inst)))
(handler-case
(case op
(:mov (setf #1=(aref reg c) #2=(aref reg r)))
(:add (incf #1# #2#))
(:sub (decf #1# #2#))
(:mul (setf #1# (* #1# #2#)))
(:div (setf #1# (/ #1# #2#)))
(:mod (setf #1# (mod #1# #2#)))
(:push (push #1# stack))
(:pop (setf #1# (pop stack)))
(:putc (princ (code-char (round #1#))))
(:putn (princ #1#))
(:jumpif (when (/= #1# 0)
(setq cur (gethash #2# jumptbl))))
(:jumpifp (when (>= #1# 0)
(setq cur (gethash #2# jumptbl))))
(:label t))
(error (c)
#3=(error 'runtime-error
:cond c
:op op :col c :row r :stack stack)))
(unless cur #3#))))
(defun run (src)
(multiple-value-call #'evaluate (parse-kifu src)))
;;; compiler
(defmacro w/uniq (names &body body)
`(let ,(mapcar #'(lambda (s)
`(,s (make-symbol ,(symbol-name s))))
(if (consp names) names (list names)))
,@body))
(defun compile% (src)
(w/uniq (greg gstack glabel gstart)
(let ((clauses (list))
(exprs (list gstart)))
(dolist (insts (parse-kifu src))
(let ((op (car insts))
(c (cadr insts))
(r (caddr insts)))
(if (eq op :label)
(progn
(push c exprs)
(push (nreverse exprs) clauses)
(setq exprs (list c)))
(let ((x `(aref ,greg ,c))
(y `(aref ,greg ,r)))
(push
(case op
(:mov `(setf ,x ,y))
(:add `(incf ,x ,y))
(:sub `(decf ,x ,y))
(:mul `(setf ,x (* ,x ,y)))
(:div `(setf ,x (/ ,x ,y)))
(:mod `(setf ,x (mod ,x ,y)))
(:push `(push ,x ,gstack))
(:pop `(setf ,x (pop ,gstack)))
(:putc `(princ (code-char (round ,x))))
(:putn `(princ ,x))
(:jumpif `(when (/= ,x 0) (return ,y)))
(:jumpifp `(when (>= ,x 0) (return ,y))))
exprs)))))
(push nil exprs)
(push (reverse exprs) clauses)
`(let ((,greg (make-array 10 :initial-contents '(0 1 2 3 4 5 6 7 8 9)))
(,gstack (list)))
(do ((,glabel ',gstart
(block ()
(case ,glabel
,@(reverse clauses)))))
((null ,glabel)))))))
(defun compile-and-run (src)
(w/uniq (gfn)
(eval
`(progn
(compile (defun ,gfn () ,(compile% src)))
(,gfn)))))
(defvar *kifu-fib-1to1k*
"▲9九金 △8七金 ▲6四歩 △5五歩 ▲6六銀 △6五銀 ▲7七金 △7六金 *1 ▲7二角 △7一歩 ▲8四王 △5八玉 ▲8八龍 △8九歩 ▲9二馬 △1一飛 *2"
"fork of http://github.com/yhara/ShogiModan/blob/master/examples/fib1000.modan")
(defvar *kifu-fib-10k*
"▲9九金 △8七金 ▲6四歩 △5五歩 ▲6六銀 △同 銀 ▲7七金 △7六金 *1 ▲7二角 △7一歩 ▲8八龍 △8九歩 ▲9二馬 △1一飛 *2 ▲8四王 △5八玉 "
"print fib(10000)")
(defvar *kifu-hw-strict*
"▲2六歩 △6二銀 ▲6六歩 △7一銀 ▲5六歩 △6二金
▲6八金 △6四歩 ▲6九金 △6三金 ▲6八玉 △5二玉
▲5九金右 △6二金 ▲5八金直 △6三金 ▲5七金 △6二金
▲5九金 △6五歩 ▲6七金 △6三金 ▲5八金 △5一金
▲5九金 △5四歩 ▲5五歩 △5三玉 ▲5七玉 △4二銀
▲6八玉 △5二金 ▲5八金 △5一金 ▲5七金上 △5二金
▲5八金 △5一金 ▲5七金上 △5二金 ▲5八金 △3一銀
▲5七玉 △4二玉 ▲5四歩 △同 金 ▲5五歩 △5一金
▲5四歩 △4一金 ▲5六玉 △5一金 ▲6五玉 △5七歩
▲3六歩 △3二玉 ▲5九金 △6一金 ▲6九金 △5一金
▲5七金 △6二金 ▲5六玉 △6三金 ▲5八金上 △7四金
▲5五玉 △4四歩 ▲3四金 △同 歩 ▲5九金 △3五金
▲4八金 △3六金 ▲6七金 △2六金 ▲3八金 △3六金
▲4八金 △3三玉 ▲5七金上 △2六金 ▲4六金 △2五金
▲4五金 △同 歩 ▲3五歩 △同 金 ▲5七金 △4三金
▲5六金 △4二玉"
"from http://yowaken.dip.jp/tdiary/20100402.html#p01")
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment