NAME
Game::Cribbage::Terminal - the cribbage board on a terminal
VERSION
Version 0.18
SYNOPSIS
my $t = Game::Cribbage::Terminal->new;
my $status = $t->start; # RETURNS the exit status; never exits
Game::Cribbage::Terminal->new(picking => 0)->start; # type numbers
DESCRIPTION
Everything that knows about a screen, and nothing that knows about the rules: those are Game::Cribbage::Board's. in and out are read-write properties defaulting to STDIN and STDOUT, so a test can hand it a pair of handles and read back exactly what it drew.
start returns and never calls exit. Its return value is the exit status bin/cribbage should use: 0 if you won or quit, 1 if you lost.
PROPERTIES
The following properties are defined in Game::Cribbage::Terminal
board
Property to store the current Game::Cribbage::Board
$game->board;
dealer
Property to store a boolean of whether the current player is the dealer for the current round. If true they are.
$game->dealer;
crib_set
Property to store a boolean of whether the current plays crib is set.
$game->crib_set;
starter_card
Property to store the starter card for the current play.
$game->starter_card;.
FUNCTIONS
The following functions are defined in Game::Cribbage::Terminal
my $game = Game::Cribbage->new;
$game->clear_screen;
$game->print_header("Welcome to terminal Cribbage");
$game->print_footer("Insert name: ");
my $name = <STDIN>;
chomp($name);
my $board = Game::Cribbage::Board->new();
$board->add_player(name => 'Bot');
$board->add_player(name => $name);
$board->start_game();
/split
$game->board($board);
$game->clear_screen;
$game->reset_cursor();
$game->split_cards();
$game->init_draw();
options
my $fields = Game::Cribbage::Terminal->options;
The options a person would set before a game, for a launcher to show. There are none, so the list is empty.
run
exit Game::Cribbage::Terminal->run(@ARGV);
The whole command line program as a class method: parses the options bin/cribbage documents, builds the terminal, plays, and returns the exit status rather than calling exit: 0 if you won or quit, 1 if you lost, 2 for a bad option, with the usage on STDERR. --help prints the usage on STDOUT and returns 0. Signal handlers are local to the call and the terminal is left in cooked mode on every way out, so a launcher such as Game::Terminal can call it in its own process and carry on afterwards. Colour is off under NO_COLOR and off a terminal.
start
Start a new terminal cribbage game. This function setups the Game::Cribbage::Board setting the players and starting the game. It will then call init_game.
$game->start();
init_game
Initialise a new terminal game, clearing the welcome start screen, calling split_cards and then init_draw.
$game->init_game();
init_draw
This is where the main terminal game loop happens. For each new round/draw this function is called recursively. Cards are drawn, discarded and the starter card is set. Hands are played until no cards are left, scores are calculated and we repeat..
$game->init_draw();
end_hands
When all cards have been used in the current draw/round then this end_hands function should be called. It handles the ending of the round and will render to the terminal an overview of the round/draw including all cards and the relevant scores.
$game->end_hands();
play_hand
Contains the logic needed to handle the play of the players hand, aka placing a card or calling go because you cannot play a card.
$game->play_hand();.
split_cards
Contains the logic needed to decide which player goes first as the dealer.
$game->split_cards();
draw_cards
Contains the logic needed to draw player cards so they can then decide which two to discard.
$game->draw_cards();
discard_cards
Contains the logic neeeded to discard two cards from the players and bots hands into the crib.
$game->discard_cards();
starter
Contains the logic needed to select the starter card for the current draw.
$game->starter();
render_card
Contians the logic needed to render a card to the terminal.
$game->render_card($card, $row, $col);
render_opponent_cards
Contains the logic needed to render the opponents cards to the terminal. AKA face down at the top of the screen.
$game->render_opponent_cards($num);
render_player_cards
Contains the logic needed to render the players cards to the terminal. AKA face up at the bottom of the screen.
$game->render_player_cards($cards, $row, $col, $all);
render_run_play
Contains the logic needed to render the current plays run cards. AKA the cards that have been played for the current play in the middle of the screen.
$game->render_run_play;
show_face_down_split
Utility function to render face down cards to the terminal.
$game->show_face_down_split($num, $vertical);
draw_background
Utility function to draw the basic cribbage game, this function calls draw_dealer, draw_crib, draw_starter and reset_cursor. It will render the green background, dealer, crib and starter card to the terminal.
$game->draw_background();
draw_starter
Utility function to draw the starter card to the terminal. If no starter card is set then nothing will be drawn.
$game->draw_starter();
draw_crib
Utility function to draw the crib to the terminal, depending on who is the dealer.
$game->draw_crib();
draw_go
Utitlity function to draw GO to the terminal.
$game->draw_go();
draw_dealer
Utility function to draw the text "Dealer" to the terminal, this will be against the player who is currently the dealer.
$game->draw_dealer();.
draw_scores
Utility function to draw the current scores to the terminal.
$game->draw_scores();
winner
Utility function to draw the winners screen to the terminal at the end of the game.
$game->winner();
clear_screen
Utility function to clear the terminal.
$game->clear_screen();
reset_cursor
Utility function to reset the terminal cursor position.
$game->reset_cursor();
set_cursor_vertical
Utiltiy function to set the vertical position of the terminal cursor.
$game->set_cursor_vertical($y);
set_cursor_horizontal
Utility function to set the horizontal position of the terminal cursor.
$game->set_cursor_horizontal($x);
say
Utility function to print text to the terminal.
$game->say("Hello World", $new_line, $indent, $color, $background);
print_header
Utility function to print the header to the terminal
$game->print_header("Print some header text");
print_footer
Utility function to print the footer to the terminal
$game->print_footer("Print some footer text");
THE PICKER
With a terminal and Term::ReadKey, the two choices that decide a cribbage game are made with the arrow keys instead of by typing a number: the two cards that go to the crib, and the card you play into the count.
The cursor only ever stops on a card you can play. The set it walks comes from "playable_cards", which asks "test_card" in Game::Cribbage::Play about each card in turn, so a card that would take the count past 31 is never a stop and never has to be refused after the fact.
The marks are frames, not colours
Three things need marking at once while discarding, so there are three box frames: light for an ordinary card, double for the one under the cursor, and heavy for a card already chosen for the crib. A mark that is a colour is gone the moment the board is piped into a file, and the suits are already using colour to tell red from black.
The caption is the engine's
"card_line" reads "test_card_score" in Game::Cribbage::Play and reports what it says: the count the card takes you to, whether that is a fifteen or thirty-one, the pair or run it makes and what it pegs. Nothing about the score is worked out here, because a preview that does its own arithmetic is a second implementation of the rules that can disagree with the first.
KEYS AND INPUT
in
out
Read-write handles, defaulting to STDIN and STDOUT. Everything the terminal draws goes through out and every line it reads comes from in, so a test can drive a whole game with a pair of in-memory handles.
picking
Whether the arrow keys are offered. Set it false to type numbers instead; left unset it follows "keys_available".
colour
Whether the escapes that colour the screen are written. Set it either way; left unset it is off when NO_COLOR is set to anything, off when "out" is not a terminal, and on otherwise. The cursor movement that lays the screen out is not colour and is written regardless.
keys_available
Whether a key can be read at all: a keysource, or in being a terminal with Term::ReadKey installed. Term::ReadKey is a recommendation and not a prerequisite, so this is false on a perfectly good installation and the typed prompt is what that installation gets.
enter_raw
leave_raw
The cbreak mode round the picker. Cbreak and not raw, so an interrupt is still an interrupt. leave_raw is safe to call more than once and from a signal handler; "run" calls it from INT, TERM, HUP and after a die, because a program that leaves a terminal in cbreak leaves the shell unusable.
keysource
pending
The seam a test drives the picker through, and the queue of characters read and put back. Both are given to new. keysource is a coderef returning one character per call, which is what makes the escape sequence for an arrow key testable: the reader has to ask three times for one key.
keyboard
screen
The Game::Terminal::Kit::Keys every key and line is read through and the Game::Terminal::Kit::Screen everything is drawn through. Both are made from "in", "out", "keysource" and "pending" when the terminal is built; hand new either to use your own.
raw
True between "enter_raw" and "leave_raw".
read_key
One named key: 'up', 'enter', 'escape' and so on, or the character itself, and 'unknown' for an escape sequence that names no key.
read_line
One line from "in", without the space around it, or undef at the end of input. What is typed is echoed, also after the arrow keys have been used.
emit
Whatever is handed to it, written to "out". Nothing in this module may use print or <STDIN> directly: that is what made the terminal untestable before.
paint
my $text = $t->paint(' Dealer ', '31;1;40');
The text in that colour and a reset after it, or the text as it was when "colour" is off.
CHOOSING
playable_cards
my $can = $t->playable_cards('player2'); # [ 1, 3, 4 ]
The 1-based positions in that player's hand of the cards that can legally be played into the current count, asked of the engine one card at a time. Empty means a go.
card_line
$t->card_line('player2', 3);
# '7♦️ takes the count to 15 for fifteen, pegging 2'
The caption under the cursor, read from the engine.
pick_card
Runs the picker for one card and returns its 1-based position, or 'go', 'bot' or 'quit'.
pick_discards
Runs the picker for the crib and returns an arrayref of the two 1-based positions chosen, or 'bot' or 'quit'. Enter on a card that is already chosen puts it back.
random_index
my $i = $t->random_index($count); # 0 .. $count - 1
Every draw this module makes goes through here: the bot's card at the low-card split and the bot's cut for the starter. It exists so a test can pin the draw, and a test must pin it here and not with local *CORE::GLOBAL::rand, which has to be in place before the calling code is compiled and so does nothing at all when a test file sets it after its own use line.
step
my $i = $t->step(\@items, $at, 'right');
The index the cursor lands on. Left and up go back, right, down and tab go on, and both wrap; home and end are the ends. The hand is drawn as one row, so left and up are the same key and so are right and down.
AUTHOR
LNATION, <email at lnation.org>
LICENSE AND COPYRIGHT
This software is Copyright (c) 2026 by LNATION.
This is free software, licensed under the Artistic License 2.0.