;================================================================
; mahjong/mahjong_hand 麻将游戏 手牌算法相关
; handle_tatsu_and_toitsu.erb 处理搭子和对子
;================================================================


;;;获取每一个可能的搭子和对子
;;;- str count_map_str 手牌数量映射数组
;;;@return 可能的搭子和对子数组(字符串形式)
@mj_get_every_tatsu_and_toitsu(count_map_str)
#FUNCTIONS
    #DIMS count_map_str
    #DIM DYNAMIC count_map, 34
    #DIM DYNAMIC i
    #DIM DYNAMIC j
    #DIM DYNAMIC index
    #DIMS DYNAMIC tatsu_and_toitsu_list_str
    FOR i, 0, VARSIZE("count_map")
        count_map:i = TOINT(SUBSTRINGU(count_map_str, i, 1))
    NEXT
    FOR i, 0, 3
        FOR j, 0, 7  ; 数字牌的 1 ~ 7 存在 101
            index = i * 9 + j
            SIF count_map:index > 0 && count_map:(index + 2) > 0
                tatsu_and_toitsu_list_str += (tatsu_and_toitsu_list_str == "" ? "" # ",") + "a" + TOSTR(index, "D2")
        NEXT
    NEXT
    FOR i, 0, 3
        FOR j, 0, 8  ; 数字牌的 1 ~ 8 存在 11
            index = i * 9 + j
            SIF count_map:index > 0 && count_map:(index + 1) > 0
                tatsu_and_toitsu_list_str += (tatsu_and_toitsu_list_str == "" ? "" # ",") + "b" + TOSTR(index, "D2")
        NEXT
    NEXT
    FOR index, 0, VARSIZE("count_map")  ; 所有麻将牌都可能存在对子
        SIF count_map:index >= 2
            tatsu_and_toitsu_list_str += (tatsu_and_toitsu_list_str == "" ? "" # ",") + "c" + TOSTR(index, "D2")
    NEXT
    RETURNF tatsu_and_toitsu_list_str


;;;取出指定的一组A类搭子(101)
;;;- (ref)str count_map_str 手牌数量映射数组
;;;- int tatsu_index 指定的搭子下标
;;;@return 1成功 0失败
@mj_remove_tatsu_a(count_map_str, tatsu_index)
#FUNCTION
    #DIMS REF count_map_str
    #DIM tatsu_index
    #DIM DYNAMIC count_map, 34
    #DIM DYNAMIC i
    FOR i, 0, VARSIZE("count_map")
        count_map:i = TOINT(SUBSTRINGU(count_map_str, i, 1))
    NEXT
    IF count_map:tatsu_index > 0 && count_map:(tatsu_index + 2) > 0
        count_map:tatsu_index -= 1
        count_map:(tatsu_index + 2) -= 1
        count_map_str '= STRJOIN(count_map, "")
        RETURNF 1
    ENDIF
    RETURNF 0


;;;取出指定的一组B类搭子(11)
;;;- (ref)str count_map_str 手牌数量映射数组
;;;- int tatsu_index 指定的搭子下标
;;;@return 1成功 0失败
@mj_remove_tatsu_b(count_map_str, tatsu_index)
#FUNCTION
    #DIMS REF count_map_str
    #DIM tatsu_index
    #DIM DYNAMIC count_map, 34
    #DIM DYNAMIC i
    FOR i, 0, VARSIZE("count_map")
        count_map:i = TOINT(SUBSTRINGU(count_map_str, i, 1))
    NEXT
    IF count_map:tatsu_index > 0 && count_map:(tatsu_index + 1) > 0
        count_map:tatsu_index -= 1
        count_map:(tatsu_index + 1) -= 1
        count_map_str '= STRJOIN(count_map, "")
        RETURNF 1
    ENDIF
    RETURNF 0


;;;取出指定的一组对子(2)
;;;- (ref)str count_map_str 手牌数量映射数组
;;;- int toitsu_index 指定的对子下标
;;;@return 1成功 0失败
@mj_remove_toitsu(count_map_str, toitsu_index)
#FUNCTION
    #DIMS REF count_map_str
    #DIM toitsu_index
    #DIM DYNAMIC tile_count
    tile_count = TOINT(SUBSTRINGU(count_map_str, toitsu_index, 1))
    SIF tile_count < 2
        RETURNF 0
    count_map_str '= SUBSTRINGU(count_map_str, 0, toitsu_index) + TOSTR(tile_count - 2) + SUBSTRINGU(count_map_str, toitsu_index + 1)
    RETURNF 1


;;;取出指定的搭子和对子组合
;;;- (ref)str count_map_str 手牌数量映射数组
;;;- str tatsu_and_toitsu_list_str 指定的搭子和对子组合列表
;;;@return 1成功 0失败
@mj_remove_tatsu_and_toitsu(count_map_str, tatsu_and_toitsu_list_str)
#FUNCTIONS
    #DIMS count_map_str
    #DIMS tatsu_and_toitsu_list_str
    #DIM DYNAMIC count_map, 34
    #DIM DYNAMIC i
    #DIM DYNAMIC index
    FOR index, 0, VARSIZE("count_map")
        count_map:index = TOINT(SUBSTRINGU(count_map_str, index, 1))
    NEXT
    FOR i, 0, STRLENSU(tatsu_and_toitsu_list_str) / 3
        index = TOINT(SUBSTRINGU(tatsu_and_toitsu_list_str, i * 3 + 1, 2))
        SELECTCASE SUBSTRINGU(tatsu_and_toitsu_list_str, i * 3, 1)
            CASE "a"
                SIF MIN(count_map:index, count_map:(index + 2)) < 1
                    THROW 取出搭子 %SUBSTRINGU(tatsu_and_toitsu_list_str, i * 3, 3)% 失败
                count_map:index -= 1
                count_map:(index + 2) -= 1
            CASE "b"
                SIF MIN(count_map:index, count_map:(index + 1)) < 1
                    THROW 取出搭子 %SUBSTRINGU(tatsu_and_toitsu_list_str, i * 3, 3)% 失败
                count_map:index -= 1
                count_map:(index + 1) -= 1
            CASE "c"
                SIF count_map:index < 2
                    THROW 取出对子 %SUBSTRINGU(tatsu_and_toitsu_list_str, i * 3, 3)% 失败
                count_map:index -= 2
            CASEELSE
                THROW 输入的搭子/对子格式错误 %SUBSTRINGU(tatsu_and_toitsu_list_str, i * 3, 3)%
        ENDSELECT
    NEXT
    count_map_str '= STRJOIN(count_map, "")
    RETURNF count_map_str


;;;DFS 可能的搭子和对子组合
;;;- int depth 当前深度
;;;@return 返回值没有意义
@mj_dfs_tatsu_and_toitsu(depth)
#FUNCTION
    #DIM DYNAMIC depth  ; 必须重置
    #DIM DYNAMIC skip_count
    #DIMS DYNAMIC hand_status
    #DIM DYNAMIC remove_success
    #DIM DYNAMIC target_index
    #DIM DYNAMIC i
    #DIM DYNAMIC j
    MJ_DFS_TIMES += 1
    ; DEBUGPRINTFORML 查找搭子对子组合方式 DFS 第{MJ_DFS_TIMES, 2}次递归 (当前深度{depth}/{MJ_DFS_MAX_DEPTH}) {str_array_len(MJ_DFS_WALK_PATH)}
    IF str_array_len(MJ_DFS_WALK_PATH) >= MJ_DFS_MAX_DEPTH  ; 达到最大深度
        IF mj_save_dfs_result_2()  ; 试图保存当前路径
            ; DEBUGPRINTFORML 保存当前路径成功 新的搭子/对子组合=\n%STRJOIN(MJ_DFS_RESULT_2, ", ", 0, str_array_len(MJ_DFS_RESULT_2))%
        ENDIF
        RETURNF 1  ; 直接终止本层探索
    ENDIF
    FOR i, 0, str_array_len(MJ_DFS_TREE_NODE)
        FOR j, 0, str_array_len(MJ_DFS_STATUS_STACK) - depth - 1
            SIF str_array_pop(MJ_DFS_STATUS_STACK) == ""
                THROW 舍弃上一轮在本层的探索 回退到当前层数的手牌状态时失败 {str_array_len(MJ_DFS_STATUS_STACK)}
        NEXT
        hand_status '= MJ_DFS_STATUS_STACK:depth  ; 初始化当前层数的手牌状态
        FOR j, 0, str_array_len(MJ_DFS_WALK_PATH) - depth
            SIF str_array_pop(MJ_DFS_WALK_PATH) == ""
                THROW 舍弃上一轮在本层的探索 回退到当前层数的节点路径时失败 {str_array_len(MJ_DFS_STATUS_STACK)}
        NEXT
        target_index = TOINT(SUBSTRINGU(MJ_DFS_TREE_NODE:i, 1))  ; 获取标记的下标
        IF SUBSTRINGU(MJ_DFS_TREE_NODE:i, 0, 1) == "a"  ; 尝试去掉指定的A类搭子(101)
            remove_success = mj_remove_tatsu_a(hand_status, target_index)
        ELSEIF SUBSTRINGU(MJ_DFS_TREE_NODE:i, 0, 1) == "b"  ; 尝试去掉指定的B类搭子(11)
            remove_success = mj_remove_tatsu_b(hand_status, target_index)
        ELSEIF SUBSTRINGU(MJ_DFS_TREE_NODE:i, 0, 1) == "c"  ; 尝试去掉指定的刻子(2)
            remove_success = mj_remove_toitsu(hand_status, target_index)
        ENDIF
        ; DEBUGPRINTFORML 第 {i} 次循环 尝试处理 %MJ_DFS_TREE_NODE:i% %remove_success ? "成功" # "失败"%
        IF remove_success
            SIF str_array_push(MJ_DFS_WALK_PATH, MJ_DFS_TREE_NODE:i) <= 0
                THROW 保存更新后的手牌状态失败 %hand_status%
        ELSE
            skip_count += 1
            SIF skip_count >= str_array_len(MJ_DFS_TREE_NODE)  ; 本层所有分支都被剪掉了
                RESULT = mj_save_dfs_result_2()  ; 试图保存当前路径
            CONTINUE  ; 剪掉在此基础上的分支
        ENDIF
        SIF str_array_push(MJ_DFS_STATUS_STACK, hand_status) <= 0
            THROW 保存更新后的手牌状态失败 %hand_status% %STRJOIN(MJ_DFS_STATUS_STACK, "|", 0, str_array_len(MJ_DFS_STATUS_STACK))%
        RESULT = mj_dfs_tatsu_and_toitsu(depth + 1)  ; 进入下一层递归
    NEXT
    RETURNF 0


;;;把手牌拆分为搭子和对子
;;;- str count_map_str 手牌数量映射数组
;;;@return 1成功 0失败
@mj_get_tatsu_and_toitsu(count_map_str)
#FUNCTION
    #DIMS DYNAMIC count_map_str
    VARSET MJ_DFS_STATUS_STACK, ""
    MJ_DFS_STATUS_STACK:0 '= count_map_str
    VARSET MJ_DFS_TREE_NODE, ""
    SPLIT mj_get_every_tatsu_and_toitsu(count_map_str), ",", MJ_DFS_TREE_NODE
    MJ_DFS_MAX_DEPTH = mj_count_hand_from(count_map_str) / 2
    VARSET MJ_DFS_WALK_PATH, ""
    VARSET MJ_DFS_RESULT_2, ""
    MJ_DFS_TIMES = 0
    RESULT = mj_dfs_tatsu_and_toitsu(0)
    RETURNF str_array_len(MJ_DFS_RESULT_2) > 0
