Implementation of Lucifers Pastime
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

999 lines
25KB

  1. #!/usr/bin/perl
  2. package LPST;
  3. use warnings;
  4. use strict;
  5. use utf8;
  6. my $ARRAY = "ARRAY";
  7. my $HAND_SIZE = 5;
  8. my $MAX_FT_SUMMON = 16;
  9. my $X_BOX_CHR = chr(0x2573);
  10. my $GRAY_BOX_CHR = chr(0x2591);
  11. my $ALT_US = chr(0x2017);
  12. my $ALT_PIPE = chr(0x2016);
  13. my $SHADE_1_CHR = $GRAY_BOX_CHR;
  14. my $SHADE_2_CHR = $X_BOX_CHR;
  15. my $PAD_AXIS = " ";
  16. my $PAD_EVEN = " ";
  17. my $PAD_ODD = " ";
  18. my $HEX_1 = '-/--\-';
  19. my $HEX_2 = '| __ |';
  20. my $HEX_3 = '| |';
  21. my $HEX_S1_1 = '-/--\-';
  22. my $HEX_S1_2 = sprintf("|%s%s%s%s|", $SHADE_1_CHR, $SHADE_1_CHR, $SHADE_1_CHR, $SHADE_1_CHR);
  23. my $HEX_S1_3 = sprintf("|%s%s%s%s|", $SHADE_1_CHR, $SHADE_1_CHR, $SHADE_1_CHR, $SHADE_1_CHR);
  24. my $HEX_S2_1 = '-/--\-';
  25. my $HEX_S2_2 = sprintf("|%s%s%s%s|", $SHADE_2_CHR, $SHADE_2_CHR, $SHADE_2_CHR, $SHADE_2_CHR);
  26. my $HEX_S2_3 = sprintf("|%s%s%s%s|", $SHADE_2_CHR, $SHADE_2_CHR, $SHADE_2_CHR, $SHADE_2_CHR);
  27. my $HEX_S3_1 = '-/--\-';
  28. my $HEX_S3_2 = sprintf("|%s%s%s%s|", $SHADE_2_CHR, $SHADE_2_CHR, $SHADE_1_CHR, $SHADE_1_CHR);
  29. my $HEX_S3_3 = sprintf("|%s%s%s%s|", $SHADE_2_CHR, $SHADE_2_CHR, $SHADE_1_CHR, $SHADE_1_CHR);
  30. my $HL_1 = "|____ ";
  31. my $HL_2 = $ALT_PIPE.$ALT_US.$ALT_US.$ALT_US.$ALT_US." ";
  32. my $SUB_CHR = "_";
  33. my $BLANK_CELL_CHR = $ALT_US;
  34. my $PREF_1 = substr($HEX_1, -2, 2);
  35. my $PREF_2 = ' ';
  36. my $PREF_3 = ' ';
  37. my $TRAIL_1 = substr($HEX_1, 0, 1);
  38. my $TRAIL_2 = substr($HEX_1, -1, 1);
  39. my $TRAIL_3 = substr($HEX_1, 0, 2);
  40. # Pieces
  41. my $MG_A = "A"; # Apprentice
  42. my $MG_I = "I"; # Iron Maiden
  43. my $MG_N = "N"; # Nekomata
  44. my $MG_IT = "It"; # Ittan-Momen
  45. my $MG_H = "H"; # Harpy
  46. my $MG_S = "S"; # Slime
  47. my $MG_RC = "Rc"; # Redcap
  48. my $MG_HS = "Hs"; # Holstaur
  49. my $MG_RO = "Ro"; # Red Oni
  50. my $MG_B = "B"; # Blue Oni
  51. my $MG_P = "P"; # Preistess
  52. my $MG_IM = "Im"; # Imp
  53. my $MG_F = "F"; # False Angel
  54. my $MG_QS = "Qs"; # Queen slime
  55. my $MG_AU = "Au"; # Automaton
  56. my $MG_SY = "Sy"; # Sylph
  57. my $MG_Q = "Q"; # Queen
  58. my @MG_PI = (
  59. $MG_A, $MG_I, $MG_N, $MG_IT, $MG_H, $MG_S,
  60. $MG_RC, $MG_HS, $MG_RO, $MG_B, $MG_P, $MG_IM,
  61. $MG_F, $MG_QS, $MG_AU, $MG_SY, $MG_Q
  62. );
  63. # Players
  64. my $P1 = "P1";
  65. my $P2 = "P2";
  66. my %OPPL = (
  67. $P1 => $P2,
  68. $P2 => $P1
  69. );
  70. my %HAND = (
  71. $P1 => [],
  72. $P2 => []
  73. );
  74. my $DIV = ":";
  75. my %AXIS = (
  76. "A" => 1,
  77. "B" => 2,
  78. "C" => 3,
  79. "D" => 4,
  80. "E" => 5,
  81. "F" => 6,
  82. "G" => 7,
  83. "H" => 8,
  84. "I" => 9,
  85. "J" => 10,
  86. "K" => 11
  87. );
  88. my %AXIS_RV = map {
  89. $AXIS{$_} => $_
  90. } keys(%AXIS);
  91. package MoveStruct;
  92. use warnings;
  93. use strict;
  94. sub new {
  95. my $class = shift;
  96. my $self = { @_ };
  97. die "invalid MoveStruct {\"mov\"}" unless $self->{"mov"};
  98. die "invalid MoveStruct ->{\"type\"}" unless $self->{"type"};
  99. die "invalid MoveStruct type" unless ref($self->{"mov"}) eq $ARRAY;
  100. return bless $self, $class;
  101. }
  102. package LPST;
  103. #
  104. # /--\ +1
  105. # | __ |
  106. # | |+1
  107. # \--/
  108. # -1 -1
  109. #
  110. # ODD
  111. # UP: 0, +1
  112. # DOWN: -1, -1
  113. # EVEN
  114. # UP: +1, +1
  115. # DOWN: +0, -1
  116. # [Row move, Diag move]
  117. # Special cells
  118. my $EMPTY_CELL = "_";
  119. # Shade enum
  120. my $SHADE_3_ENUM = 0b011;
  121. my $SHADE_2_ENUM = 0b010;
  122. my $SHADE_1_ENUM = 0b001;
  123. my $EMPTY_ENUM = 0;
  124. my %SHADE = (
  125. $SHADE_1_ENUM => [$HEX_S1_1, $HEX_S1_2, $HEX_S1_3],
  126. $SHADE_2_ENUM => [$HEX_S2_1, $HEX_S2_2, $HEX_S2_3],
  127. $SHADE_3_ENUM => [$HEX_S3_1, $HEX_S3_2, $HEX_S3_3],
  128. $EMPTY_ENUM => [$HEX_1, $HEX_2, $HEX_3]
  129. );
  130. my $MOVE_ENUM = $SHADE_1_ENUM;
  131. my $BLOCK_ENUM = $SHADE_2_ENUM;
  132. my $MOVBLOCK_ENUM = $SHADE_3_ENUM;
  133. my $ERR_C_1 = -1;
  134. my %MOVE = (
  135. $MG_A => [
  136. MoveStruct->new("mov" => [-1, 1], "type" => $MOVBLOCK_ENUM),
  137. MoveStruct->new("mov" => [ 0, 1], "type" => $MOVBLOCK_ENUM)
  138. ],
  139. $MG_Q => [
  140. MoveStruct->new("mov" => [ 0, 1], "type" => $MOVE_ENUM),
  141. MoveStruct->new("mov" => [ 1, 0], "type" => $MOVE_ENUM),
  142. MoveStruct->new("mov" => [-1, 0], "type" => $MOVE_ENUM),
  143. MoveStruct->new("mov" => [ 0,-1], "type" => $MOVE_ENUM)
  144. ],
  145. $MG_I => [
  146. MoveStruct->new("mov" => [-1, 0], "type" => $BLOCK_ENUM),
  147. MoveStruct->new("mov" => [-1, 1], "type" => $BLOCK_ENUM),
  148. MoveStruct->new("mov" => [ 0, 1], "type" => $BLOCK_ENUM),
  149. MoveStruct->new("mov" => [ 0,-1], "type" => $BLOCK_ENUM),
  150. MoveStruct->new("mov" => [ 1, 0], "type" => $BLOCK_ENUM),
  151. MoveStruct->new("mov" => [ 1,-1], "type" => $BLOCK_ENUM)
  152. ],
  153. $MG_IT => [
  154. MoveStruct->new("mov" => [ 0,-1], "type" => $MOVE_ENUM),
  155. MoveStruct->new("mov" => [ 1,-1], "type" => $MOVE_ENUM),
  156. MoveStruct->new("mov" => [-1, 1], "type" => $BLOCK_ENUM),
  157. MoveStruct->new("mov" => [ 0, 1], "type" => $BLOCK_ENUM)
  158. ],
  159. $MG_N => [
  160. MoveStruct->new("mov" => [-1, 2], "type" => $MOVE_ENUM),
  161. MoveStruct->new("mov" => [ 1,-2], "type" => $MOVE_ENUM),
  162. MoveStruct->new("mov" => [-1, 1], "type" => $BLOCK_ENUM),
  163. MoveStruct->new("mov" => [ 0, 1], "type" => $BLOCK_ENUM)
  164. ],
  165. $MG_H => [
  166. MoveStruct->new("mov" => [-3, 2], "type" => $MOVE_ENUM),
  167. MoveStruct->new("mov" => [-1,-2], "type" => $MOVE_ENUM),
  168. MoveStruct->new("mov" => [ 1, 2], "type" => $MOVE_ENUM),
  169. MoveStruct->new("mov" => [ 3,-2], "type" => $MOVE_ENUM),
  170. MoveStruct->new("mov" => [ 0,-1], "type" => $BLOCK_ENUM),
  171. MoveStruct->new("mov" => [ 1,-1], "type" => $BLOCK_ENUM),
  172. MoveStruct->new("mov" => [-1, 1], "type" => $BLOCK_ENUM),
  173. MoveStruct->new("mov" => [ 0, 1], "type" => $BLOCK_ENUM)
  174. ],
  175. $MG_RC => [
  176. MoveStruct->new("mov" => [-1, 0], "type" => $MOVE_ENUM),
  177. MoveStruct->new("mov" => [-2, 0], "type" => $MOVE_ENUM),
  178. MoveStruct->new("mov" => [ 1, 0], "type" => $MOVE_ENUM),
  179. MoveStruct->new("mov" => [ 2, 0], "type" => $MOVE_ENUM),
  180. MoveStruct->new("mov" => [ 0,-1], "type" => $BLOCK_ENUM),
  181. MoveStruct->new("mov" => [ 1,-1], "type" => $BLOCK_ENUM),
  182. MoveStruct->new("mov" => [-1, 1], "type" => $BLOCK_ENUM),
  183. MoveStruct->new("mov" => [ 0, 1], "type" => $BLOCK_ENUM)
  184. ],
  185. $MG_S => [
  186. MoveStruct->new("mov" => [-1, 1], "type" => $MOVE_ENUM),
  187. MoveStruct->new("mov" => [-2, 2], "type" => $MOVE_ENUM),
  188. MoveStruct->new("mov" => [ 0, 1], "type" => $MOVE_ENUM),
  189. MoveStruct->new("mov" => [ 0, 2], "type" => $MOVE_ENUM),
  190. MoveStruct->new("mov" => [ 0,-1], "type" => $MOVE_ENUM),
  191. MoveStruct->new("mov" => [ 0,-2], "type" => $MOVE_ENUM),
  192. MoveStruct->new("mov" => [ 1,-1], "type" => $MOVE_ENUM),
  193. MoveStruct->new("mov" => [ 2,-2], "type" => $MOVE_ENUM),
  194. ],
  195. $MG_HS => [
  196. MoveStruct->new("mov" => [-3, 1], "type" => $MOVE_ENUM),
  197. MoveStruct->new("mov" => [-2,-1], "type" => $MOVE_ENUM),
  198. MoveStruct->new("mov" => [ 2, 1], "type" => $MOVE_ENUM),
  199. MoveStruct->new("mov" => [ 3,-1], "type" => $MOVE_ENUM),
  200. MoveStruct->new("mov" => [-2, 1], "type" => $BLOCK_ENUM),
  201. MoveStruct->new("mov" => [ 1, 1], "type" => $BLOCK_ENUM),
  202. MoveStruct->new("mov" => [-1, 1], "type" => $BLOCK_ENUM),
  203. MoveStruct->new("mov" => [ 0, 1], "type" => $BLOCK_ENUM)
  204. ],
  205. $MG_RO => [
  206. MoveStruct->new("mov" => [-1, 1], "type" => $MOVE_ENUM),
  207. MoveStruct->new("mov" => [ 0, 1], "type" => $MOVE_ENUM),
  208. MoveStruct->new("mov" => [ 1, 1], "type" => $MOVE_ENUM),
  209. MoveStruct->new("mov" => [ 1,-2], "type" => $MOVE_ENUM),
  210. MoveStruct->new("mov" => [-1, 0], "type" => $BLOCK_ENUM),
  211. MoveStruct->new("mov" => [ 1, 0], "type" => $BLOCK_ENUM)
  212. ],
  213. $MG_B => [
  214. MoveStruct->new("mov" => [-1, 1], "type" => $MOVE_ENUM),
  215. MoveStruct->new("mov" => [ 0, 1], "type" => $MOVE_ENUM),
  216. MoveStruct->new("mov" => [ 0,-2], "type" => $MOVE_ENUM),
  217. MoveStruct->new("mov" => [ 2,-2], "type" => $MOVE_ENUM),
  218. MoveStruct->new("mov" => [ 0,-1], "type" => $BLOCK_ENUM),
  219. MoveStruct->new("mov" => [ 1,-1], "type" => $BLOCK_ENUM)
  220. ],
  221. $MG_P => [
  222. MoveStruct->new("mov" => [-4, 2], "type" => $MOVE_ENUM),
  223. MoveStruct->new("mov" => [-2, 1], "type" => $MOVBLOCK_ENUM),
  224. MoveStruct->new("mov" => [-2,-2], "type" => $MOVE_ENUM),
  225. MoveStruct->new("mov" => [-1,-1], "type" => $MOVBLOCK_ENUM),
  226. MoveStruct->new("mov" => [ 1, 1], "type" => $MOVBLOCK_ENUM),
  227. MoveStruct->new("mov" => [ 2,-1], "type" => $MOVBLOCK_ENUM),
  228. MoveStruct->new("mov" => [ 2, 2], "type" => $MOVE_ENUM),
  229. MoveStruct->new("mov" => [ 4,-2], "type" => $MOVE_ENUM)
  230. ],
  231. $MG_IM => [
  232. MoveStruct->new("mov" => [-2, 1], "type" => $MOVBLOCK_ENUM),
  233. MoveStruct->new("mov" => [-1,-1], "type" => $MOVBLOCK_ENUM),
  234. MoveStruct->new("mov" => [-1, 2], "type" => $MOVBLOCK_ENUM),
  235. MoveStruct->new("mov" => [ 1, 1], "type" => $MOVBLOCK_ENUM),
  236. MoveStruct->new("mov" => [ 1,-1], "type" => $MOVE_ENUM),
  237. MoveStruct->new("mov" => [ 1,-2], "type" => $BLOCK_ENUM),
  238. MoveStruct->new("mov" => [ 2,-1], "type" => $MOVBLOCK_ENUM)
  239. ],
  240. $MG_F => [
  241. MoveStruct->new("mov" => [-1, 0], "type" => $MOVE_ENUM),
  242. MoveStruct->new("mov" => [-1, 1], "type" => $MOVE_ENUM),
  243. MoveStruct->new("mov" => [ 0, 1], "type" => $MOVE_ENUM),
  244. MoveStruct->new("mov" => [ 0,-1], "type" => $MOVE_ENUM),
  245. MoveStruct->new("mov" => [ 1, 0], "type" => $MOVE_ENUM),
  246. MoveStruct->new("mov" => [ 1,-1], "type" => $MOVE_ENUM),
  247. MoveStruct->new("mov" => [ 0, 2], "type" => $BLOCK_ENUM),
  248. MoveStruct->new("mov" => [ 0,-2], "type" => $BLOCK_ENUM),
  249. MoveStruct->new("mov" => [ 1, 1], "type" => $BLOCK_ENUM),
  250. MoveStruct->new("mov" => [ 1,-2], "type" => $BLOCK_ENUM),
  251. MoveStruct->new("mov" => [ 2, 0], "type" => $BLOCK_ENUM),
  252. MoveStruct->new("mov" => [ 2,-1], "type" => $BLOCK_ENUM),
  253. MoveStruct->new("mov" => [ 2,-2], "type" => $BLOCK_ENUM),
  254. MoveStruct->new("mov" => [-1, 2], "type" => $BLOCK_ENUM),
  255. MoveStruct->new("mov" => [-1,-1], "type" => $BLOCK_ENUM),
  256. MoveStruct->new("mov" => [-2, 0], "type" => $BLOCK_ENUM),
  257. MoveStruct->new("mov" => [-2, 1], "type" => $BLOCK_ENUM),
  258. MoveStruct->new("mov" => [-2, 2], "type" => $BLOCK_ENUM)
  259. ],
  260. $MG_QS => [
  261. MoveStruct->new("mov" => [-3, 3], "type" => $MOVE_ENUM),
  262. MoveStruct->new("mov" => [-2, 2], "type" => $MOVE_ENUM),
  263. MoveStruct->new("mov" => [-2, 0], "type" => $MOVE_ENUM),
  264. MoveStruct->new("mov" => [-1, 0], "type" => $MOVE_ENUM),
  265. MoveStruct->new("mov" => [-1, 1], "type" => $MOVE_ENUM),
  266. MoveStruct->new("mov" => [ 0, 1], "type" => $MOVE_ENUM),
  267. MoveStruct->new("mov" => [ 0, 2], "type" => $MOVE_ENUM),
  268. MoveStruct->new("mov" => [ 0, 3], "type" => $MOVE_ENUM),
  269. MoveStruct->new("mov" => [ 0,-1], "type" => $MOVE_ENUM),
  270. MoveStruct->new("mov" => [ 0,-2], "type" => $MOVE_ENUM),
  271. MoveStruct->new("mov" => [ 0,-3], "type" => $MOVE_ENUM),
  272. MoveStruct->new("mov" => [ 1, 0], "type" => $MOVE_ENUM),
  273. MoveStruct->new("mov" => [ 1,-1], "type" => $MOVE_ENUM),
  274. MoveStruct->new("mov" => [ 2, 0], "type" => $MOVE_ENUM),
  275. MoveStruct->new("mov" => [ 2,-2], "type" => $MOVE_ENUM),
  276. MoveStruct->new("mov" => [ 3,-3], "type" => $MOVE_ENUM),
  277. MoveStruct->new("mov" => [ 3, 0], "type" => $MOVE_ENUM),
  278. MoveStruct->new("mov" => [-3, 0], "type" => $MOVE_ENUM)
  279. ],
  280. $MG_AU => [
  281. MoveStruct->new("mov" => [-1, 0], "type" => $MOVBLOCK_ENUM),
  282. MoveStruct->new("mov" => [-1, 1], "type" => $MOVBLOCK_ENUM),
  283. MoveStruct->new("mov" => [ 0, 1], "type" => $MOVBLOCK_ENUM),
  284. MoveStruct->new("mov" => [ 0,-1], "type" => $MOVBLOCK_ENUM),
  285. MoveStruct->new("mov" => [ 1, 0], "type" => $MOVBLOCK_ENUM),
  286. MoveStruct->new("mov" => [ 1,-1], "type" => $MOVBLOCK_ENUM),
  287. MoveStruct->new("mov" => [ 0, 2], "type" => $BLOCK_ENUM),
  288. MoveStruct->new("mov" => [ 0,-2], "type" => $BLOCK_ENUM),
  289. MoveStruct->new("mov" => [ 1, 1], "type" => $BLOCK_ENUM),
  290. MoveStruct->new("mov" => [ 1,-2], "type" => $BLOCK_ENUM),
  291. MoveStruct->new("mov" => [ 2,-1], "type" => $BLOCK_ENUM),
  292. MoveStruct->new("mov" => [ 2,-2], "type" => $BLOCK_ENUM),
  293. MoveStruct->new("mov" => [-1, 2], "type" => $BLOCK_ENUM),
  294. MoveStruct->new("mov" => [-1,-1], "type" => $BLOCK_ENUM),
  295. MoveStruct->new("mov" => [-2, 1], "type" => $BLOCK_ENUM),
  296. MoveStruct->new("mov" => [-2, 2], "type" => $BLOCK_ENUM)
  297. ],
  298. $MG_SY => [
  299. MoveStruct->new("mov" => [-4, 4], "type" => $MOVE_ENUM),
  300. MoveStruct->new("mov" => [-3, 3], "type" => $MOVE_ENUM),
  301. MoveStruct->new("mov" => [-3, 2], "type" => $MOVBLOCK_ENUM),
  302. MoveStruct->new("mov" => [-1,-2], "type" => $MOVBLOCK_ENUM),
  303. MoveStruct->new("mov" => [ 0,-4], "type" => $MOVE_ENUM),
  304. MoveStruct->new("mov" => [ 0,-3], "type" => $MOVE_ENUM),
  305. MoveStruct->new("mov" => [ 0, 3], "type" => $MOVE_ENUM),
  306. MoveStruct->new("mov" => [ 0, 4], "type" => $MOVE_ENUM),
  307. MoveStruct->new("mov" => [ 1, 2], "type" => $MOVBLOCK_ENUM),
  308. MoveStruct->new("mov" => [ 3,-2], "type" => $MOVBLOCK_ENUM),
  309. MoveStruct->new("mov" => [ 3,-3], "type" => $MOVE_ENUM),
  310. MoveStruct->new("mov" => [ 4,-4], "type" => $MOVE_ENUM),
  311. MoveStruct->new("mov" => [-1, 1], "type" => $BLOCK_ENUM),
  312. MoveStruct->new("mov" => [ 0, 1], "type" => $BLOCK_ENUM),
  313. MoveStruct->new("mov" => [ 0,-1], "type" => $BLOCK_ENUM),
  314. MoveStruct->new("mov" => [ 1,-1], "type" => $BLOCK_ENUM)
  315. ]
  316. );
  317. my %board;
  318. # Display pieces
  319. #==================================================
  320. sub get_pi_str($){
  321. my ($p) = (shift);
  322. $p =~ s/($P1|$P2)$DIV//;
  323. $p .= "_" if length($p) < 2;
  324. return $p;
  325. }
  326. sub sub_pi_str($$$){
  327. my ($p, $c0, $hex) = (shift, shift, shift);
  328. my $s0;
  329. $p = get_pi_str($p);
  330. $s0 = $hex;
  331. unless($p eq "__"){
  332. substr($s0, 2,2) = $p;
  333. }
  334. if($c0 % 2 == 0){
  335. $s0 =~ s/$SUB_CHR/$BLANK_CELL_CHR/g;
  336. }
  337. return $s0;
  338. }
  339. # Display shade
  340. #==================================================
  341. sub apply_shade($$$){
  342. my ($self, $not, $en) = (shift, shift, shift);
  343. $self->{"sc"}{$not} = $en unless grep(/^$not$/, keys( %{$self->{"sc"}} ));
  344. $self->{"sc"}{$not} = $MOVBLOCK_ENUM unless $self->{"sc"}{$not} == $en;
  345. }
  346. sub get_shade_en($$){
  347. my ($self, $not) = (shift, shift);
  348. return $self->{"sc"}{$not} if (grep /^$not$/, keys( %{$self->{"sc"}} ));
  349. return $EMPTY_ENUM;
  350. }
  351. sub get_shade_hex($){
  352. my $en = shift;
  353. return $SHADE{$en};
  354. }
  355. sub get_cell_shade($$$){
  356. my ($self, $r0, $c0) = (shift, shift, shift);
  357. my $not;
  358. $not = cell_index_rev($c0, $r0);
  359. return get_shade_hex($self->get_shade_en($not));
  360. }
  361. # Display lines
  362. #==================================================
  363. sub disp_1($$$){
  364. my ($self, $r0, $c0) = (shift, shift, shift);
  365. my $hex;
  366. $hex = $self->get_cell_shade($r0, $c0)->[0];
  367. return $hex;
  368. }
  369. sub disp_2($$$){
  370. my ($self, $r0, $c0) = (shift, shift, shift);
  371. my $p;
  372. my $not;
  373. my $hex;
  374. $hex = $self->get_cell_shade($r0, $c0)->[1];
  375. $not = cell_index_rev($c0, $r0);
  376. $p = $self->{"board"}{$not};
  377. return sub_pi_str($p, $c0, $hex);
  378. }
  379. sub disp_3($$$){
  380. my ($self, $r0, $c0) = (shift, shift, shift);
  381. my $hex;
  382. $hex = $self->get_cell_shade($r0, $c0)->[2];
  383. return $hex;
  384. }
  385. sub disp_y_axis($$$$){
  386. my ($s0, $s1, $s2, $r0) = @_;
  387. my $n0;
  388. $n0 = length($r0);
  389. $s0 = $r0 % 2 == 1 ? $PAD_ODD : $PAD_EVEN.$PREF_1;
  390. $s1 = $r0 % 2 == 1 ? $PAD_ODD : $PAD_EVEN.$PREF_2;
  391. $s1 =~ s/^ {$n0}/$r0/;
  392. $s2 = $r0 % 2 == 1 ? $PAD_ODD : $PAD_EVEN.$PREF_3;
  393. return ($s0, $s1, $s2);
  394. }
  395. # Display cell
  396. #==================================================
  397. sub add_cell($$$$$$){
  398. my ($self, $s0, $s1, $s2, $r0, $c0) = @_;
  399. $s0 .= $self->disp_1($r0, $c0);
  400. $s1 .= $self->disp_2($r0, $c0);
  401. $s2 .= $self->disp_3($r0, $c0);
  402. return ($s0, $s1, $s2);
  403. }
  404. sub disp_0($){
  405. my ($self, $r0) = (shift, shift);
  406. my ($s0, $s1, $s2);
  407. # Append the y axis
  408. ($s0, $s1, $s2) = disp_y_axis($s0, $s1, $s2, $r0);
  409. # Iterate through the cells
  410. for my $i (1..11){
  411. ($s0, $s1, $s2) = $self->add_cell($s0, $s1, $s2, $r0, $i);
  412. }
  413. return $s0."\n".$s1."\n".$s2."\n";
  414. }
  415. # Display row
  416. #==================================================
  417. sub disp_row($$){
  418. my $row;
  419. my ($self, $r0) = (shift, shift);
  420. # $r0 = shift;
  421. $row = $self->disp_0($r0);
  422. # Handle trailing characters
  423. if($r0 % 2 == 1){
  424. # Trim the start of the first line
  425. $row =~ s/$TRAIL_1/ /;
  426. # Trim the end of the first line
  427. $row =~ s/\n/$TRAIL_3\n/
  428. }else{
  429. # Trim the end of the last line
  430. $row =~ s/$TRAIL_2\n/ \n/m;
  431. }
  432. return $row;
  433. }
  434. sub disp_trailing_row(){
  435. my $s0;
  436. my $s1;
  437. $s0 = $PAD_EVEN.$PREF_1;
  438. # Clear some chars from
  439. # our hex patterns
  440. $s1 = $HEX_1;
  441. substr($s1, 2,2) = " ";
  442. # Append hex pattern to
  443. # trailing row
  444. for my $i (1..11){
  445. $s0 .= $s1;
  446. }
  447. # Clear one last pair of
  448. # chrs
  449. substr($s0, -2,2) = " ";
  450. $s0 .= "\n";
  451. return $s0;
  452. }
  453. sub disp_x_axis(){
  454. my $s0;
  455. $s0 = $PAD_AXIS;
  456. $s0 .= join(
  457. $PAD_AXIS, map{
  458. $AXIS_RV{$_}
  459. }(1..11));
  460. $s0 .= "\n";
  461. $s0 .= $PAD_AXIS;
  462. $s0 .= join(
  463. "", map{
  464. $_ % 2 == 1 ? $HL_1 : $HL_2
  465. }(1..11));
  466. $s0 .= "\n";
  467. return $s0
  468. }
  469. # Display board
  470. #==================================================
  471. sub disp_board($){
  472. my $self = shift;
  473. my $b;
  474. for my $i (map {11-$_+1} (1..11)) {
  475. $b .= $self->disp_row($i);
  476. }
  477. $b .= disp_trailing_row();
  478. $b .= disp_x_axis();
  479. $b =~ s/$TRAIL_1$TRAIL_3\n/\n/m;
  480. for my $i (1..11-1){
  481. substr($b, 2+6*$i, 2) = " ";
  482. }
  483. printf("%s", $b);
  484. }
  485. # Caclulate movement
  486. #==================================================
  487. sub pi_split($$$){
  488. my ($self, $not, $i0) = (shift, shift, shift);
  489. return (split(/$DIV/, $self->{"board"}{$not}))[$i0];
  490. }
  491. sub cell_pi($$){
  492. my ($self, $not) = (shift, shift);
  493. return $self->pi_split($not, 1);
  494. }
  495. sub cell_pl($$){
  496. my ($self, $not) = (shift, shift);
  497. return $self->pi_split($not, 0);
  498. }
  499. sub cell_index_rev($$){
  500. return $AXIS_RV{$_[0]}.$_[1];
  501. }
  502. sub cell_index($){
  503. my $chr1 = substr($_[0], 0,1);
  504. my $chr2 = substr($_[0], 1,length($_[0])-1);
  505. return ($AXIS{$chr1}, $chr2);
  506. }
  507. sub apply_shift($$){
  508. my ($not, $my_shift) = (shift, shift);
  509. my $r0;
  510. my $c0;
  511. ($c0, $r0) = cell_index($not);
  512. $r0 += $my_shift->[1];
  513. $c0 += $my_shift->[0];
  514. return $ERR_C_1 if $r0 > 11 or $c0 > 11 or $r0 < 1 or $c0 < 1;
  515. return cell_index_rev($c0, $r0);
  516. }
  517. sub calc_new_cell($$){
  518. my ($not, $mov) = (shift, shift);
  519. my ($c0, $r0) = cell_index($not);
  520. my $x_shift;
  521. my $y_shift;
  522. my $n0;
  523. my $ni;
  524. # get y_shift
  525. $y_shift = $mov->[1];
  526. # get x_shift
  527. $x_shift = $mov->[0];
  528. # make x_shift adjustment
  529. $ni = $y_shift != 0 ? ($y_shift / abs($y_shift)) : 1;
  530. $n0 = ($r0 + (($ni + 1)/2) ) % 2;
  531. $x_shift += int(($y_shift + ($n0 * $ni)) / 2);
  532. return apply_shift($not, [$x_shift, $y_shift]);
  533. }
  534. sub mirror_mov($){
  535. my $mov = shift;
  536. return MoveStruct->new(
  537. "mov" => [$mov->{"mov"}[0] * -1, $mov->{"mov"}[1] * -1],
  538. "type" => $mov->{"type"}
  539. );
  540. }
  541. sub get_mov($$$){
  542. my ($pi, $en, $apl) = (shift, shift, shift);
  543. my @mv1;
  544. @mv1 = grep {
  545. ($_->{"type"} & $en) != 0
  546. } @{$MOVE{$pi}};
  547. my ($t1, $t2) = (0, 0);
  548. if($apl eq $P2){
  549. @mv1 = map {
  550. mirror_mov($_)
  551. } @mv1;
  552. }
  553. return \@mv1;
  554. }
  555. sub find_all_mov($$$){
  556. my ($self, $not, $en) = (shift, shift, shift);
  557. my $pi;
  558. my @mv1;
  559. my $apl;
  560. $pi = $self->cell_pi($not);
  561. $apl = $self->cell_pl($not);
  562. @mv1 = @{ get_mov($pi, $en, $apl) };
  563. return grep {
  564. $_ if $_->[0] ne $ERR_C_1
  565. } map {
  566. [
  567. calc_new_cell($not, $_->{"mov"}),
  568. $_->{"type"}
  569. ]
  570. } @mv1;
  571. }
  572. sub shade_pi_mvmt($$$){
  573. my ($self, $not, $en) = (shift, shift, shift);
  574. my $c1;
  575. my @mv1;
  576. @mv1 = $self->find_all_mov($not, $en);
  577. for my $mv (@mv1){
  578. $self->apply_shade($mv->[0], $mv->[1]);
  579. }
  580. }
  581. sub shade_all_mvmt($$$){
  582. my ($self, $pl, $en) = (shift, shift, shift);
  583. my @pi1;
  584. @pi1 = grep {
  585. $self->cell_pl($_) eq $pl
  586. } keys(%{$self->{"board"}});
  587. for my $el (@pi1){
  588. $self->shade_pi_mvmt($el, $en);
  589. }
  590. }
  591. sub shade_all_p1_mvmt($){
  592. my $self = shift;
  593. $self->shade_all_mvmt($P1, $MOVBLOCK_ENUM);
  594. }
  595. sub shade_all_p2_mvmt($){
  596. my $self = shift;
  597. $self->shade_all_mvmt($P2, $MOVBLOCK_ENUM);
  598. }
  599. sub get_block_cell($$){
  600. my ($self, $pl) = (shift, shift);
  601. return map {
  602. $_->[0]
  603. } map {
  604. ( $self->find_all_mov($_, $BLOCK_ENUM) );
  605. } grep {
  606. $self->cell_pl($_) eq $pl
  607. } keys(%{$self->{"board"}});
  608. }
  609. sub check_valid_card($$){
  610. my ($self, $s1) = (shift, shift);
  611. die "invalid card/piece - $s1" unless grep {
  612. $_ =~ /^$s1$/i
  613. } @MG_PI;
  614. }
  615. sub check_empty_cell($$){
  616. my ($self, $hx1) = (shift, shift);
  617. $hx1 = uc $hx1;
  618. $self->check_valid_cell($hx1);
  619. die "piece in cell $hx1" if $self->{"board"}{$hx1} ne $EMPTY_CELL;
  620. }
  621. sub check_nonempty_cell($$){
  622. my ($self, $hx1) = (shift, shift);
  623. $hx1 = uc $hx1;
  624. $self->check_valid_cell($hx1);
  625. die "no piece in cell $hx1" if $self->{"board"}{$hx1} eq $EMPTY_CELL;
  626. }
  627. sub check_valid_cell($$){
  628. my ($self, $hx1) = (shift, shift);
  629. $hx1 = uc $hx1;
  630. die "invalid cell - $hx1" unless grep {
  631. $hx1 =~ /^$_$/i
  632. } keys %{$self->{"board"}};
  633. # } keys %board;
  634. }
  635. sub check_match_pi($$$$){
  636. my ($self, $hx1, $pi) = (shift, shift, shift);
  637. my $hx2;
  638. $hx2 = $self->cell_pi($hx1);
  639. die "$pi - Wrong piece notation for $hx1 should be $hx2" if $hx2 ne $pi;
  640. }
  641. sub check_src_cell($$$$){
  642. my ($self, $hx1, $apl, $pi) = (shift, shift, shift, shift);
  643. $hx1 = uc $hx1;
  644. $self->check_nonempty_cell($hx1);
  645. $self->check_match_pi($hx1, $pi);
  646. die "This cell is not owned by $apl" if $self->cell_pl($hx1) ne $apl;
  647. }
  648. sub check_valid_player($$){
  649. my ($self, $apl) = (shift, shift);
  650. die "invalid player - $apl" unless grep {
  651. $apl =~ /^$_$/
  652. } keys %HAND;
  653. }
  654. sub check_valid_piece($$$){
  655. my ($self, $pi, $apl) = (shift, shift, shift);
  656. $self->check_valid_card($pi);
  657. die "player $apl does not have $pi" unless grep {
  658. $pi =~ /$_$/
  659. } @{$HAND{$apl}};
  660. }
  661. sub check_block($$$){
  662. my ($self, $s0, $apl) = (shift, shift, shift);
  663. for my $c0 ($self->get_block_cell($OPPL{$apl})){
  664. die "summon to cell $s0 is blocked" if $s0 eq $c0;
  665. }
  666. }
  667. sub check_valid_mov($$$){
  668. my ($self, $src, $dst) = (shift, shift, shift);
  669. $src = uc $src;
  670. die "not valid move" unless grep {$dst eq $_->[0]} $self->find_all_mov($src, $MOVE_ENUM);
  671. }
  672. sub check_sz($$$){
  673. my ($self, $hx1, $apl) = (shift, shift, shift);
  674. my ($c0, $r0) = cell_index($hx1);
  675. die "$hx1 not in start zone" if($r0 > 3 && $apl eq $P1);
  676. die "$hx1 not in start zone" if($r0 < 8 && $apl eq $P2);
  677. }
  678. sub draw($$$){
  679. my ($self, $s0, $apl) = (shift, shift, shift);
  680. my $i = 0;
  681. for my $s1 (uniq( [split(/ /, $s0)] )){
  682. $i++;
  683. $self->check_valid_card($s1);
  684. push(@{$HAND{$apl}}, $s1);
  685. }
  686. die "draw() $s0 - hand size less than $HAND_SIZE. Possible duplicate card?" if $i < $HAND_SIZE;
  687. }
  688. sub summon($$$){
  689. my ($self, $s0, $apl) = (shift, shift, shift);
  690. my ($pi, $hx1) = $s0 =~ /([A-Za-z]{1,2})([A-Za-z][0-9]{1,})/;
  691. $hx1 = uc $hx1;
  692. $self->check_empty_cell($hx1);
  693. $self->check_valid_player($apl);
  694. $self->check_valid_piece($pi, $apl);
  695. $self->check_block($hx1, $apl);
  696. $self->{"board"}{uc $hx1} = $apl.$DIV.$pi;
  697. }
  698. sub sz_summon($$$){
  699. my ($self, $s0, $apl) = (shift, shift, shift);
  700. my ($pi, $hx1) = $s0 =~ /([A-Za-z]{1,2})([A-Za-z][0-9]{1,})/;
  701. $hx1 = uc $hx1;
  702. $self->check_sz($hx1, $apl);
  703. $self->summon($s0, $apl);
  704. }
  705. sub ft_summon($$$){
  706. my ($self, $s0, $apl) = (shift, shift, shift);
  707. die "Must summon queen on first turn" unless $s0 =~ /$MG_Q[A-ka-k]{1,2}[0-9]{1,2}/;
  708. die "Max summons on first turn is $MAX_FT_SUMMON" if ( scalar (() = $s0 =~ /\*/g) > $MAX_FT_SUMMON );
  709. for my $mv1 ($s0 =~ /\b[A-Za-z]{2,3}[0-9]{1,2}\*/g){
  710. $self->sz_summon($mv1, $apl);
  711. }
  712. }
  713. sub mov($$$){
  714. my ($self, $s0, $apl) = (shift, shift, shift);
  715. my ($pi, $src, $dst) = $s0 =~ /([A-Za-z]){1,2}([A-Za-z][0-9]{1,2})([A-Za-z][0-9]{1,2})$/;
  716. $src = uc $src;
  717. $dst = uc $dst;
  718. $self->check_valid_player($apl);
  719. $self->check_src_cell($src, $apl, $pi);
  720. $self->check_empty_cell($dst);
  721. $self->check_valid_mov($src, $dst);
  722. $self->{"board"}{$dst} = $self->cell_pl($src).$DIV.$self->cell_pi($src);
  723. $self->{"board"}{$src} = $EMPTY_CELL;
  724. }
  725. sub new {
  726. my $class = shift;
  727. my $self = { @_ };
  728. $self->{"board"} = { map {
  729. $_ => $EMPTY_CELL
  730. } map {
  731. my $l0;
  732. $l0 = $_;
  733. (map {$l0.$_} ("1".."11"))
  734. } map {
  735. $AXIS_RV{$_}
  736. }(1...11) };
  737. # Creates a hash of the the form
  738. # $board{cell_notation} = piece_enum
  739. %board = map {
  740. $_ => $EMPTY_CELL
  741. } map {
  742. my $l0;
  743. $l0 = $_;
  744. (map {$l0.$_} ("1".."11"))
  745. } map {
  746. $AXIS_RV{$_}
  747. }(1...11);
  748. $self->{"sc"} = {};
  749. # Both players start with a
  750. # queen
  751. push(@{$HAND{$P1}}, "Q");
  752. push(@{$HAND{$P2}}, "Q");
  753. return bless $self, $class;
  754. }
  755. sub uniq($){
  756. my %h0;
  757. return grep { !$h0{$_}++ } @{$_[0]};
  758. }
  759. sub P1 {
  760. return $P1;
  761. }
  762. sub P2 {
  763. return $P2;
  764. }
  765. sub MG_A {
  766. return $MG_A;
  767. }
  768. sub MG_I{
  769. return $MG_I;
  770. }
  771. sub MG_N{
  772. return $MG_N;
  773. }
  774. sub MG_IT{
  775. return $MG_I;
  776. }
  777. sub MG_H{
  778. return $MG_H;
  779. }
  780. sub MG_S{
  781. return $MG_S;
  782. }
  783. sub MG_RC{
  784. return $MG_RO;
  785. }
  786. sub MG_HS{
  787. return $MG_H;
  788. }
  789. sub MG_RO{
  790. return $MG_RC;
  791. }
  792. sub MG_B{
  793. return $MG_B;
  794. }
  795. sub MG_P{
  796. return $MG_P;
  797. }
  798. sub MG_IM{
  799. return $MG_I;
  800. }
  801. sub MG_F{
  802. return $MG_F;
  803. }
  804. sub MG_QS{
  805. return $MG_QS;
  806. }
  807. sub MG_AU{
  808. return $MG_A;
  809. }
  810. sub MG_SY{
  811. return $MG_SY;
  812. }
  813. sub MG_Q{
  814. return $MG_Q;
  815. }
  816. binmode(STDOUT, ":utf8");
  817. return 1;