Skip to content

Instantly share code, notes, and snippets.

@bluebat
Created February 25, 2014 08:06
Show Gist options
  • Save bluebat/9204818 to your computer and use it in GitHub Desktop.
Save bluebat/9204818 to your computer and use it in GitHub Desktop.
#!/usr/bin/perl -w
# 作者: 洪朝貴 http://www.cyut.edu.tw/~ckhung/, 2001.
# 趙惟倫 <[email protected]>, 2012.
# 功能: 讓使用者下象棋的程式. 純粹只是版面安排及棋子移動;
# 沒有電腦下棋的功能.
# 需求: 系統內應有 ncurses 程式庫, 及 perl 的 curses 模組.
# 操作說明: 用方向鍵移動遊標, 用空間棒撿起/放下棋子,
# 按 s 將目前盤面存檔. 所存檔案, 下次可作為命令列參數
# 其他: 在彩色終端機上可顯示彩色 (例如 cxterm-color 或 linux
# console); 在黑白終端機上 (例如 MS Windows 的 telnet)
# 則以反白區別將帥兩國. (由 TERM 這個環境變數決定.)
# 版權聲明: XFree86 style. 若要將本程式修改成有用的大程式,
# 建議將您的版本施以 GPL.
use Curses;
use Data::Dumper;
use strict;
use vars qw($pos); # 用 my 宣告的變數無法跨越檔案
my (%viseff, $pos0, $chess, $ch, $cursor, $picked);
$pos0 = { # 標準位置
'將'=>[0,0],
'士1'=>[0,-1], '士2'=>[0,1], '象1'=>[0,-2], '象2'=>[0,2],
'車1'=>[0,-4], '車2'=>[0,4], '馬1'=>[0,-3], '馬2'=>[0,3],
'包1'=>[2,-3], '包2'=>[2,3], '卒1'=>[3,-4], '卒2'=>[3,4],
'卒3'=>[3,-2], '卒4'=>[3,2], '卒5'=>[3,0],
'帥'=>[9,0],
'仕1'=>[9,-1], '仕2'=>[9,1], '相1'=>[9,-2], '相2'=>[9,2],
'俥1'=>[9,-4], '俥2'=>[9,4], '傌1'=>[9,-3], '傌2'=>[9,3],
'炮1'=>[7,-3], '炮2'=>[7,3], '兵1'=>[6,-4], '兵2'=>[6,4],
'兵3'=>[6,-2], '兵4'=>[6,2], '兵5'=>[6,0],
};
$cursor = [9,0];
initscr();
cbreak();
noecho();
keypad(1);
# getmaxyx($height, $width);
%viseff = set_visual_effect();
foreach $chess (keys %$pos0) {
@{$pos->{$chess}} = @{$pos0->{$chess}};
}
if (-r $ARGV[0]) {
do $ARGV[0];
# "do" is better because "require" tries to avoid repeated loading.
redraw();
show_status("saved game restored!");
} else {
redraw();
}
$picked = 0; # 目前撿起了那個棋子
while (1) {
move(xy2rc(@$cursor));
$ch = getch();
show_status(" " x 60);
if ($ch eq KEY_LEFT) {
--$cursor->[0];
$cursor->[0] += 10 if $cursor->[0] < 0;
} elsif ($ch eq KEY_RIGHT) {
++$cursor->[0];
$cursor->[0] -= 10 if $cursor->[0] > 9;
} elsif ($ch eq KEY_UP) {
--$cursor->[1];
$cursor->[1] += 9 if $cursor->[1] < -4;
} elsif ($ch eq KEY_DOWN) {
++$cursor->[1];
$cursor->[1] -= 9 if $cursor->[1] > 4;
} elsif ($ch eq ' ') {
$chess = who_is_at(@$cursor);
if ($picked) { # 即將放下棋子
if ($chess and $chess ne $picked) { # 底下原本有一個棋子
if (side($chess) == side($picked)) {
flash(); # 同一國的, 不可以吃啦!
next;
} else { # 另一國的, 吃掉!
delete $pos->{$chess};
}
}
move_chess($picked, @$cursor);
$picked = 0;
} else { # 即將撿起棋子
if (not $chess) { # 可是這裡沒有棋子可撿啊!
flash();
next;
}
$picked = $chess;
show_chess($chess, $viseff{picked});
}
} elsif ($ch eq 's') {
$Data::Dumper::Terse = 1; # 印變數時只要內容不要首尾
open F, "> save.cch" or die "can't open save.cch";
print F '$pos = ', Dumper($pos), ";\n";
close F;
show_status("Saved!");
} elsif ($ch eq "\x0c" || $ch eq "\x12") {
redraw();
} else {
last;
}
}
endwin();
sub xy2rc { # 把棋盤座標轉換成螢幕字元座標
return (($_[1]+4)*2+2, $_[0]*6+8);
}
sub show_status {
addstr(0, 0, @_);
}
sub redraw { # 重畫整個棋盤及所有棋子
my ($x, $y, @t);
clear();
for ($y=-4; $y<=4; ++$y) {
addstr(xy2rc(0, $y), ("+-----" x 9) . "+");
}
for ($x=0; $x<=9; ++$x) {
for ($y=-4; $y<=3; ++$y) {
@t = xy2rc($x, $y);
addstr($t[0]+1, $t[1], "|");
}
}
foreach (keys %$pos) {
show_chess($_);
}
}
sub side { # 這個棋子是那一國的?
return ($pos0->{$_[0]}[0] > 5) ? 1 : 0;
}
sub show_chess {
my ($chess, $attr) = @_;
$attr |= side($chess) ? $viseff{side_B} : $viseff{side_A};
attrset($attr);
addstr(xy2rc(@{$pos->{$chess}}), substr($chess,0,3));
attrset(A_NORMAL);
}
sub who_is_at { # 那個棋子落在這個座標上?
my ($x, $y) = @_;
my ($c);
foreach $c (keys %$pos) {
return $c if ($x == $pos->{$c}[0] && $y == $pos->{$c}[1]);
}
return 0;
}
sub set_visual_effect { # 決定要用黑白還是彩色
return (
side_A=>A_NORMAL, side_B=>A_REVERSE, picked=>A_UNDERLINE,
) unless has_colors();
start_color();
init_pair(1, COLOR_CYAN, COLOR_BLACK);
init_pair(2, COLOR_RED, COLOR_BLACK);
return (
side_A=>COLOR_PAIR(1), side_B=>COLOR_PAIR(2), picked=>A_REVERSE,
);
}
sub move_chess {
my ($chess, @new_pos) = @_;
addstr(xy2rc(@{$pos->{$chess}}), $pos->{$chess}[0] == 9 ? '+' : '+-');
@{$pos->{$chess}} = @new_pos;
show_chess($chess);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment