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.

439 lines
7.4KB

  1. #!/usr/bin/perl
  2. use warnings;
  3. use strict;
  4. use utf8;
  5. my $PAD_AXIS = " ";
  6. my $PAD_EVEN = " ";
  7. my $PAD_ODD = " ";
  8. my $HEX_1 = '-/--\-';
  9. my $HEX_2 = '| __ |';
  10. my $HEX_3 = '| |';
  11. my $XBOX_CHR = chr(0x2573);
  12. my $SHADE_CHR = chr(0x2591);
  13. my $ALT_US = chr(0x2017);
  14. my $ALT_PIPE = chr(0x2016);
  15. my $HL_1 = "|_____";
  16. my $HL_2 = $ALT_PIPE.$ALT_US.$ALT_US.$ALT_US.$ALT_US.$ALT_US;
  17. my $SUB_CHR = "_";
  18. my $ALT_SUB_CHR = $ALT_US;
  19. my $PREF_1 = substr($HEX_1, -2, 2);
  20. my $PREF_2 = ' ';
  21. my $PREF_3 = ' ';
  22. my $TRAIL_1 = substr($HEX_1, 0, 1);
  23. my $TRAIL_2 = substr($HEX_1, -1, 1);
  24. my $TRAIL_3 = substr($HEX_1, 0, 2);
  25. # Pieces
  26. my $MG_A = "A"; # Apprentice
  27. my $MG_I = "I"; # Iron Maiden
  28. my $MG_N = "N"; # Nekomata
  29. my $MG_IT = "It"; # Ittan-Momen
  30. my $MG_H = "H"; # Harpy
  31. my $MG_S = "S"; # Slime
  32. my $MG_RC = "Rc"; # Redcap
  33. my $MG_RO = "Hs"; # Red Oni
  34. my $MG_HS = "Ro"; # Holstaur
  35. my $MG_B = "B"; # Blue Oni
  36. my $MG_P = "P"; # Preistess
  37. my $MG_IM = "Im"; # Imp
  38. my $MG_F = "F"; # False Angel
  39. my $MG_QS = "Qs"; # Queen slime
  40. my $MG_AU = "Au"; # Automaton
  41. my $MG_SY = "Sy"; # Sylph
  42. my $MG_Q = "Q"; # Queen
  43. # Players
  44. my $P1 = "P1";
  45. my $P2 = "P2";
  46. my $DIV = ":";
  47. my %AXIS = (
  48. "A" => 1,
  49. "B" => 2,
  50. "C" => 3,
  51. "D" => 4,
  52. "E" => 5,
  53. "F" => 6,
  54. "G" => 7,
  55. "H" => 8,
  56. "I" => 9,
  57. "J" => 10,
  58. "K" => 11
  59. );
  60. my %AXIS_RV = map {
  61. $AXIS{$_} => $_
  62. } keys(%AXIS);
  63. #
  64. # /--\ +1
  65. # | __ |
  66. # | |+1
  67. # \--/
  68. # -1 -1
  69. #
  70. # ODD
  71. # UP: 0, +1
  72. # DOWN: -1, -1
  73. # EVEN
  74. # UP: +1, +1
  75. # DOWN: +0, -1
  76. # [Row move, Diag move]
  77. my %MOVE = (
  78. $MG_A => [
  79. [-1, 1], [ 0, 1]
  80. ],
  81. $MG_Q => [
  82. [ 0, 1], [ 1, 0], [-1, 0], [ 0,-1],
  83. ],
  84. $MG_I => [
  85. [0,0]
  86. ],
  87. $MG_IT => [
  88. [ 0,-1], [ 1,-1]
  89. ],
  90. $MG_N => [
  91. [-1, 2],
  92. [ 1,-2]
  93. ],
  94. $MG_H => [
  95. [-3, 2], [-1,-2], [ 1, 2], [ 3,-2]
  96. ],
  97. $MG_RC => [
  98. [-1, 0], [-2, 0], [ 0, 1], [ 0, 2]
  99. ],
  100. $MG_S => [
  101. [-1, 1], [-2, 2], [ 0, 1], [ 0, 2],
  102. [ 0,-1], [ 0,-2], [ 1,-1], [ 2,-2],
  103. ],
  104. $MG_HS => [
  105. [-3, 1], [-2,-1], [ 2, 1], [ 3,-1]
  106. ],
  107. $MG_RO => [
  108. [-1, 1], [ 0, 1], [ 1, 1], [ 1,-2]
  109. ],
  110. $MG_B => [
  111. [-1, 1], [ 0, 1], [ 0,-2], [ 1,-2]
  112. ],
  113. $MG_P => [
  114. [-4, 2], [-2, 1], [-2,-2], [-1,-1],
  115. [ 1, 1], [ 2,-1], [ 2, 2], [ 4,-2]
  116. ],
  117. $MG_IM => [
  118. [-2, 1], [-1,-1], [-1, 2], [ 1, 1],
  119. [ 1,-1], [ 1,-2], [ 2,-1]
  120. ],
  121. $MG_F => [
  122. [-1, 0], [-1, 1], [ 0, 1], [ 0,-1],
  123. [ 1, 0], [ 1,-1]
  124. ],
  125. $MG_QS => [
  126. [-3, 3], [-2, 2], [-2, 0], [-1, 0],
  127. [-1, 1], [ 0, 1], [ 0, 2], [ 0, 3],
  128. [ 0,-1], [ 0,-2], [ 0,-3], [ 1, 0],
  129. [ 1,-1], [ 2, 0], [ 2,-2], [ 3,-3],
  130. ],
  131. $MG_AU => [
  132. [-1, 0], [-1, 1], [ 0, 1], [ 0,-1],
  133. [ 1, 0], [ 1,-1]
  134. ],
  135. $MG_SY => [
  136. [-4, 4], [-3, 3], [-3, 2], [-1,-2],
  137. [ 0,-2], [ 0,-3], [ 0, 3], [ 0, 4],
  138. [ 1, 2], [ 3,-2], [ 3,-3], [ 4,-4]
  139. ]
  140. );
  141. # Special cells
  142. my $EMPTY_CELL = "_";
  143. my %board;
  144. # Display pieces
  145. #==================================================
  146. sub f_1($$){
  147. my $p = shift;
  148. my $c0 = shift;
  149. my $s0;
  150. $p =~ s/($P1|$P2)$DIV//;
  151. $p .= "_" if length($p) < 2;
  152. $s0 = $HEX_2;
  153. $s0 =~ s/$SUB_CHR{1,2}/$p/;
  154. if($c0 % 2 == 0){
  155. $s0 =~ s/$SUB_CHR/$ALT_SUB_CHR/g;
  156. }
  157. return $s0;
  158. }
  159. # Display lines
  160. #==================================================
  161. sub disp_1($$){
  162. my ($r0, $c0) = (shift, shift);
  163. return $HEX_1;
  164. }
  165. sub disp_2($$){
  166. my ($r0, $c0) = (shift, shift);
  167. my $p;
  168. # Cell notation
  169. my $not;
  170. $not = cell_index_rev($c0, $r0);
  171. $p = $board{$not};
  172. return f_1($p, $c0);
  173. # my ($r0, $c0) = (shift, shift);
  174. # return $HEX_2;
  175. }
  176. sub disp_3($$){
  177. my ($r0, $c0) = (shift, shift);
  178. return $HEX_3;
  179. }
  180. sub disp_y_axis($$$$){
  181. my ($s0, $s1, $s2, $r0) = @_;
  182. my $n0;
  183. $n0 = length($r0);
  184. $s0 = $r0 % 2 == 1 ? $PAD_ODD : $PAD_EVEN.$PREF_1;
  185. $s1 = $r0 % 2 == 1 ? $PAD_ODD : $PAD_EVEN.$PREF_2;
  186. $s1 =~ s/^ {$n0}/$r0/;
  187. $s2 = $r0 % 2 == 1 ? $PAD_ODD : $PAD_EVEN.$PREF_3;
  188. return ($s0, $s1, $s2);
  189. }
  190. # Display cell
  191. #==================================================
  192. sub add_cell($$$$$){
  193. my ($s0, $s1, $s2, $r0, $c0) = @_;
  194. $s0 .= disp_1($r0, $c0);
  195. $s1 .= disp_2($r0, $c0);
  196. $s2 .= disp_3($r0, $c0);
  197. # if($c0 % 2 == 0){
  198. # $s0 =~ s/ /$SHADE_CHR/g;
  199. # $s1 =~ s/ /$SHADE_CHR/g;
  200. # $s2 =~ s/ /$SHADE_CHR/g;
  201. # }
  202. return ($s0, $s1, $s2);
  203. }
  204. sub disp_0($){
  205. my $r0;
  206. my ($s0, $s1, $s2);
  207. $r0 = shift;
  208. # Append the y axis
  209. ($s0, $s1, $s2) = disp_y_axis($s0, $s1, $s2, $r0);
  210. # Iterate through the cells
  211. for my $i (1..11){
  212. ($s0, $s1, $s2) = add_cell($s0, $s1, $s2, $r0, $i);
  213. }
  214. return $s0."\n".$s1."\n".$s2."\n";
  215. }
  216. # Display row
  217. #==================================================
  218. sub disp_row($){
  219. my $row;
  220. my $r0;
  221. $r0 = shift;
  222. $row = disp_0($r0);
  223. # Handle trailing characters
  224. if($r0 % 2 == 1){
  225. # Trim the start of the first line
  226. $row =~ s/$TRAIL_1/ /;
  227. # Trim the end of the first line
  228. $row =~ s/\n/$TRAIL_3\n/
  229. }else{
  230. # Trim the end of the last line
  231. $row =~ s/$TRAIL_2\n/ \n/m;
  232. }
  233. return $row;
  234. }
  235. sub disp_trailing_row(){
  236. my $s0;
  237. my $s1;
  238. $s0 = $PAD_EVEN.$PREF_1;
  239. # Clear some chars from
  240. # our hex patterns
  241. $s1 = $HEX_1;
  242. substr($s1, 2,2) = " ";
  243. # Append hex pattern to
  244. # trailing row
  245. for my $i (1..11){
  246. $s0 .= $s1;
  247. }
  248. # Clear one last pair of
  249. # chrs
  250. substr($s0, -2,2) = " ";
  251. $s0 .= "\n";
  252. return $s0;
  253. }
  254. sub disp_x_axis(){
  255. my $s0;
  256. $s0 = $PAD_AXIS;
  257. $s0 .= join(
  258. $PAD_AXIS, map{
  259. $AXIS_RV{$_}
  260. }(1..11));
  261. $s0 .= "\n";
  262. $s0 .= $PAD_AXIS;
  263. $s0 .= join(
  264. "", map{
  265. $_ % 2 == 1 ? $HL_1 : $HL_2
  266. }(1..11));
  267. $s0 .= "\n";
  268. return $s0
  269. }
  270. # Display board
  271. #==================================================
  272. sub disp_board(){
  273. my $b;
  274. for my $i (map {11-$_+1} (1..11)) {
  275. $b .= disp_row($i);
  276. }
  277. $b .= disp_trailing_row();
  278. $b .= disp_x_axis();
  279. $b =~ s/$TRAIL_1$TRAIL_3\n/\n/m;
  280. for my $i (1..11-1){
  281. substr($b, 2+6*$i, 2) = " ";
  282. }
  283. printf("%s", $b);
  284. }
  285. sub cell_index_rev($$){
  286. return $AXIS_RV{$_[0]}.$_[1];
  287. }
  288. sub cell_index($){
  289. my ($chr1, $chr2) = (split(//, $_[0]));
  290. return ($AXIS{$chr1}, $chr2);
  291. }
  292. sub apply_shift($$){
  293. my ($not, $my_shift) = (shift, shift);
  294. my $r0;
  295. my $c0;
  296. ($r0, $c0) = cell_index($not);
  297. $r0 += $my_shift->[0];
  298. $c0 += $my_shift->[1];
  299. die "cell index [$r0, $c0]: out of bound exception" if $r0 > 11 or $c0 > 11 or $r0 < 1 or $c0 < 1;
  300. return cell_index_rev($r0, $c0);
  301. }
  302. sub calc_move($$){
  303. my ($not, $mov) = (shift, shift);
  304. my $r0;
  305. my $c0;
  306. my $x_shift;
  307. my $y_shift;
  308. my $n0;
  309. my $ni;
  310. ($c0, $r0) = cell_index($not);
  311. # get y_shift
  312. $y_shift = $mov->[1];
  313. # get x_shift
  314. $x_shift = $mov->[0];
  315. # make x_shift adjustment
  316. $ni = $y_shift != 0 ? ($y_shift / ($y_shift * -1)) : -1;
  317. $ni *= -1;
  318. $n0 = ($r0 + 1) % 2;
  319. $x_shift += int(($y_shift + ($n0 * $ni)) / 2);
  320. return apply_shift($not, [$x_shift, $y_shift]);
  321. }
  322. # Main starts here!
  323. binmode(STDOUT, ":utf8");
  324. # Creates a hash of the the form
  325. # $board{cell_notation} = piece_enum
  326. %board = map {
  327. $_ => $EMPTY_CELL
  328. } map {
  329. my $l0;
  330. $l0 = $_;
  331. (map {$l0.$_} ("1".."11"))
  332. } map {
  333. $AXIS_RV{$_}
  334. }(1...11);
  335. my $m1 = "E6";
  336. my $c1 = $MG_A;
  337. $board{$m1} = $P1.$DIV.$c1;
  338. for my $mv (@{$MOVE{$c1}}){
  339. printf("%s\n", calc_move($m1, $mv));
  340. }
  341. disp_board();