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}