今更でもズンドコキヨシ (js/VB/HSP/Lisp/Excel)

[元ネタ](https://twitter.com/kumiromilk/status/707437861881180160)
[まとめ](http://qiita.com/shunsugai@github/items/971a15461de29563bf90)
時期遅れって言えないレベルですが、今更マイブームになっているので数種類実装してみました。
レギュレーションとしてズンズンズンズンズンドコは無しにしています。
# 文字列比較 js/VB
### JavaScript
```js:kiyoshi.js
console.log(kiyoshi());

function kiyoshi(){
	const zundoko=["ズン","ドコ"];
	const exit_kiyoshi="キ・ヨ・シ!"
	const zdchk="00001";
	var rec="";
	for(;;){
		var zd=Math.floor(Math.random()*zundoko.length);
		process.stdout.write(zundoko[zd]);
		rec+=zd;
		if(zdchk[0]==rec.slice(-(zdchk.length+1))[0] && zdchk==(rec).slice(-zdchk.length)){
			return exit_kiyoshi;
		}
	}
}
```
### VB.net
```vbnet:kiyoshi.vb
Imports System
Imports System.Console
Imports Microsoft.VisualBasic

Module Program
	Sub Main()
		WriteLine(kiyoshi())
	End Sub

	Function kiyoshi() As String
		Dim rand As New Random()
		Dim zundoko As String()={"ズン","ドコ"}
		Dim exit_kiyoshi As String="キ・ヨ・シ!"
		Dim zdchk="00001"
		Dim rec As String=""
		Do
			Dim zd As Long=rand.Next(zundoko.Length)
			Write(zundoko(zd))
			rec &= zd
			If zdchk(0)<>Right(rec,zdchk.Length+1)(0) And zdchk=Right(rec,zdchk.Length) Then
				Return exit_kiyoshi
			End If
		Loop
	End Function
End Module
```
一番最初に書いた型だったけど値を配列に保持してないのでレギュ違反気味。
オンライン実行環境: [JavaScript](http://rextester.com/SINHR69644), [VB.net](http://rextester.com/UOYU61248)


# 配列スライド js/VB
### JavaScript
```js:kiyoshi.js
console.log(kiyoshi());

function kiyoshi(){
    const zundoko=["ズン","ドコ"];
    const exit_kiyoshi="キ・ヨ・シ!"
    const zdchk=[0,0,0,0,1];
    var stk=new Array(zdchk.length);
    for(;;){
        var zd=Math.floor(Math.random()*zundoko.length);
        process.stdout.write(zundoko[zd]);
        stk.push(zundoko[zd])
        var stk0=stk.shift();
        if(stk0!=zundoko[zdchk[0]] && stk.join()==zdchk.map(val=>zundoko[val]).join()){
            return exit_kiyoshi;
        }
    }
}
```
###VB.net
```vbnet:kiyoshi.vb
Imports System
Imports System.Console
Imports System.Collections.Generic

Module Program
	Sub Main()
		WriteLine(kiyoshi())
	End Sub

	Function kiyoshi() As String
		Dim rand As New Random()
		Dim zundoko As String()={"ズン","ドコ"}
		Dim exit_kiyoshi As String="キ・ヨ・シ!"
		Dim zdchk As String()={0,0,0,0,1}
		Dim stk As New LinkedList(Of String)(New String(5-1){})
		Do
			Dim zd As Long=rand.Next(zundoko.Length)
			Write(zundoko(zd))
			stk.AddLast(zundoko(zd))
			Dim stk0 As String=stk.First.Value
			stk.RemoveFirst()
			If stk0<>zundoko(zdchk(0)) And String.Join("",stk)=String.Join("",Array.ConvertAll(zdchk,Function(val) zundoko(val))) Then
				Return exit_kiyoshi
			End If
		Loop
	End Function
End Module
```
pushしてshiftすれば1つ分スライドするよねっていう発想。
.Netの配列にはこの機能が備わっていないらしく、移植には少し苦労した。
そこでVBには初めてLinkedListを使用したけど、存在すら知らなかった。
インデックスは存在しないけど、順番は保持してくれて前後端の操作に優れているらしい。
配列というものに動的なものを含めるかどうかでレギュレーションは変わるなぁ。
オンライン実行環境: [JavaScript](http://rextester.com/FCMHI49244), [VB.net](http://rextester.com/ZVKAE30334)

# ループぶん回し HSP
### HSP
```vbnet:kiyoshi.hsp
#runtime "hsp3cl"
#uselib "msvcrt.dll"
randomize

mes kiyoshi()
#module Program
	#func printf "printf" str
	#defcfunc kiyoshi
		zundoko="ズン","ドコ"
		exit_kiyoshi="キ・ヨ・シ!"
		zdchk=0,0,0,0,1
		sdim stk,,length(zdchk)
		repeat
			zd=rnd(length(zundoko))
			stk0=stk(0)
			repeat length(stk)-1
				stk(cnt)=stk(cnt+1)
			loop
			printf zundoko(zd)
			stk(length(stk)-1)=zundoko(zd)
			if stk0!=zundoko(zdchk(0)){
				repeat length(stk)
					if stk(cnt)!=zundoko(zdchk(cnt)){
						break
					}
					if cnt=length(stk)-1{
						return exit_kiyoshi
					}
				loop
			}
		loop
#global
```
特殊な操作を一切行わずに原始的な手段だけで解決。
一番正解に近いのはコレだったりするのかもしれない。
あと地味にHSPでは先駆者っぽい。

#with CommonLisp
### CommonLisp

```cl:kiyoshi.lisp
(defun kiyoshi()
	(setq *random-state* (make-random-state t))
	(let(
		(zundoko_list '("ズン" "ドコ"))
		(exit_kiyoshi "キ・ヨ・シ!")
		(zdchk '(0 0 0 0 1))
	)(let(
		(stc (mapcar #'(lambda(val)"") zdchk))
	)
		(defun fact(stc)
			(let(
				(zd(random(length zundoko_list)))
			)(let(
				(stczd (append (rest stc) `(,(elt zundoko_list zd))))
			)
				(format t (elt zundoko_list zd))
				(if (and
					(string/= (first stc) (first zundoko_list))
					(equal stczd (mapcar #'(lambda(val)(elt zundoko_list val)) zdchk))
				)
					exit_kiyoshi
					(fact stczd)
				)
			))
		)
		(fact stc)
	))
)
(format t (kiyoshi))
```
Lispでもズンドコしてみた。
再帰しまくって副作用をできるだけ出さないように書いてみた。
慣れない書き方をしたので結構疲れた。
Listの比較ができるequalは今回初めて知ったけど便利だ。
[CommonLisp](http://rextester.com/PJH49108)

# おまけ:クラス/モジュール化 js/VB/HSP/CL
[※最新版](http://qiita.com/yosgspec/items/3aef775c54632e060013)
### JavaScript
```js:nyaaan.js
const zundoko=require("./zundoko");

(function(){
	const zd=new zundoko();
	console.log(zd.kiyoshi());
	const nyaaan=new zundoko(["ぺぇこ","にゃん"],"ぺぇこぺぇこふぅーんふぅーんぺぇこふぅーんふぅー",[0,0,1,1,0,1,1]);
	console.log(nyaaan.kiyoshi());
})();
```
```js:zundoko.js
module.exports=function zundoko(_zundoko_list,_exit_kiyoshi,_zdchk){
	var zundoko_list;
	var exit_kiyoshi;
	var zdchk;
	this.zundoko=function(){
		if(zundoko.length==zundoko.arguments.length){
			zundoko_list=_zundoko_list;
			exit_kiyoshi=_exit_kiyoshi;
			zdchk=_zdchk;
		}
		else{
			zundoko_list=["ズン","ドコ"];
			exit_kiyoshi="キ・ヨ・シ!";
			zdchk=[0,0,0,0,1]
		}
	}

	this.kiyoshi=function(){
		var stk=new Array(zdchk.length);
		for(;;){
			var zd=Math.floor(Math.random()*zundoko_list.length);
			process.stdout.write(zundoko_list[zd]);
			stk.push(zundoko_list[zd])
			var stk0=stk.shift();
			if(stk0!=zundoko_list[zdchk[0]] && stk.join()==zdchk.map(val=>zundoko_list[val]).join()){
				return exit_kiyoshi;
			}
		}
	}
	return this.zundoko();
}
```
### VB.net
```vbnet:nyaaan.vb
Imports System
Imports System.Console
Imports zundoko

Public Module Program
	Sub Main()
		Dim zd As New zundoko()
		WriteLine(zd.kiyoshi())
		Dim nyaaan As New zundoko({"ぺぇこ","にゃん"},"ぺぇこぺぇこふぅーんふぅーんぺぇこふぅーんふぅー",{0,0,1,1,0,1,1})
		WriteLine(nyaaan.kiyoshi())
	End Sub
End Module
```
```vbnet:zundoko.vb
Imports System
Imports System.Console
Imports System.Collections.Generic

Class zundoko
	Dim rand As New Random()
	Dim zundoko_list As String()
	Dim exit_kiyoshi As String
	Dim zdchk As Integer()
	Sub New()
		Me.zundoko_list={"ズン","ドコ"}.Clone
		Me.exit_kiyoshi="キ・ヨ・シ!"
		Me.zdchk={0,0,0,0,1}.Clone
	End Sub

	Sub New(zundoko_list,exit_kiyoshi,zdchk)
		Me.zundoko_list=zundoko_list.Clone
		Me.exit_kiyoshi=exit_kiyoshi
		Me.zdchk=zdchk.Clone
	End Sub

	Function kiyoshi() As String
		Dim rand As New Random()
		Dim stk As New LinkedList(Of String)(New String(zdchk.Length-1){})
		Do
			Dim zd As Long=rand.Next(zundoko_list.Length)
			Write(zundoko_list(zd))
			stk.AddLast(zundoko_list(zd))
			Dim stk0 As String=stk.First.Value
			stk.RemoveFirst()
			If stk0<>zundoko_list(zdchk(0)) And String.Join("",stk)=String.Join("",Array.ConvertAll(zdchk,Function(val) zundoko_list(val))) Then
				Return exit_kiyoshi
			End If
		Loop
	End Function
End Class
```
### HSP
```vbnet:nyaaan.hsp
#runtime "hsp3cl"
#include "zundoko.as"

newmod zd,zundoko
mes kiyoshi(zd)

newmod nyaaan,zundoko
words="ぺぇこ","にゃん"
fin="ぺぇこぺぇこふぅーんふぅーんぺぇこふぅーんふぅー"
ptn=0,0,1,1,0,1,1
set nyaaan,words,fin,ptn
mes kiyoshi(nyaaan)
```
```vbnet:zundoko.as
#uselib "msvcrt.dll"
randomize

#module zundoko zundoko_list,exit_kiyoshi,zdchk
	#func printf "printf" str

	#modinit
		zundoko_list="ズン","ドコ"
		exit_kiyoshi="キ・ヨ・シ!"
		zdchk=0,0,0,0,1
	return

	#modfunc set array _zundoko_list,str _exit_kiyoshi,array _zdchk
		sdim zundoko_list,,length(_zundoko_list)
		repeat length(_zundoko_list)
			zundoko_list(cnt)=_zundoko_list(cnt)
		loop
		exit_kiyoshi=_exit_kiyoshi
		sdim zdchk,,length(_zdchk)
		repeat length(_zdchk)
			zdchk(cnt)=_zdchk(cnt)
		loop
	return

	#modcfunc kiyoshi
		sdim stk,,length(zdchk)
		repeat
			zd=rnd(length(zundoko_list))
			stk0=stk(0)
			repeat length(stk)-1
				stk(cnt)=stk(cnt+1)
			loop

			printf zundoko_list(zd)
			stk(length(stk)-1)=zundoko_list(zd)

			if stk0!=zundoko_list(zdchk(0)){
				repeat length(stk)
					if stk(cnt)!=zundoko_list(zdchk(cnt)){
						break
					}
					if cnt=length(stk)-1{
						return exit_kiyoshi
					}
				loop
			}
		loop
#global
```
### CommonLisp
```cl:nyaaan.lisp
(load "zundoko")
(defparameter zd (make-instance 'zundoko))
(format t "~a~%" (kiyoshi zd))

(defparameter nyaaan (make-instance 'zundoko :words '("ぺぇこ" "にゃん") :fin "ぺぇこぺぇこふぅーんふぅーんぺぇこふぅーんふぅー" :ptn '(0 0 1 1 0 1 1)))
(format t "~a~%" (kiyoshi nyaaan))
```
```cl:zundoko.lisp
(defun kiyoshi()
	(setq *random-state* (make-random-state t))
	(let(
		(zundoko_list '("ズン" "ドコ"))
		(exit_kiyoshi "キ・ヨ・シ!")
		(zdchk '(0 0 0 0 1))
	)(let(
		(stc (mapcar #'(lambda(val)"") zdchk))
	)
		(defun fact(stc)
			(let(
				(zd(random(length zundoko_list)))
			)(let(
				(stczd (append (rest stc) `(,(elt zundoko_list zd))))
			)
				(format t (elt zundoko_list zd))
				(if (and
					(string/= (first stc) (first zundoko_list))
					(equal stczd (mapcar #'(lambda(val)(elt zundoko_list val)) zdchk))
				)
					exit_kiyoshi
					(fact stczd)
				)
			))
		)
		(fact stc)
	))
)
(format t (kiyoshi))
```

```text:コンソール出力
ズンドコドコズンズンドコドコドコズンドコドコズンズンズンドコズンズンズンドコドコドコドコドコドコドコズンズンズンズンズンドコズンドコドコズンドコドコドコズンドコドコドコドコズンズンズンドコズンズンズンドコズンズンドコズンドコズンドコズンドコドコズンドコズンドコズンズンズンドコドコドコドコドコドコドコドコドコズンズンズンズンドコキ・ヨ・シ!
にゃんにゃんにゃんぺぇこにゃんにゃんにゃんにゃんにゃんにゃんぺぇこぺぇこぺぇこにゃんにゃんにゃんぺぇこにゃんにゃんぺぇこぺぇこにゃんにゃんにゃんぺぇこぺぇこにゃんにゃんぺぇこぺぇこにゃんにゃんぺぇこにゃんにゃんぺぇこぺぇこふぅーんふぅーんぺぇこふぅーんふぅー
```
上記のプログラムをそのままクラス/モジュール化。
使用方法は次の通り。

```js:js
const zundoko=require("zundoko");
var hoge=new zundoko([ズンドコパターン:配列], フィニッシュ台詞, [マッチパターン:int配列]);
console.log(hoge.kiyoshi());
```
```vbnet:VB
Dim hoge As New zundoko([ズンドコパターン:配列], フィニッシュ台詞, [マッチパターン:int配列])
Console.WriteLine(hoge.kiyoshi())
```
```php:HSP
include "zundoko.as"
newmod hoge,zundoko
set hoge,[ズンドコパターン:配列], フィニッシュ台詞, [マッチパターン:int配列]
//setしなければ通常のズンドコキヨシ
mes kiyoshi(hoge)
```
```cl:CL
(load "zundoko")
(defparameter hoge (make-instance 'zundoko :words [ズンドコパターン:リスト] :fin フィニッシュ台詞 :ptn [マッチパターン:intリスト]))
(format t "~a~%" (kiyoshi hoge))
```


クラス/モジュールファイルを同じフォルダにおいてこのようにすれば、好きなワードやパターンでズンドコ可能。
オンライン実行環境: [JavaScript](http://rextester.com/LAFLVK83237), [VB.net](http://rextester.com/WUFAZ39651), [CommonLisp](http://rextester.com/JVWBC26719)

# Excel
![excelkiyoshi.png](https://qiita-image-store.s3.amazonaws.com/0/147573/5ddedba2-bdf3-a50f-1dd4-d60296d1997b.png)
![kitoshigs.png](https://qiita-image-store.s3.amazonaws.com/0/147573/52331e7e-f378-2db8-ad63-d4e23cdad4e5.png)

```vbnet:EXCEL
=IFERROR(
	IF(AND(
		"ズン"=INDIRECT(ADDRESS(ROW()-5,COLUMN())),
		"ズン"=INDIRECT(ADDRESS(ROW()-4,COLUMN())),
		"ズン"=INDIRECT(ADDRESS(ROW()-3,COLUMN())),
		"ズン"=INDIRECT(ADDRESS(ROW()-2,COLUMN())),
		"ドコ"=INDIRECT(ADDRESS(ROW()-1,COLUMN()))
	),
		IF(
			ISERROR(IF("ズン"<>INDIRECT(ADDRESS(ROW()-6,COLUMN())),
				NA(),
				0
			)),
			"キ・ヨ・シ!",
			NA()
		),
		IF(NOT(ISERROR(MATCH(
			"キ・ヨ・シ!",
			INDIRECT(
				ADDRESS(1,COLUMN())&":"&
				ADDRESS(ROW()-1,COLUMN())
			),
			0
		))),
			"",
			NA()
		)
	),
	IF(RANDBETWEEN(0,1)=0,
		"ズン",
		"ドコ"
	)
)
```
一セルに情熱を。
[2番煎じ](http://qiita.com/Kta-M/items/89b0ea73cb20d83a90ba)ですけど作成。
好きなセルに上記を貼り付けて上下に適当にズザーすれば使用できます。
[GoogleSpreadでも動いたのでリンク置いときます。](https://docs.google.com/spreadsheets/d/1tE5xgY4F8X6O7O5GvXiKc8Uv56gsh77_R_rauUwaVA8/edit?usp=sharing)

# 実行環境
JavaScript: node v4.3.2
VB.net: vbc 14.0.1055
HSP 3.32
CommonLisp: CLISP 2.49, SBCL 1.2.7
MS Excel 2007
及び、[Rextester](http://rextester.com/)