Aleph-w 3.0
A C++ Library for Data Structures and Algorithms
Loading...
Searching...
No Matches
ca-ascii.H
Go to the documentation of this file.
1/*
2 Aleph_w
3
4 Data structures & Algorithms
5 version 2.0.0b
6 https://github.com/lrleon/Aleph-w
7
8 This file is part of Aleph-w library
9
10 Copyright (c) 2002-2026 Leandro Rabindranath Leon
11
12 Permission is hereby granted, free of charge, to any person obtaining a copy
13 of this software and associated documentation files (the "Software"), to deal
14 in the Software without restriction, including without limitation the rights
15 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
16 copies of the Software, and to permit persons to whom the Software is
17 furnished to do so, subject to the following conditions:
18
19 The above copyright notice and this permission notice shall be included in all
20 copies or substantial portions of the Software.
21
22 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
23 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
24 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
25 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
26 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
27 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
28 SOFTWARE.
29*/
30
43#ifndef CA_ASCII_H
44#define CA_ASCII_H
45
46#include <concepts>
47#include <cstddef>
48#include <ostream>
49#include <sstream>
50#include <string>
51#include <utility>
52
53#include <ah-errors.H>
54
55#include <ca-io.H>
56#include <tpl_ca_concepts.H>
57
58namespace Aleph {
59namespace CA {
60
67{
68 bool include_border = false;
70 std::string line_prefix;
71};
72
80template <typename State>
82{
83 State dead{};
84 std::string dead_glyph = ".";
85 std::string alive_glyph = "#";
86
91 [[nodiscard]] std::string operator()(const State &value) const
92 {
93 return value == dead ? dead_glyph : alive_glyph;
94 }
95
104 {
105 return dead_glyph.size() > alive_glyph.size() ? dead_glyph.size() : alive_glyph.size();
106 }
107};
108
117template <typename State>
119{
120 State dead{};
121 RGB8 dead_colour{20, 24, 28};
122 RGB8 alive_colour{230, 245, 255};
123 std::string glyph = " ";
124
129 [[nodiscard]] std::string operator()(const State &value) const
130 {
131 const RGB8 c = value == dead ? dead_colour : alive_colour;
132 std::ostringstream out;
133 out << "\033[48;2;" << static_cast<unsigned>(c.r) << ';' << static_cast<unsigned>(c.g) << ';'
134 << static_cast<unsigned>(c.b) << 'm' << glyph << "\033[0m";
135 return out.str();
136 }
137
146 {
147 return glyph.size();
148 }
149};
150
167template <typename Lattice, typename Palette>
168inline void render_ascii(std::ostream &out,
169 const Lattice &frame,
171 const Ascii_Render_Options &opts = {})
172 requires requires(Palette &&p, const typename Lattice::state_type &v) {
173 { p(v) } -> std::convertible_to<std::string>;
174 }
175{
176 static_assert(LatticeLike<Lattice>, "render_ascii requires a LatticeLike frame");
177 static_assert(Lattice::rank == 2, "render_ascii requires a rank-2 frame");
178 using coord_t = typename Lattice::coord_type;
179
180 // Visible width of one rendered cell, in terminal columns. Palettes
181 // may opt in by exposing a `glyph_width()` method (e.g.
182 // `Binary_ANSI24_Palette` whose two-space glyph occupies 2 columns).
183 // Default to 1 for legacy palettes.
184 std::size_t glyph_w = 1;
185 if constexpr (requires { palette.glyph_width(); })
186 glyph_w = palette.glyph_width();
187 if (glyph_w == 0)
188 glyph_w = 1;
189
190 auto write_border = [&](const bool emit_newline)
191 {
192 out << opts.line_prefix << '+';
193 const ca_size_t dashes = frame.size(1) * static_cast<ca_size_t>(glyph_w);
194 for (ca_size_t c = 0; c < dashes; ++c)
195 out << '-';
196 out << '+';
197 if (emit_newline)
198 out << '\n';
199 };
200
201 if (opts.include_border)
202 write_border(true);
203
204 for (ca_size_t r = 0; r < frame.size(0); ++r)
205 {
206 out << opts.line_prefix;
207 if (opts.include_border)
208 out << '|';
209 for (ca_size_t c = 0; c < frame.size(1); ++c)
210 out << palette(frame.at(coord_t{static_cast<ca_index_t>(r), static_cast<ca_index_t>(c)}));
211 if (opts.include_border)
212 out << '|';
213 // Always terminate intermediate rows; the trailing newline of
214 // the last row is governed by `include_trailing_newline`.
215 // When a bottom border follows, the row separator is required
216 // to keep the border on its own line.
217 if (r + 1 < frame.size(0) or opts.include_border or opts.include_trailing_newline)
218 out << '\n';
219 }
220
221 if (opts.include_border)
222 write_border(opts.include_trailing_newline);
223
224 ah_runtime_error_if(not out) << "render_ascii: output stream failed";
225}
226
236template <typename Lattice, typename Palette>
237[[nodiscard]] inline std::string render_ascii_string(const Lattice &frame,
239 const Ascii_Render_Options &opts = {})
240 requires requires(Palette &&p, const typename Lattice::state_type &v) {
241 { p(v) } -> std::convertible_to<std::string>;
242 }
243{
244 std::ostringstream out;
245 render_ascii(out, frame, std::forward<Palette>(palette), opts);
246 return out.str();
247}
248
256template <typename Lattice>
257inline void render_ascii(std::ostream &out, const Lattice &frame, const Ascii_Render_Options &opts = {})
258{
260}
261
269template <typename Lattice>
270[[nodiscard]] inline std::string render_ascii_string(const Lattice &frame,
271 const Ascii_Render_Options &opts = {})
272{
273 std::ostringstream out;
274 render_ascii(out, frame, opts);
275 return out.str();
276}
277
285template <typename Palette>
287{
288 std::ostream *out_ = nullptr;
292
293public:
300 Ascii_Frame_Sink(std::ostream &out,
303 const bool include_step_header = true)
304 : out_(&out), palette_(std::move(palette)), opts_(std::move(opts)),
306 {}
307
313 template <typename Lattice>
314 void accept(const std::size_t step, const Lattice &frame)
315 {
317 *out_ << "# step " << step << '\n';
318 render_ascii(*out_, frame, palette_, opts_);
319 }
320
322 void flush()
323 {
324 out_->flush();
325 ah_runtime_error_if(not *out_) << "Ascii_Frame_Sink::flush: output stream failed";
326 }
327};
328
329template <typename Palette>
330Ascii_Frame_Sink(std::ostream &, Palette, Ascii_Render_Options = {}, bool = true)
332
333} // namespace CA
334} // namespace Aleph
335
336#endif // CA_ASCII_H
Exception handling system with formatted messages for Aleph-w.
#define ah_runtime_error_if(C)
Throws std::runtime_error if condition holds.
Definition ah-errors.H:271
size_t size_t int32_t value
Definition ca-c-api.h:116
size_t size_t int32_t * out
Definition ca-c-api.h:120
File-format readers and writers for cellular-automata frames.
Stream sink that writes textual frames to an output stream.
Definition ca-ascii.H:287
Ascii_Frame_Sink(std::ostream &out, Palette palette, Ascii_Render_Options opts={}, const bool include_step_header=true)
Build a stream-backed ASCII sink.
Definition ca-ascii.H:300
Ascii_Render_Options opts_
Definition ca-ascii.H:290
void accept(const std::size_t step, const Lattice &frame)
Write one textual frame.
Definition ca-ascii.H:314
void flush()
Flush the wrapped stream.
Definition ca-ascii.H:322
Lattice that adds boundary-aware access on top of a storage.
typename Storage::state_type state_type
typename Storage::coord_type coord_type
static constexpr std::size_t rank
ca_size_t size() const noexcept
state_type at(const coord_type &c) const
Strict access: throws if c is out of range.
size_t blossom_maximum_cardinality_matching(const GT &g, DynDlist< typename GT::Arc * > &matching, SA sa=SA())
Alias of compute_maximum_cardinality_general_matching().
Definition Blossom.H:466
void render_ascii(std::ostream &out, const Lattice &frame, Palette &&palette, const Ascii_Render_Options &opts={})
Render a rank-2 frame as text.
Definition ca-ascii.H:168
std::string render_ascii_string(const Lattice &frame, Palette &&palette, const Ascii_Render_Options &opts={})
Return the text rendering of a rank-2 frame.
Definition ca-ascii.H:237
std::size_t ca_size_t
Unsigned size component used for extents and counts.
Definition ca-traits.H:63
Main namespace for Aleph-w library functions.
Definition ah-arena.H:89
STL namespace.
Options for textual CA rendering.
Definition ca-ascii.H:67
bool include_border
draw a simple +---+ border
Definition ca-ascii.H:68
std::string line_prefix
text prepended to every row
Definition ca-ascii.H:70
bool include_trailing_newline
append newline after the last row
Definition ca-ascii.H:69
ANSI 24-bit colour palette for binary frames.
Definition ca-ascii.H:119
State dead
state considered dead
Definition ca-ascii.H:120
RGB8 alive_colour
background colour for live cells
Definition ca-ascii.H:122
std::string glyph
glyph painted with the background
Definition ca-ascii.H:123
std::string operator()(const State &value) const
Map a cell state to an ANSI-coloured glyph.
Definition ca-ascii.H:129
std::size_t glyph_width() const noexcept
Visible width of a single rendered cell, in columns.
Definition ca-ascii.H:145
RGB8 dead_colour
background colour for dead cells
Definition ca-ascii.H:121
Default binary text palette.
Definition ca-ascii.H:82
std::string operator()(const State &value) const
Map a cell state to display text.
Definition ca-ascii.H:91
std::size_t glyph_width() const noexcept
Visible width of a single rendered cell, in columns.
Definition ca-ascii.H:103
std::string dead_glyph
glyph for dead cells
Definition ca-ascii.H:84
State dead
state considered dead
Definition ca-ascii.H:83
std::string alive_glyph
glyph for live cells
Definition ca-ascii.H:85
RGB byte triplet used by PPM exporters.
Definition ca-io.H:85
std::uint8_t g
green channel
Definition ca-io.H:87
std::uint8_t b
blue channel
Definition ca-io.H:88
std::uint8_t r
red channel
Definition ca-io.H:86
gsl_rng * r
C++20 concepts for the Cellular Automata module.