1
use std::fmt;
2

            
3
use merc_symbolic::FormatConfigSet;
4

            
5
use crate::PG;
6
use crate::Player;
7
use crate::VariabilityParityGame;
8

            
9
/// Display implementation output a parity game in Graphviz DOT format.
10
pub struct PgDot<'a, G: PG> {
11
    pub game: &'a G,
12
}
13

            
14
impl<'a, G: PG> PgDot<'a, G> {
15
    /// Creates a new PgDot Display for the given parity game.
16
    pub fn new(game: &'a G) -> Self {
17
        Self { game }
18
    }
19
}
20

            
21
impl<'a, G: PG> fmt::Display for PgDot<'a, G> {
22
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
23
        write_dot_header(f)?;
24
        write_dot_style(f)?;
25

            
26
        let initial = self.game.initial_vertex();
27

            
28
        write_vertices(f, self.game)?;
29

            
30
        // Display edges
31
        for v in self.game.iter_vertices() {
32
            for to in self.game.outgoing_edges(v) {
33
                writeln!(f, "  v{} -> v{};", v, to)?;
34
            }
35
        }
36

            
37
        write_init_arrow(f, initial)?;
38

            
39
        write_footer(f)
40
    }
41
}
42

            
43
/// Display implementation output a variability parity game in Graphviz DOT format.
44
pub struct VpgDot<'a> {
45
    pub game: &'a VariabilityParityGame,
46
}
47

            
48
impl<'a> VpgDot<'a> {
49
    /// Creates a new PgDot Display for the given parity game.
50
    pub fn new(game: &'a VariabilityParityGame) -> Self {
51
        Self { game }
52
    }
53
}
54

            
55
impl<'a> fmt::Display for VpgDot<'a> {
56
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
57
        write_dot_header(f)?;
58
        write_dot_style(f)?;
59

            
60
        let initial = self.game.initial_vertex();
61

            
62
        write_vertices(f, self.game)?;
63

            
64
        // Display edges
65
        for v in self.game.iter_vertices() {
66
            for edge in self.game.outgoing_conf_edges(v) {
67
                writeln!(
68
                    f,
69
                    "  v{} -> v{} [label=\"{}\"];",
70
                    v,
71
                    edge.to(),
72
                    FormatConfigSet(edge.configuration())
73
                )?;
74
            }
75
        }
76

            
77
        write_init_arrow(f, initial)?;
78

            
79
        write_footer(f)
80
    }
81
}
82

            
83
// Shared free functions for DOT rendering
84
fn write_dot_header(f: &mut fmt::Formatter<'_>) -> fmt::Result {
85
    writeln!(f, "digraph parity_game {{")
86
}
87

            
88
fn write_dot_style(f: &mut fmt::Formatter<'_>) -> fmt::Result {
89
    writeln!(f, "  rankdir=LR;")?;
90
    writeln!(f, "  graph [fontname=\"DejaVu Sans\", splines=true];")?;
91
    writeln!(f, "  node [fontname=\"DejaVu Sans\"];")?;
92
    writeln!(
93
        f,
94
        "  edge [fontname=\"DejaVu Sans\", color=\"#444444\", arrowsize=0.9, penwidth=1.2];"
95
    )
96
}
97

            
98
fn write_init_arrow(f: &mut fmt::Formatter<'_>, initial: impl fmt::Display) -> fmt::Result {
99
    writeln!(f, "  init [shape=point, width=0.05, label=\"\"];")?;
100
    writeln!(f, "  init -> v{} [arrowsize=0.6];", initial)
101
}
102

            
103
fn write_footer(f: &mut fmt::Formatter<'_>) -> fmt::Result {
104
    writeln!(f, "}}")
105
}
106

            
107
fn write_vertices<G: PG>(f: &mut fmt::Formatter<'_>, game: &G) -> fmt::Result {
108
    for v in game.iter_vertices() {
109
        let orientation = match game.owner(v) {
110
            Player::Odd => "0",
111
            Player::Even => "45",
112
        };
113

            
114
        writeln!(
115
            f,
116
            "  v{} [label=\"{}\", shape=square, orientation={}, xlabel=< <FONT POINT-SIZE=\"9\">v{}</FONT> >];",
117
            v,
118
            game.priority(v),
119
            orientation,
120
            v
121
        )?;
122
    }
123
    Ok(())
124
}