"""任务 3 · 括号匹配：先写判定，再交出第一个出错的位置

题目：给一段只由 ()[]{} 组成的文本，判断里面的括号是否配对正确。空文本算正确。

读到一个右括号时，能跟它配对的只有**最近一个还没有配对的左括号**——这就是栈：
遇到左括号入栈，遇到右括号就检查栈顶是不是同一种左括号。

两个函数都要写：

    is_valid(s)      配对正确交回 True，否则 False；
    first_error(s)   正确交回 -1，否则交回**第一个出错的位置**（下标，从 0 起）。

第二个函数是这一课要练的「栈顶到底是什么」：出错有三种情形，各自要与不要弹出栈顶
都不一样。先写顺 is_valid，first_error 只是在它的每一处提前 return 上换一个数字。

三种出错情形（下表是给好的思路，代码自己写）：
    情形            读到的东西        栈的状态           该交出哪个下标
    右括号多余      ')' 之类          栈是空的           就是这个右括号的下标
    左右不配对      ')' 之类          栈顶是另一种左括号   就是这个右括号的下标
    左括号没等到   没有东西可读       栈里还留着东西      栈**最底下**那个左括号的下标

第三种最容易被漏：'(((' 报的位置应当是 0（最底下那个 '('），不是 2。

接口：函数名、造数据那几行、带 print 的行都是判分接口，别改；
要写的是标着 TODO 的两段。

跑： py task3_brackets.py
判： py run_tests.py
"""

from tools import show_count


# ══ TODO 1 ═════════════════════════════════════════════════
# 写 is_valid(s)：配对正确交回 True，否则 False。
#
# 要点：
#   pair = {')': '(', ']': '[', '}': '{'}      右括号 -> 它对应的左括号（给好的）
#   st = []                                    栈里只放**左括号**
#   从左往右读每一个字符 ch：
#       ch 是 '(' '[' '{' 之一  -> 入栈
#       ch 是右括号             -> 先看栈是不是空的：
#                                  空        -> 直接 return False（右括号多余）
#                                  栈顶对不上 -> 直接 return False（不配对）
#                                  对得上     -> 弹出栈顶
#   读完整个文本之后：栈空才算正确，所以最后 return not st
#   （文本是空串时 st 也是空的，not st 为真，空文本自动算正确。）
def is_valid(s):
    pair = {')': '(', ']': '[', '}': '{'}       # 别改：配对表
    return False


# ══ TODO 2 ═════════════════════════════════════════════════
# 写 first_error(s)：配对正确交回 -1，否则交回第一个出错位置的下标。
#
# 要点（照上面那张表写）：
#   · 读到右括号、而栈是空的          -> return 这个右括号的下标
#   · 读到右括号、而栈顶不是对应的左括号 -> return 这个右括号的下标
#   · 读完之后栈里还有东西（左括号没等到）-> return 栈里**最底下**那个左括号的下标
#
# 第三种的取法：栈是自底向顶存的，最底下那一项是 st[0]（下标 0 那一格）。
# 常见错法：写成 st[-1]（那是**最后**一个左括号的下标，'(((' 会报成 2）。
# 循环里用到下标时，写法是 for i in range(len(s)): 再取 s[i]。
def first_error(s):
    return -1


if __name__ == '__main__':                     # 别改：这层守卫让判分 import 它时不出声
    cases = ['()[]{}', '([)]', '(]', '((', '()', '', '([{}])', ')))', '(()']   # 别改

    for s in cases:                            # 别改
        print('用例', repr(s), is_valid(s), first_error(s))     # 别改：repr 让空串也看得见

    valid_count = 0                            # 别改
    for s in cases:                            # 别改
        if is_valid(s):
            valid_count += 1
    print('一组用例里配对正确的个数', valid_count)                  # 别改：期望 4
    print('校验 前六个用例逐字对照', [is_valid(s) for s in cases[:6]] == [True, False, False, False, True, True])   # 别改：期望 True
    print('校验 后三个用例逐字对照', [first_error(s) for s in cases[6:]] == [-1, 0, 0])                          # 别改：期望 True
    show_count(1, '配对正确个数', valid_count)                    # 别改
    show_count(2, '(() 的首个错位', first_error('(()'))           # 别改：期望 0
    show_count(3, '(]  的首个错位', first_error('(]'))            # 别改：期望 1
