example/
example.rs

1/*
2 * To the extent possible under law, the author(s) have dedicated all
3 * copyright and neighboring rights to this software to the public domain
4 * worldwide. This software is distributed without any warranty. See
5 * <http://creativecommons.org/publicdomain/zero/1.0/> for a copy of the
6 * CC0 Public Domain Dedication.
7 *
8 * Note that the above copyright notice applies only to the code in this
9 * file: markov-generator, which this code depends on, is licensed under
10 * version 3 or later of the GNU General Public License. Thus, any version of
11 * this code that links to or is otherwise a derived work of markov-generator
12 * may be distributed only in accordance with markov-generator's license.
13 */
14
15use markov_generator::{AddEdges, HashChain};
16use std::fs::File;
17use std::io::{self, BufRead, BufReader, BufWriter, Write};
18
19fn main() -> io::Result<()> {
20    const DEPTH: usize = 6;
21    // Maps each sequence of 6 items to a list of possible next items.
22    // `HashChain` uses hash maps internally; b-trees can also be used.
23    let mut chain = HashChain::new(DEPTH);
24
25    // In this case, corpus.txt contains one paragraph per line.
26    let file = File::open("examples/corpus.txt")?;
27    let mut reader = BufReader::new(file);
28    let mut line = String::new();
29    // The previous `DEPTH` characters before `line`.
30    let mut prev = Vec::<char>::new();
31
32    while let Ok(1..) = reader.read_line(&mut line) {
33        // `Both` means that the generated random output could start with the
34        // beginning of `line` or end after the end of `line`.
35        chain.add_all(line.chars(), AddEdges::Both);
36
37        // This makes sure there's a chance that the end of the previous line
38        // could be followed by the start of the current line when generating
39        // random output.
40        chain.add_all(
41            prev.iter().copied().chain(line.chars().take(DEPTH)),
42            AddEdges::Neither,
43        );
44
45        if let Some((n, (i, _c))) =
46            line.char_indices().rev().enumerate().take(DEPTH).last()
47        {
48            // Keep only the most recent `DEPTH` characters.
49            prev.drain(0..prev.len().saturating_sub(DEPTH - n - 1));
50            prev.extend(line[i..].chars());
51        }
52        line.clear();
53    }
54
55    // Generate and print random Markov data.
56    let mut stdout = BufWriter::new(io::stdout().lock());
57    let mut prev_newline = false;
58    for &c in chain.generate() {
59        if prev_newline {
60            writeln!(stdout)?;
61        }
62        prev_newline = c == '\n';
63        write!(stdout, "{c}")?;
64    }
65    stdout.flush()
66}