我想要在 LaTeX 中排版 MinMax 决策树,就像下图这样:
我进行了一些尝试并实现了部分目标:
\documentclass{article}
\usepackage{tikz,tikz-qtree}
\usetikzlibrary{backgrounds}
\newcommand{\ply}[3][black]{\footnotesize{#2 ({\color{#1}#3})}}
\newcommand{\player}[1]{\footnotesize \emph #1}
\begin{document}
\begin{tikzpicture}[framed]
\Tree [.{} \edge[opacity=0]; [.\player{MAX:} \edge[opacity=0];
[.\player{MIN:} \edge[opacity=0];
[.\player{MAX:} \edge[opacity=0];
[.\player{MIN:} ]]]]
\edge[opacity=0];
[.\ply[red]{4}{+1}
\edge node[auto=right]{-1};
[. \ply[red]{3}{-1}
\edge node[auto=right]{-1};
[. \ply[red]{2}{+1}
\edge node[auto=right]{-1}; [.\ply{1}{+1} ] ]
\edge node[auto=left]{-2}; \ply{1}{-1} ]
\edge node[auto=right]{-2}; \ply[red]{2}{-1}
\edge node[auto=left]{-3}; \ply{1}{+1}
]]
\end{tikzpicture}
\end{document}
我还需要实现一些功能:
- 减少图片顶部的边距(删除不可见的根节点)
- 使边缘标签尺寸更小,最好是 \scriptsize
- 从图纸中添加红色向上箭头
- 如果可能的话,让 MIN / MAX 标签右对齐
我对 tikz 的了解不足以做这些事情,所以如果有人能帮助我,我将非常感激!
答案1
你感觉自己有多勇敢?
以下解决方案使用基于的实验包forest
。似乎没人愿意测试prooftrees
,所以我想我也尝试justtrees
一下。
首先,结果:
接下来是代码:
\documentclass[tikz,border=5pt,multi]{standalone}
\usepackage{justtrees}
\usepackage{cfr-lm}% for italic small-caps
\newcommand{\ply}[3][black]{\footnotesize{#2 ({\color{#1}#3})}}
\newcommand{\player}[1]{\footnotesize \emph #1}
\begin{document}
\begin{forest}
just tree,
just format/.style={font=\sishape},% italic small-caps
for tree={
font=\tlstyle,% for tabular, lining figures with cfr-lm
alias/.wrap 2 pgfmath args={#1-#2}{int(subtract(level(),1))}{n()}% labels the nodes systematically so we can refer to them later
},
my edge label/.style n args=2{% save typing when creating the edge labels
edge label={node [midway, font=\scriptsize\tlstyle, #1] {#2}}
},
[, phantom
[{\ply[red]{4}{+1}}, left just={Max:}
[{\ply[red]{3}{-1}}, left just={Min:}, my edge label={left}{-1}
[{\ply[red]{2}{+1}}, left just={Max:}, my edge label={left}{-1}
[{\ply{1}{+1}}, left just={Min:}, my edge label={left}{-1}
]
]
[{\ply{1}{-1}}, my edge label={left}{-2}]
]
[{\ply[red]{2}{-1}}, calign with current, my edge label={left, pos=.75}{-2}]
[{\ply{1}{+1}}, my edge label={right}{-3}]
]
]
\tikzset{->}
\draw [red] (1-3.north) [bend right] to (0-1.east);
\draw [red] ([xshift=2.5pt]3-1.north) [bend right] to ([xshift=2.5pt]2-1.south);
\draw [red] (2-2.north) [bend right] to (1-1.east);
\end{forest}
\end{document}
最后,打包(保存justtrees.sty
在与文档相同的目录中):
\NeedsTeXFormat{LaTeX2e}
\ProvidesPackage{justtrees}[2015/05/30 v0.01 justtrees]
\RequirePackage{forest}
\newcounter{justtree@countlevels}% count the levels in the just tree
\setcounter{justtree@countlevels}{0}
\newcount\justtree@lcount% count the left justifiers (on the left)
\newcount\justtree@rcount% count the right justifiers (on the right)
\forestset{
just format/.style={font=\normalfont\normalsize},
declare boolean={left justifiers}{0},% left justifications
declare boolean={right justifiers}{0},% right justifications
right justifier/.style={% creates the right justifiers on the right but does not yet specify any content
anchor=base west,
no edge,
before typesetting nodes={% page 51
TeX={\advance\justtree@rcount1},
name/.expanded={right just \the\justtree@rcount},% name them so they can be moved
if={\the\justtree@rcount>2}{% correct the location as for the left justifiers
for previous={
append/.expanded={right just \the\justtree@rcount}
},
}{},
},
},
left justifier/.style={% creates the left justifiers on the left but does not yet specify any content
anchor=base east,
no edge,
before typesetting nodes={% page 51
TeX={\advance\justtree@lcount1},
name/.expanded={left just \the\justtree@lcount},% name them so they can be moved
if={\the\justtree@lcount>2}{% correct the location as for the left justifiers
for previous={
append/.expanded={left just \the\justtree@lcount}
},
}{},
},
},
left justifications/.style={
for tree={left justifiers},
},
no left justifications/.style={
for tree={not left justifiers},
},
right justifications/.style={
for tree={right justifiers},
},
no right justifications/.style={
for tree={not right justifiers},
},
just tree/.style={
for tree={
parent anchor=south,
delay={
where content={}{
shape=coordinate,
}{}
},
},
where level=0{
for children={
no edge,
},
delay={
if={(\forestove{left justifiers}==1) || (\forestove{right justifiers}==1)}{% count the levels if necessary
for descendants={
if={level()>\value{justtree@countlevels}}{
TeX={
\stepcounter{justtree@countlevels}
},
}{},
},
}{},
if={(\forestove{left justifiers}==1)}{% create the left justifiers if appropriate
prepend={
[,
fit=rectangle,
just format,
left justifier,
repeat={\value{justtree@countlevels}-1}{% most are created in the wrong place but they are moved later
delay n={\the\justtree@lcount}{
append={[, left justifier, just format]}
},
}
]
},
}{},
if={(\forestove{right justifiers}==1}{% create the nodes which will hold the right justifiers, if required
append={
[,
fit=rectangle,
right justifier,
just format,
repeat={\value{justtree@countlevels}-1}{% most are created in the wrong place but right justifier moves them later
delay n={\the\justtree@rcount}{
append={[, right justifier, just format]}
},
}
]
}
}{},
},
}{},
before packing={
for tree={
tier/.wrap pgfmath arg={tier ##1}{level()},
},
},
},
right just/.style={
if={\forestove{right justifiers}==0}{
for root={
right justifiers,
},
}{},
before packing={% puts the content of the right justifiers into the empty right justifier nodes on the right; because this is done late, the nodes need to be typeset again
for={name/.wrap pgfmath arg={right just ##1}{level()}}{
content={#1},
typeset node
},
}
},
left just/.style={
if={\forestove{left justifiers}==0}{
for root={
left justifiers,
},
}{},
before packing={% puts the content of the left justifiers into the empty left justifier nodes on the left; because this is done late, the nodes need to be typeset again
for={name/.wrap pgfmath arg={left just ##1}{level()}}{
content={#1},
typeset node
},
}
},
}
\endinput
%% end justtrees.sty
我本来想匿名发布此文,但这对于实验性代码来说似乎不公平,所以我又违反了我的规则。唉。