Files
codetutor/frontend/src/lib/python-helpers.ts

201 lines
5.5 KiB
TypeScript

/**
* Python helper code and detection utilities for the test runner.
*
* This module provides Python code as string constants for data structure
* classes, conversion functions, and utilities to detect problem types.
*/
// =============================================================================
// Data Structure Classes
// =============================================================================
export const TREE_NODE_CLASS = `
class TreeNode:
def __init__(self, val=0, left=None, right=None):
self.val = val
self.left = left
self.right = right
`.trim();
export const LIST_NODE_CLASS = `
class ListNode:
def __init__(self, val=0, next=None):
self.val = val
self.next = next
`.trim();
// =============================================================================
// Conversion Functions
// =============================================================================
/**
* Builds a binary tree from a level-order array representation.
* Example: [1, 2, 3, null, 4] -> TreeNode(1, TreeNode(2, None, TreeNode(4)), TreeNode(3))
*/
export const BUILD_TREE = `
def __build_tree(arr):
if not arr or arr[0] is None:
return None
root = TreeNode(arr[0])
queue = [root]
i = 1
while queue and i < len(arr):
node = queue.pop(0)
if i < len(arr) and arr[i] is not None:
node.left = TreeNode(arr[i])
queue.append(node.left)
i += 1
if i < len(arr) and arr[i] is not None:
node.right = TreeNode(arr[i])
queue.append(node.right)
i += 1
return root
`.trim();
/**
* Converts a binary tree to a level-order array representation.
* Example: TreeNode(1, TreeNode(2), TreeNode(3)) -> [1, 2, 3]
*/
export const TREE_TO_ARRAY = `
def __tree_to_array(root):
if root is None:
return []
result = []
queue = [root]
while queue:
node = queue.pop(0)
if node is None:
result.append(None)
else:
result.append(node.val)
queue.append(node.left)
queue.append(node.right)
# Trim trailing nulls
while result and result[-1] is None:
result.pop()
return result
`.trim();
/**
* Builds a linked list from an array.
* Example: [1, 2, 3] -> ListNode(1, ListNode(2, ListNode(3)))
*/
export const BUILD_LIST = `
def __build_list(arr):
if not arr:
return None
head = ListNode(arr[0])
current = head
for val in arr[1:]:
current.next = ListNode(val)
current = current.next
return head
`.trim();
/**
* Converts a linked list to an array.
* Example: ListNode(1, ListNode(2, ListNode(3))) -> [1, 2, 3]
*/
export const LIST_TO_ARRAY = `
def __list_to_array(head):
result = []
current = head
while current:
result.append(current.val)
current = current.next
return result
`.trim();
// =============================================================================
// Problem Type Detection
// =============================================================================
/** Parameter names that indicate a tree-based problem */
export const TREE_PARAMS = ["root", "tree", "p", "q"];
/** Parameter names that indicate a linked-list problem */
export const LIST_PARAMS = ["head", "l1", "l2", "list1", "list2", "node"];
export type ProblemType = "simple" | "tree" | "linkedlist" | "class-based";
/**
* Detects the problem type based on the function signature and input.
*
* @param signature - The function signature (e.g., "def two_sum(nums, target):")
* @param input - The test case input object
* @returns The detected problem type
*/
export function detectProblemType(
signature: string,
input: Record<string, unknown>
): ProblemType {
// Class-based: check if input has "operations" key
if ("operations" in input) {
return "class-based";
}
// Check signature for type hints
const hasTreeNode = signature.includes("TreeNode");
const hasListNode = signature.includes("ListNode");
if (hasTreeNode) {
return "tree";
}
if (hasListNode) {
return "linkedlist";
}
// Check parameter names in signature and input keys
const inputKeys = Object.keys(input);
const hasTreeParam =
TREE_PARAMS.some((param) => signature.includes(param)) ||
inputKeys.some((key) => TREE_PARAMS.includes(key));
const hasListParam =
LIST_PARAMS.some((param) => signature.includes(param)) ||
inputKeys.some((key) => LIST_PARAMS.includes(key));
if (hasTreeParam) {
return "tree";
}
if (hasListParam) {
return "linkedlist";
}
return "simple";
}
/**
* Gets the Python helper code needed for a given problem type.
*/
export function getPythonHelpers(problemType: ProblemType): string {
switch (problemType) {
case "tree":
return [TREE_NODE_CLASS, BUILD_TREE, TREE_TO_ARRAY].join("\n\n");
case "linkedlist":
return [LIST_NODE_CLASS, BUILD_LIST, LIST_TO_ARRAY].join("\n\n");
case "class-based":
return ""; // Class-based problems define their own class
case "simple":
default:
return "";
}
}
/**
* Gets the list of parameter names that need tree conversion.
*/
export function getTreeParams(input: Record<string, unknown>): string[] {
return Object.keys(input).filter((key) => TREE_PARAMS.includes(key));
}
/**
* Gets the list of parameter names that need linked list conversion.
*/
export function getListParams(input: Record<string, unknown>): string[] {
return Object.keys(input).filter((key) => LIST_PARAMS.includes(key));
}