CDW リプレイを実装した


2022年 6月 17日
 
 
 元祖ダイスウォーズには全占領した後リプレイがある。

 これをやってみた。


 
 

 考え方として、まずベタに考えると 1動作につき 1マップ、データ化すると考える。

 すると 1マップ最大 X × 55 + Y × 31 = 1705だとして、× 何ターンもデータ化すると量が多すぎる。

 しかもダイス増のデータも要るし、キャラクターユニットの情報も要る。
 
 
 そこで考え方として、初期マップ状態に対する「変化のみをデータ化する」という事を考える。

 つまり 1つ占領してマップが変わったら、その占領された国の情報だけをデータ化する。

 同様にダイス増もキャラクターユニットも、その変化した国のデータのみを記録する。
 
 
 次の考えたかとして、HSPは 1データ 4バイトある。

 16進数だと FF FF FF FFという事になるけど、10進数だと 2147483648という数までとなる。

 2進数や 16進数を扱うのは自分には難しいので、素直に 10進数で考えてみる。

 そこで、1つのデータのケタを 4つに分けてつかう。

 214 748 364 8 という風に分けて、それぞれデータを入れる。

 1つ目~3つ目はデータ、最後の 4つ目はデータの種類を表すフラグデータとする。

 これによって HSPで扱う 1データで、この場合は 3つのマップ変化データを扱える。

 つまり 3分の1のデータ圧縮と考えられる。
 
 
 初期

////////// リプレイ //////////
*rep_ini

	repb=100000 ; データ
	 dim repd,repb

	repc=2 ; カウンター
	repk=0 ; データ位置

	return

 リプレイデータは repdになります。

 repcは何番目のデータかで、repkは先の通り 1データの何番目のデータかです。

 repcが 2からなのは、セーブデータとして repd(0)には repcの値が、repd(1)には repkの値が、それぞれ格納されるためです。
 
 
 データ書き込み

#deffunc rep_add int _repf,int _repn1,int _repn2,int _repn3 ; データ構築

	if repc>=repb : return ; 最大書き込み

	repf=_repf   ; データ種類(1=ダイス+、2=勝ち、3=負け)
	repn1=_repn1 ; 国1
	repn2=_repn2 ; 国2
	repn3=_repn3 ; 国2のCU移動先

	switch repf

	 case 1 ; 国+

	  if repk=0 { ; 000 000 111 1
	   repd(repc)+=repf		; データ種類
	   repd(repc)+=repn1*10	; 国No.
	   repk+
	   swbreak
	  }

	  if repk=1 { ; 000 111 000 0
	   repd(repc)+=repn1*10000 ; 2番目のデータ
	   repk+
	   swbreak
	  }

	  if repk=2 { ; 111 000 000 0
	   repd(repc)+=repn1*10000000 ; 3番目のデータ
	   repk=0 ; リセットして次のデータへ
	   repc+ ;: rep_save ; 一旦セーブ判定
	   swbreak
	  }
	 swbreak

	 case 2 ; 勝ち
	  if repk>0 { ; データ途中
	   repk=0
	   repc+ ;: rep_save ; 一旦セーブ判定
	  }
	  repd(repc)+=repf			; データ種類
	  repd(repc)+=repn1*10		; 国1
	  repd(repc)+=repn2*10000	; 国2
	  repd(repc)+=repn3*10000000; 国2のCU移動先
	  repc+
	 swbreak

	 case 3 ; 負け
	  if repk>0 { ; データ途中
	   repk=0
	   repc+ ;: rep_save ; 一旦セーブ判定
	  }
	  repd(repc)+=repf			; データ種類
	  repd(repc)+=repn1*10		; 国1
	  repd(repc)+=repn2*10000	; 国2
	  repc+
	 swbreak
	swend

	return

 データの 4番目、つまり 1ケタ目のデータは何のデータかを表すフラグになってます。

 switch文の repfです。

 フラグ 1はダイス増ですね、どの国のダイスが +1されたかだけ記録してます。

 repk+によって、1データの何番目に書き込むか指定してます、1~3になってます。
 
 
 フラグ 2は勝った場合、占領した場合の変化です。

 データ 10ケタからは占領した国、10000ケタからは占領された国で、これは 3分割では無くて2分割になってます。

 なぜかと言うと、データの最大値が 214 748 364 8であるために、1データ目は 214が最大値になってしまうためで、もし国の最大数が 214以上だと表せなくなります。

 もう一つの理由は、1データで一つの戦勝処理を表した方が分かりやすいからだと思います。
 
 
 フラグ 3は負けた場合のデータです。
 
 
 
 データを元にリプレイを表示

*replay ; リプレイ

	repf=0		; フラグ
	repc=repb	; カウント

	rept1=1	; ダイス+待機時間
	rept2=2 ; 戦闘国待機時間
	rept3=3 ; 勝敗待機時間

	rep_ldn1=0 ; 現プレイヤー
	rep_ldn2=0

	while repf!10
	 switch repd(repc)\10

	  case 0 ; end
	   repf=10
	  swbreak

	  case 1 ; 国ダイス+
	   rept=rept1 ; 表示時間

	   if repf=0 { ; データ1
		rep_ldn1=(repd(repc)/10)\1000 ; 国No.
		ldcd(rep_ldn1)+
		repf+
		swbreak
	   }

	   if repf=1 { ; データ2
		rep_ldn1=(repd(repc)/10000)\1000 ; 国No.
		ldcd(rep_ldn1)+
		repf+
		swbreak
	   }

	   if repf=2 { ; データ3
		rep_ldn1=(repd(repc)/10000000)\1000 ; 国No.
		ldcd(rep_ldn1)+
		repf=0 : repc+
	   }
	  swbreak

	  case 2 ; 勝ち
	   if repf=0 { ; 攻撃国
		kln1=(repd(repc)/10)\100
		repf+ : rept=rept2 : rep_ldn1=kln1
		swbreak
	   }

	   if repf=1 { ; 防衛国
		kln2=(repd(repc)/10000)\1000
		repf+ : rept=rept2
		swbreak
	   }

	   if repf=2 { ; 勝敗
	    ldcd(kln2)=ldcd(kln1)-1 : ldcd(kln1)=1 ; ダイス

; cu表情
	    if ldcu(kln1)>0 : cupf(ldcu(kln1))=1 ; 勝ち
	    if ldcu(kln2)>0 : cupf(ldcu(kln2))=2 ; 負け

	    repeat 1 ; CU移動
	     kln3=(repd(repc)/10000000)\1000 ; 国2の移動先
	     if ldcu(kln1)>0 {
	      ldcun=0 ; 一時格納
	      if ldcu(kln2)>0 : ldcun=ldcu(kln2) ; 一時格納
	      ldcu(kln2)=ldcu(kln1) ; CU移動
	      ldcu(kln1)=0
	      ldcu(kln3)=ldcun ; 入れ替え
	      break
	     }
	     if ldcu(kln2)>0 {
		  if kln3=0 : break
		  ldcu(kln3)=ldcu(kln2)
		  ldcu(kln2)=0
		  break
		 }
		loop

	    lpd(kln2)=lpd(kln1) ; 国色を変える
	    repf=0 : repc+
	    swbreak
	   }
	  swbreak
	  case 3 ; 負け
	   if repf=0 { ; 攻撃国
		kln1=(repd(repc)/10)\100
		repf+ : rept=rept2 : rep_ldn1=kln1
		swbreak
	   }
	   if repf=1 { ; 防衛国
		kln2=(repd(repc)/10000)\1000
		repf+ : rept=rept2
		swbreak
	   }
	   if repf=2 { ; 勝敗
	    ldcd(kln1)=1

; cu表情
	    if ldcu(kln1)>0 : cupf(ldcu(kln1))=2 ; 負け
	    if ldcu(kln2)>0 : cupf(ldcu(kln2))=1 ; 勝ち

	    repf+ : rept=rept3
	    swbreak
	   }
	   if repf=3 { ; リセット
		repf=0 : repc+ : rept=1
	   }
	  swbreak
	 swend


; cu表情のリセット
	 if lpd(rep_ldn1)!lpd(rep_ldn2) {
	  repeat ldb,1 : ldn=cnt
	   if lpd(ldn)!lpd(rep_ldn1) : continue
	   if ldcu(ldn)=0 : continue
	   cupf(ldcu(ldn))=0 ; フラットに
	  loop
	  rep_ldn2=rep_ldn1
	 }

	 repeat rept
	  redraw 0
	   sc_mput
	  redraw 1

	  await 100
	 loop

	wend

	return

 データの 1ケタ目をフラグ repfとして、同じように switch文で分岐処理します。

 1はダイス増、2は占領、3は負け処理です。

 キャラクターユニットの移動は、元のマップからの変化でのみ処理してます。

 つまり、もしどこかで間違えると、ずっと間違ったまま処理されます。

 少しややこしいのは、キャラクターユニットの表情の変化です。

 表情の値は cupfです。

 詳細は忘れましたけど、その国の番が回ってきた時に表情をフラットにするのに苦心したと思います。
 
 
 
 これでリプレイのデータ量は、大体 10000前後~多くても 30000以内くらいです。

 10000データという事は 40000バイト、つまり 4MBです。

 今の所セーブ箇所が 8個になる予定なので、× 8で最大 32MBくらいになると思います。

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です