aW1wb3J0IG1hdHBsb3RsaWIucHlwbG90IGFzIHBsdAppbXBvcnQgbmV0d29ya3ggYXMgbngKZnJvbSByZXBvcnRsYWIubGliLnBhZ2VzaXplcyBpbXBvcnQgQTQKZnJvbSByZXBvcnRsYWIucGxhdHlwdXMgaW1wb3J0IFNpbXBsZURvY1RlbXBsYXRlLCBQYXJhZ3JhcGgsIFNwYWNlciwgSW1hZ2UsIFRhYmxlLCBUYWJsZVN0eWxlCmZyb20gcmVwb3J0bGFiLmxpYiBpbXBvcnQgY29sb3JzCmZyb20gcmVwb3J0bGFiLmxpYi5zdHlsZXMgaW1wb3J0IGdldFNhbXBsZVN0eWxlU2hlZXQKCiMgUERGIOi8uOWHuui3r+W+kQpwZGZfcGF0aCA9ICZxdW90O0hhcnJ5UG90dGVyX1RpbWVUdXJuZXJfTG9naWMucGRmJnF1b3Q7CmRvYyA9IFNpbXBsZURvY1RlbXBsYXRlKHBkZl9wYXRoLCBwYWdlc2l6ZT1BNCkKc3R5bGVzID0gZ2V0U2FtcGxlU3R5bGVTaGVldCgpCnN0b3J5ID0gW10KCiMg5qiZ6aGMCnN0b3J5LmFwcGVuZChQYXJhZ3JhcGgoJnF1b3Q75ZOI5Yip5rOi54m544CK6Zi/6Iyy5Y2h54+t55qE6YCD54qv44CL5pmC5YWJ5Zmo5oKW6KuW55qE6YKP6Lyv5YiG5p6QJnF1b3Q7LCBzdHlsZXNbJnF1b3Q7VGl0bGUmcXVvdDtdKSkKc3RvcnkuYXBwZW5kKFNwYWNlcigxLCAxMikpCgojIOewoeS7i+aWh+WtlwppbnRybyA9ICZxdW90OyZxdW90OyZxdW90OwrmnKzmlofku7blsIfku6Xlm5vlpKfpgo/ovK/lvovvvIjlkIzkuIDlvovjgIHnn5vnm77lvovjgIHmjpLkuK3lvovjgIHlhYXotrPnkIbnlLHlvovvvInmqqLoppYK44CK5ZOI5Yip5rOi54m577ya6Zi/6Iyy5Y2h54+t55qE6YCD54qv44CL5Lit44CM5pmC5YWJ5Zmo44CN5oOF56+A55qE6YKP6Lyv6Yyv6Kqk77yM5Lim5pCt6YWN6KGo5qC86IiH5rWB56iL5ZyW5riF5qWa5ZGI54++55+b55u+5LmL6JmV44CCCiZxdW90OyZxdW90OyZxdW90OwpzdG9yeS5hcHBlbmQoUGFyYWdyYXBoKGludHJvLCBzdHlsZXNbJnF1b3Q7Tm9ybWFsJnF1b3Q7XSkpCnN0b3J5LmFwcGVuZChTcGFjZXIoMSwgMTIpKQoKIyDooajmoLzmlbjmk5oKZGF0YSA9IFsKICAgIFsmcXVvdDvpgo/ovK/lvosmcXVvdDssICZxdW90O+mbu+W9seS4reeahOmMr+iqpCZxdW90O10sCiAgICBbJnF1b3Q75ZCM5LiA5b6LJnF1b3Q7LCAmcXVvdDvlkIzkuIDkurrnianlh7rnj77lhanlgIvniYjmnKzvvIjlk4jliKnlkIzmmYLlrZjlnKjvvIkmcXVvdDtdLAogICAgWyZxdW90O+efm+ebvuW+iyZxdW90OywgJnF1b3Q75ZG96aGM5ZCM5pmC54K655yf6IiH5YGH77yI5pa95pS+5Y+I5pyq5pa95pS+6K235rOV5ZKS77yJJnF1b3Q7XSwKICAgIFsmcXVvdDvmjpLkuK3lvosmcXVvdDssICZxdW90O+WRvemhjOecn+WAvOaooeeziu+8iOaXouacieaWveazleWPiOeEoeaWveazle+8iSZxdW90O10sCiAgICBbJnF1b3Q75YWF6Laz55CG55Sx5b6LJnF1b3Q7LCAmcXVvdDvlm6DmnpzlvqrnkrDvvIjorbfms5XlkpLnhKHotbfmupDvvIkmcXVvdDtdCl0KCnRhYmxlID0gVGFibGUoZGF0YSwgY29sV2lkdGhzPVsxMDAsIDM0MF0pCnRhYmxlLnNldFN0eWxlKFRhYmxlU3R5bGUoWwogICAgKCZxdW90O0JBQ0tHUk9VTkQmcXVvdDssICgwLCAwKSwgKC0xLCAwKSwgY29sb3JzLmxpZ2h0Ymx1ZSksCiAgICAoJnF1b3Q7VEVYVENPTE9SJnF1b3Q7LCAoMCwgMCksICgtMSwgMCksIGNvbG9ycy5ibGFjayksCiAgICAoJnF1b3Q7QUxJR04mcXVvdDssICgwLCAwKSwgKC0xLCAtMSksICZxdW90O0NFTlRFUiZxdW90OyksCiAgICAoJnF1b3Q7Rk9OVE5BTUUmcXVvdDssICgwLCAwKSwgKC0xLCAwKSwgJnF1b3Q7SGVsdmV0aWNhLUJvbGQmcXVvdDspLAogICAgKCZxdW90O0ZPTlRTSVpFJnF1b3Q7LCAoMCwgMCksICgtMSwgLTEpLCAxMCksCiAgICAoJnF1b3Q7Qk9YJnF1b3Q7LCAoMCwgMCksICgtMSwgLTEpLCAxLCBjb2xvcnMuYmxhY2spLAogICAgKCZxdW90O0dSSUQmcXVvdDssICgwLCAwKSwgKC0xLCAtMSksIDAuNSwgY29sb3JzLmdyZXkpLApdKSkKc3RvcnkuYXBwZW5kKHRhYmxlKQpzdG9yeS5hcHBlbmQoU3BhY2VyKDEsIDI0KSkKCiMg5rWB56iL5ZyW57mq6KO9CkcgPSBueC5EaUdyYXBoKCkKbm9kZXMgPSB7CiAgICAmcXVvdDtIYXJyeTEmcXVvdDs6ICZxdW90O+WTiOWIqSjnlbbkuIspJnF1b3Q7LAogICAgJnF1b3Q7VGltZVR1cm5lciZxdW90OzogJnF1b3Q75L2/55So5pmC5YWJ5ZmoJnF1b3Q7LAogICAgJnF1b3Q7SGFycnkyJnF1b3Q7OiAmcXVvdDvlk4jliKko5Zue5Yiw6YGO5Y67KSZxdW90OywKICAgICZxdW90O1BhdHJvbnVzJnF1b3Q7OiAmcXVvdDvmlr3mlL7orbfms5XlkpImcXVvdDssCiAgICAmcXVvdDtMb29wJnF1b3Q7OiAmcXVvdDvlm6DmnpzlvqrnkrDvvJrorbfms5XlkpLnhKHotbfmupAmcXVvdDsKfQpmb3IgbiwgbGFiZWwgaW4gbm9kZXMuaXRlbXMoKToKICAgIEcuYWRkX25vZGUobiwgbGFiZWw9bGFiZWwpCgplZGdlcyA9IFsKICAgICgmcXVvdDtIYXJyeTEmcXVvdDssICZxdW90O1RpbWVUdXJuZXImcXVvdDspLAogICAgKCZxdW90O1RpbWVUdXJuZXImcXVvdDssICZxdW90O0hhcnJ5MiZxdW90OyksCiAgICAoJnF1b3Q7SGFycnkyJnF1b3Q7LCAmcXVvdDtQYXRyb251cyZxdW90OyksCiAgICAoJnF1b3Q7UGF0cm9udXMmcXVvdDssICZxdW90O0hhcnJ5MSZxdW90OyksCiAgICAoJnF1b3Q7UGF0cm9udXMmcXVvdDssICZxdW90O0xvb3AmcXVvdDspCl0KRy5hZGRfZWRnZXNfZnJvbShlZGdlcykKCiMg5qiZ6Ki75Zub5aSn6YKP6Lyv5b6LCmFubm90YXRpb25zID0gewogICAgKCZxdW90O0hhcnJ5MSZxdW90OywgJnF1b3Q7VGltZVR1cm5lciZxdW90Oyk6ICZxdW90O+WQjOS4gOW+i1xuKOWTiOWIqeS7jeaYr+WQjOS4gOS6uj8pJnF1b3Q7LAogICAgKCZxdW90O0hhcnJ5MiZxdW90OywgJnF1b3Q7UGF0cm9udXMmcXVvdDspOiAmcXVvdDvnn5vnm77lvotcbijlt7Lmlr3mlL4v5pyq5pa95pS+KSZxdW90OywKICAgICgmcXVvdDtQYXRyb251cyZxdW90OywgJnF1b3Q7SGFycnkxJnF1b3Q7KTogJnF1b3Q75o6S5Lit5b6LXG4o55yf5oiW5YGH5LiN5piO56K6KSZxdW90OywKICAgICgmcXVvdDtQYXRyb251cyZxdW90OywgJnF1b3Q7TG9vcCZxdW90Oyk6ICZxdW90O+WFhei2s+eQhueUseW+i1xuKOWboOaenOW+queSsOe8uuS5j+WOn+WboCkmcXVvdDsKfQoKcGx0LmZpZ3VyZShmaWdzaXplPSg2LCA1KSkKcG9zID0gbnguc3ByaW5nX2xheW91dChHLCBzZWVkPTQyKQpueC5kcmF3X25ldHdvcmt4X25vZGVzKEcsIHBvcywgbm9kZV9zaXplPTI4MDAsIG5vZGVfY29sb3I9JnF1b3Q7bGlnaHR5ZWxsb3cmcXVvdDssIGVkZ2Vjb2xvcnM9JnF1b3Q7YmxhY2smcXVvdDspCm54LmRyYXdfbmV0d29ya3hfbGFiZWxzKEcsIHBvcywgbGFiZWxzPW54LmdldF9ub2RlX2F0dHJpYnV0ZXMoRywgJnF1b3Q7bGFiZWwmcXVvdDspLCBmb250X3NpemU9OCkKbnguZHJhd19uZXR3b3JreF9lZGdlcyhHLCBwb3MsIGFycm93c3R5bGU9JnF1b3Q7LSZndDsmcXVvdDssIGFycm93c2l6ZT0xNSkKCmZvciBlZGdlLCB0ZXh0IGluIGFubm90YXRpb25zLml0ZW1zKCk6CiAgICB4MCwgeTAgPSBwb3NbZWRnZVswXV0KICAgIHgxLCB5MSA9IHBvc1tlZGdlWzFdXQogICAgeG0sIHltID0gKHgwICsgeDEpIC8gMiwgKHkwICsgeTEpIC8gMgogICAgcGx0LnRleHQoeG0sIHltLCB0ZXh0LCBmb250c2l6ZT02LCBjb2xvcj0mcXVvdDtkYXJrcmVkJnF1b3Q7LCBoYT0mcXVvdDtjZW50ZXImcXVvdDssIHZhPSZxdW90O2NlbnRlciZxdW90OywKICAgICAgICAgICAgIGJib3g9ZGljdChib3hzdHlsZT0mcXVvdDtyb3VuZCxwYWQ9MC4yJnF1b3Q7LCBmYWNlY29sb3I9JnF1b3Q7bWlzdHlyb3NlJnF1b3Q7LCBlZGdlY29sb3I9JnF1b3Q7cmVkJnF1b3Q7LCBhbHBoYT0wLjYpKQoKcGx0LmF4aXMoJnF1b3Q7b2ZmJnF1b3Q7KQpmbG93Y2hhcnRfcGF0aCA9ICZxdW90O2Zsb3djaGFydC5wbmcmcXVvdDsKcGx0LnNhdmVmaWcoZmxvd2NoYXJ0X3BhdGgsIGJib3hfaW5jaGVzPSZxdW90O3RpZ2h0JnF1b3Q7LCBkcGk9MTUwKQpwbHQuY2xvc2UoKQoKIyDmj5LlhaXmtYHnqIvlnJbliLAgUERGCnN0b3J5LmFwcGVuZChQYXJhZ3JhcGgoJnF1b3Q75pmC5YWJ5Zmo5oKW6KuW5rWB56iL5ZyW77yI5ZCr5Zub5aSn6YKP6Lyv5b6L5qiZ6Ki777yJJnF1b3Q7LCBzdHlsZXNbJnF1b3Q7SGVhZGluZzImcXVvdDtdKSkKc3RvcnkuYXBwZW5kKEltYWdlKGZsb3djaGFydF9wYXRoLCB3aWR0aD00MDAsIGhlaWdodD0zMDApKQpzdG9yeS5hcHBlbmQoU3BhY2VyKDEsIDEyKSkKCiMg6Ly45Ye6IFBERgpkb2MuYnVpbGQoc3RvcnkpCnByaW50KGYmcXVvdDvlt7LovLjlh7ogUERGIOaqlOahiO+8mntwZGZfcGF0aH0mcXVvdDsp
import matplotlib.pyplot as plt
import networkx as nx
from reportlab.lib.pagesizes import A4
from reportlab.platypus import SimpleDocTemplate, Paragraph, Spacer, Image, Table, TableStyle
from reportlab.lib import colors
from reportlab.lib.styles import getSampleStyleSheet
# PDF 輸出路徑
pdf_path = "HarryPotter_TimeTurner_Logic.pdf"
doc = SimpleDocTemplate(pdf_path, pagesize=A4)
styles = getSampleStyleSheet()
story = []
# 標題
story.append(Paragraph("哈利波特《阿茲卡班的逃犯》時光器悖論的邏輯分析", styles["Title"]))
story.append(Spacer(1, 12))
# 簡介文字
intro = """
本文件將以四大邏輯律(同一律、矛盾律、排中律、充足理由律)檢視
《哈利波特:阿茲卡班的逃犯》中「時光器」情節的邏輯錯誤,並搭配表格與流程圖清楚呈現矛盾之處。
"""
story.append(Paragraph(intro, styles["Normal"]))
story.append(Spacer(1, 12))
# 表格數據
data = [
["邏輯律", "電影中的錯誤"],
["同一律", "同一人物出現兩個版本(哈利同時存在)"],
["矛盾律", "命題同時為真與假(施放又未施放護法咒)"],
["排中律", "命題真值模糊(既有施法又無施法)"],
["充足理由律", "因果循環(護法咒無起源)"]
]
table = Table(data, colWidths=[100, 340])
table.setStyle(TableStyle([
("BACKGROUND", (0, 0), (-1, 0), colors.lightblue),
("TEXTCOLOR", (0, 0), (-1, 0), colors.black),
("ALIGN", (0, 0), (-1, -1), "CENTER"),
("FONTNAME", (0, 0), (-1, 0), "Helvetica-Bold"),
("FONTSIZE", (0, 0), (-1, -1), 10),
("BOX", (0, 0), (-1, -1), 1, colors.black),
("GRID", (0, 0), (-1, -1), 0.5, colors.grey),
]))
story.append(table)
story.append(Spacer(1, 24))
# 流程圖繪製
G = nx.DiGraph()
nodes = {
"Harry1": "哈利(當下)",
"TimeTurner": "使用時光器",
"Harry2": "哈利(回到過去)",
"Patronus": "施放護法咒",
"Loop": "因果循環:護法咒無起源"
}
for n, label in nodes.items():
G.add_node(n, label=label)
edges = [
("Harry1", "TimeTurner"),
("TimeTurner", "Harry2"),
("Harry2", "Patronus"),
("Patronus", "Harry1"),
("Patronus", "Loop")
]
G.add_edges_from(edges)
# 標註四大邏輯律
annotations = {
("Harry1", "TimeTurner"): "同一律\n(哈利仍是同一人?)",
("Harry2", "Patronus"): "矛盾律\n(已施放/未施放)",
("Patronus", "Harry1"): "排中律\n(真或假不明確)",
("Patronus", "Loop"): "充足理由律\n(因果循環缺乏原因)"
}
plt.figure(figsize=(6, 5))
pos = nx.spring_layout(G, seed=42)
nx.draw_networkx_nodes(G, pos, node_size=2800, node_color="lightyellow", edgecolors="black")
nx.draw_networkx_labels(G, pos, labels=nx.get_node_attributes(G, "label"), font_size=8)
nx.draw_networkx_edges(G, pos, arrowstyle="->", arrowsize=15)
for edge, text in annotations.items():
x0, y0 = pos[edge[0]]
x1, y1 = pos[edge[1]]
xm, ym = (x0 + x1) / 2, (y0 + y1) / 2
plt.text(xm, ym, text, fontsize=6, color="darkred", ha="center", va="center",
bbox=dict(boxstyle="round,pad=0.2", facecolor="mistyrose", edgecolor="red", alpha=0.6))
plt.axis("off")
flowchart_path = "flowchart.png"
plt.savefig(flowchart_path, bbox_inches="tight", dpi=150)
plt.close()
# 插入流程圖到 PDF
story.append(Paragraph("時光器悖論流程圖(含四大邏輯律標註)", styles["Heading2"]))
story.append(Image(flowchart_path, width=400, height=300))
story.append(Spacer(1, 12))
# 輸出 PDF
doc.build(story)
print(f"已輸出 PDF 檔案:{pdf_path}")