我在Perl 5.24中制作Tic-Tac-Toe并正在努力以不同的颜色显示获胜的动作,所以我在棋盘中的每个角色中进行迭代并使用print()
将字符显示在屏幕上。
我遇到的问题是,每次for
循环递增时,print()
都会为每个字符添加换行符。
我使用了this,
this,
this,和
this并且还有换行符,所以在我看来问题是print()
和/或循环如何在Perl中运行。
根据要求,这里是整个项目:
use 5.24.0;
use warnings;
use strict;
use Win32::Console;
my $CONSOLE = Win32::Console->new( STD_OUTPUT_HANDLE );
my $attr = $CONSOLE->Attr();
$| = 1;
use constant { TRUE => 1, FALSE => 0 };
use subs qw(pause);
my $player = "X";
my @usedXMoves = [];
my @usedOMoves = [];
my $xScore = 0;
my $oScore = 0;
my $winningMove = "";
my %indsToCheck = (
Top => [ 0, 2, 4 ],
Bottom => [ 12, 14, 16 ],
Left => [ 0, 6, 12 ],
Right => [ 4, 10, 16 ],
MidV => [ 2, 8, 14 ],
MidH => [ 6, 8, 10 ],
DiaTB => [ 0, 8, 16 ],
DiaBT => [ 12, 8, 4 ]
);
main();
sub main {
my ( $gameBoard, %boardInds ) = ResetBoard();
DisplayBoardAndInds( $gameBoard, \%boardInds );
my $res = -1;
while ( TRUE ) {
if ( -2 == $res ) {
DisplayScores( TRUE );
last;
}
elsif ( 1 == $res ) {
# Update score first
if ( "X" eq $player ) { $xScore++; }
else { $oScore++; }
say "\n\nWe have a winner!\nWould you like to play again? (Y/N) ";
my $again = <STDIN>;
chomp $again;
if ( "Y" eq uc( $again ) ) {
( $gameBoard, %boardInds ) = ResetBoard();
$res = -1;
DisplayScores();
SwitchPlayer();
}
elsif ( "N" eq uc( $again ) ) {
DisplayScores( TRUE );
last;
}
}
else {
$res = ValidateAndApplyMove( GetInput( \%boardInds ), \$gameBoard );
}
DisplayBoardAndInds( $gameBoard, \%boardInds );
}
}
sub pause {
<STDIN>;
}
sub SetColor {
$CONSOLE->Attr( shift );
}
sub ResetColor {
$CONSOLE->Attr( $attr );
}
# Will display text in color
# in: Color, text
sub PrintInColor {
SetColor( shift );
$CONSOLE->Write( shift );
ResetColor();
}
# Resets the gameboard and playable indicies
sub ResetBoard {
my $gameBoard = "_|_|_\n_|_|_\n | | ";
my %boardInds = (
TL => 0,
TM => 2,
TR => 4,
ML => 6,
MM => 8,
MR => 10,
BL => 12,
BM => 14,
BR => 16
);
@usedXMoves = [];
@usedOMoves = [];
return ( $gameBoard, %boardInds );
}
# Displays the current board and usable moves
sub DisplayBoardAndInds {
system( "cls" );
my $board = shift;
my $refInds = shift;
if ( "" ne $winningMove ) {
my @winningInds = @{ $indsToCheck{$winningMove} };
my $indInd = 0;
my $currInd = $winningInds[0];
# TODO:
# Figure out why new lines are being appended here
use Data::Dumper;
$Data::Dumper::Useqq = 1;
$CONSOLE->Write( Dumper $board);
$CONSOLE->Write( Dumper $FG_RED);
pause;
for my $i ( 0 .. length( $board ) - 1 ) {
if ( $i eq $currInd ) {
PrintInColor( $FG_RED, substr( $board, $i, 1 ) );
$indInd++;
$currInd = $winningInds[$indInd];
}
else {
$CONSOLE->Write( substr( $board, $i, 1 ) );
}
pause;
}
$CONSOLE->Write( "\n" );
$winningMove = "";
}
else {
say $board;
}
say "Current player = $player\n";
# Sort by value (using reference)
foreach my $k ( sort { $refInds->{$a} <=> $refInds->{$b} } keys( %$refInds ) ) {
$CONSOLE->Write( "$k, " );
}
$CONSOLE->Write( "EXIT\n" );
}
sub DisplayScores {
system( "cls" );
my $final = shift;
if ( $final ) {
say "Final scores:";
}
else {
say "Scores:";
}
say "X: $xScore";
say "O: $oScore";
if ( $final ) {
say "\n\nThanks for playing!";
}
pause;
}
# Retrieves and validates input
sub GetInput {
$CONSOLE->Write( "What move would you like to make? " );
my $move = <STDIN>;
chomp $move; # <STDIN> returns with a newline
$move = uc( $move );
my $refInds = shift;
my $ret = -1;
if ( "exit" eq lc( $move ) ) {
$ret = -2;
}
if ( exists $refInds->{$move} ) {
$ret = $refInds->{$move};
delete $refInds->{$move};
}
return $ret;
}
# Displays any error message
# If none, then applies the move to the board
sub ValidateAndApplyMove {
my $move = shift;
my $gameBoard = shift;
if ( -2 == $move ) {
return -2;
}
elsif ( -1 == $move ) {
say "\n\nInvalid move. Please try again.";
pause;
}
else {
my $tBoard = ${$gameBoard};
my $len = length( $tBoard );
$tBoard = substr( $tBoard, 0, $move ) . $player . substr( $tBoard, $move + 1, $len );
${$gameBoard} = $tBoard;
if ( "X" eq $player ) {
push @usedXMoves, $move;
}
else {
push @usedOMoves, $move;
}
if ( CheckWin() ) {
return 1;
}
#SwitchPlayer();
}
return 0;
}
# Updates the current player
sub SwitchPlayer {
if ( "X" eq $player ) {
$player = "O";
}
else {
$player = "X";
}
}
# Checks current moves against winning conditions
sub CheckWin {
my @moves = [];
if ( "X" eq $player ) {
@moves = @usedXMoves;
}
else {
@moves = @usedOMoves;
}
return (
GetRow( "Top", @moves )
or GetRow( "MidH", @moves )
or GetRow( "Bottom", @moves )
or GetRow( "Left", @moves )
or GetRow( "MidV", @moves )
or GetRow( "Right", @moves )
or GetRow( "DiaTB", @moves )
or GetRow( "DiaBT", @moves )
);
}
# Returns true if the passed in array contains all the values for a given row
sub GetRow {
my $row = shift;
my @moves = @_;
# Convert array to map
my %moves = map { $_ => 1 } @moves;
my @indsToCheck = @{ $indsToCheck{$row} };
foreach ( @indsToCheck ) {
if ( !exists( $moves{$_} ) ) {
return FALSE;
}
}
$winningMove = $row;
return TRUE;
}
董事会成员:
X|X|X
O|X|_
O|_|O
输出:
X
|
X
|
X
...
那么如何在循环中不使用换行符进行打印?
答案 0 :(得分:3)
看过你的完整代码,我确切地知道发生了什么
你的程序有这个循环
for my $i ( 0 .. length( $board ) - 1 ) {
if ( $i eq $currInd ) {
PrintInColor( $FG_RED, substr( $board, $i, 1 ) );
$indInd++;
$currInd = $winningInds[$indInd];
}
else {
$CONSOLE->Write( substr( $board, $i, 1 ) );
}
pause;
}
其中pause
是
sub pause {
<STDIN>;
}
这意味着你必须按返回来逐步完成循环。每次执行此操作时,都会在屏幕上显示换行符。删除pause
,它将起作用
除非您自己在其他地方添加了代码,否则您展示的代码没有理由打印换行符
我能为您做的最好的事情是发布一个示例程序,该程序使用您在$board
中所说的字符串,并以 X 字符显示为红色。请注意,Attr()
不会重置颜色;您必须使用Attr($FG_WHITE)
use strict;
use warnings 'all';
use Win32::Console;
my $c = Win32::Console->new(STD_OUTPUT_HANDLE);
$c->Cls($FG_WHITE | $BG_BLACK);
my $board = "X|X|X\n_|_|_\n | | | ";
for my $ch ( split //, $board ) {
if ( $ch eq 'X' ) {
$c->Attr($FG_LIGHTRED);
$c->Write($ch);
$c->Attr($FG_WHITE);
}
else {
$c->Write($ch);
}
}
答案 1 :(得分:1)
如果$board
不包含任何换行符,那么您声称print
正在为您要打印的内容添加换行符。默认情况下,print
不会附加任何内容。如果它附加换行符,则必须设置$\ = "\n";
(可能使用-l
)。