From 480e11dbf4b6825a266ab578f2b993a7c63afbc8 Mon Sep 17 00:00:00 2001 From: yyc12345 Date: Tue, 16 Jun 2026 19:57:15 +0800 Subject: [PATCH] feat: update legacy --- legacy/dataset.py | 2 +- legacy/lcr_connector.py | 273 +++++++++++++++++++++++++++++++++++----- legacy/query.py | 12 +- 3 files changed, 252 insertions(+), 35 deletions(-) diff --git a/legacy/dataset.py b/legacy/dataset.py index 726c20f..6d3b98b 100644 --- a/legacy/dataset.py +++ b/legacy/dataset.py @@ -1,6 +1,6 @@ from typing import Iterable from pathlib import Path -from .common import LcrConnException +from common import LcrConnException class Dataset: diff --git a/legacy/lcr_connector.py b/legacy/lcr_connector.py index 53dfabb..3ff7f2a 100644 --- a/legacy/lcr_connector.py +++ b/legacy/lcr_connector.py @@ -1,36 +1,245 @@ -from .common import LcrConnException, Circuit, JointKind, to_human_readable_value +import enum +import argparse +from dataclasses import dataclass +from pathlib import Path +from typing import TypeVar, cast +from common import Circuit, CircuitDeviceScale, JointKind +from dataset import ( + DatasetCollection, + to_human_readable_value, + from_human_readable_value, +) +from query import Response +from resolver import Resolver, LutResolver, AStarResolver + +_T = TypeVar("_T", bound=str) -def _get_joint_kind_symbol(joint_kind: JointKind) -> str: - match joint_kind: - case JointKind.SERIES: - return "S" - case JointKind.PARALLEL: - return "P" +class AppResolver(enum.StrEnum): + """ + The resolver for the app. + """ + + LUT = "lut" + """The look-up table resolver.""" + ASTAR = "astar" + """The A* resolver.""" -def _illustrate_circuit(circuit: Circuit) -> None: - match circuit.len_devices(): - case 1: - dev1 = to_human_readable_value(circuit.__first_device_value) - print(f"{dev1}") - case 2: - dev1 = to_human_readable_value(circuit.__first_device_value) - joint1 = circuit.joints[0] - j1 = _get_joint_kind_symbol(joint1.__joint_kind) - dev2 = to_human_readable_value(joint1.__device_value) - print(f"[{j1}] ┬ {dev1}") - print(f" └ {dev2}") - case 3: - dev1 = to_human_readable_value(circuit.__first_device_value) - joint1 = circuit.joints[0] - j1 = _get_joint_kind_symbol(joint1.__joint_kind) - dev2 = to_human_readable_value(joint1.__device_value) - joint2 = circuit.joints[1] - j2 = _get_joint_kind_symbol(joint2.__joint_kind) - dev3 = to_human_readable_value(joint2.__device_value) - print(f"[{j2}] ┬ [{j1}] ┬ {dev1}") - print(f" │ └ {dev2}") - print(f" └ {dev3}") - case _: - raise LcrConnException("Circuit too complex to illustrate") +@dataclass +class AppConfig: + """ + The configuration for the app. + """ + + resolver: AppResolver + """The resolver for the app.""" + + resistor_dataset: Path + """The path to the resistor dataset file.""" + capacitor_dataset: Path + """The path to the capacitor dataset file.""" + inductor_dataset: Path + """The path to the inductor dataset file.""" + + +class App: + """ + The app. + """ + + __config: AppConfig + """The configuration for the app.""" + __dataset: DatasetCollection + """The dataset for the app.""" + __resolver: Resolver + """The resolver for the app.""" + + def __init__(self, config: AppConfig) -> None: + self.__config = config + self.__dataset = DatasetCollection.from_file( + self.__config.resistor_dataset, + self.__config.capacitor_dataset, + self.__config.inductor_dataset, + ) + match self.__config.resolver: + case AppResolver.LUT: + self.__resolver = LutResolver(self.__dataset) + case AppResolver.ASTAR: + self.__resolver = AStarResolver(self.__dataset) + + def run(self) -> None: + """ + Run the app. + """ + print("LCR Connector") + print('Type "help" for more info. Type "exit" to quit.') + print("query: do a query.") + print("help: show all command.") + print("exit: exit this app.") + + while True: + shit = self.__accept_command(("query", "help", "exit")) + match self.__accept_command(("query", "help", "exit")): + case "query": + self.__op_query() + case "help": + print("LCR Connector Help:") + print("") + print("query: do a query.") + print("help: show all command.") + print("exit: exit this app.") + case "exit": + break + + def __op_query(self) -> None: + pass + + def __op_page_viewer(self, response: Response) -> None: + cnt = len(response) + if cnt == 0: + print("Sorry, no result!") + print("Please consider adjusting your requirements and try again.") + return + + ITEMS_PER_PAGE: int = 10 + all_page = cnt // ITEMS_PER_PAGE + current_page = 0 + + while True: + # print list + for i in range(ITEMS_PER_PAGE - 1): + # build index and check it + index = current_page * (ITEMS_PER_PAGE - 1) + i + if index >= cnt: + continue + # fetch item and print it + item = response[index] + print( + "Plan {0}\t{1}\t{2:.2%}".format( + index + 1, + to_human_readable_value(item.value), + item.relative_difference, + ) + ) + # print page footer + print("") + print("Page {} of {}.".format(current_page + 1, all_page + 1)) + print("f: previous page. b: next page. q: quit this viewer.") + # check command + match self.__accept_command(("f", "b", "q")): + case "f": + current_page = max(0, current_page - 1) + case "b": + current_page = min(all_page, current_page + 1) + case "q": + break + + def __accept_command(self, valid_commands: tuple[_T, ...]) -> _T: + while True: + print("> ", end=None) + words = input() + words = words.strip() + if words in valid_commands: + return cast(_T, words) + print("Unknown command, please try again.") + + def __accept_value_input(self) -> float: + while True: + words = input() + + try: + pending = from_human_readable_value(words) + except ValueError: + print("Wrong value, please try again.") + continue + + if pending > 0: + return pending + else: + print("Value out of range, please try again.") + + def __get_joint_kind_symbol(self, joint_kind: JointKind) -> str: + match joint_kind: + case JointKind.SERIES: + return "S" + case JointKind.PARALLEL: + return "P" + + def __illustrate_circuit(self, circuit: Circuit) -> None: + match circuit.device_scale: + case CircuitDeviceScale.ONE: + dev1 = to_human_readable_value(circuit.first_device_value) + print(f"{dev1}") + case CircuitDeviceScale.TWO: + dev1 = to_human_readable_value(circuit.first_device_value) + j2 = self.__get_joint_kind_symbol(circuit.second_device_joint) + dev2 = to_human_readable_value(circuit.second_device_value) + print(f"[{j2}] ┬ {dev1}") + print(f" └ {dev2}") + case CircuitDeviceScale.THREE: + dev1 = to_human_readable_value(circuit.first_device_value) + j2 = self.__get_joint_kind_symbol(circuit.second_device_joint) + dev2 = to_human_readable_value(circuit.second_device_value) + j3 = self.__get_joint_kind_symbol(circuit.third_device_joint) + dev3 = to_human_readable_value(circuit.third_device_value) + print(f"[{j3}] ┬ [{j2}] ┬ {dev1}") + print(f" │ └ {dev2}") + print(f" └ {dev3}") + + +if __name__ == "__main__": + parser = argparse.ArgumentParser( + prog="LCR Connector", + description="Get the resistor, capacitor, or inductor circuit which has the closest value for your given value within at most 3 devices.", + ) + parser.add_argument( + "-s", + "--resolver", + dest="resolver", + action="store", + type=AppResolver, + choices=[resolver.value for resolver in AppResolver], + required=True, + help="The resolver you want to use", + ) + parser.add_argument( + "-r", + "--resistor", + dest="resistor_dataset", + action="store", + type=Path, + required=True, + help="The path to the resistor dataset file", + metavar="RESISTOR.TXT", + ) + parser.add_argument( + "-l", + "--inductor", + dest="inductor_dataset", + action="store", + type=Path, + required=True, + help="The path to the inductor dataset file", + metavar="INDUCTOR.TXT", + ) + parser.add_argument( + "-c", + "--capacitor", + dest="capacitor_dataset", + action="store", + type=Path, + required=True, + help="The path to the capacitor dataset file", + metavar="CAPACITOR.TXT", + ) + + args = parser.parse_args() + app_config = AppConfig( + resolver=args.resolver, + resistor_dataset=args.resistor_dataset, + capacitor_dataset=args.capacitor_dataset, + inductor_dataset=args.inductor_dataset, + ) + app = App(app_config) + app.run() diff --git a/legacy/query.py b/legacy/query.py index da955f5..701e382 100644 --- a/legacy/query.py +++ b/legacy/query.py @@ -2,7 +2,7 @@ import enum from functools import cached_property from dataclasses import dataclass from typing import Iterator -from .common import DeviceKind, Circuit +from common import DeviceKind, Circuit class ResponsePriority(enum.Enum): @@ -103,7 +103,9 @@ class Response: """ The collection of possible solutions given by the resolver. - For getting the response items, please use the iterator protocol. + For getting the response items, please use `response[index]`. + For iterating the response items, please use the iterator protocol. + For getting the count of response items, please use the ``len`` function. """ __sorted_items: list[ResponseItem] @@ -125,5 +127,11 @@ class Response: # Cut item by limit self.__sorted_items = self.__sorted_items[:request.count_limit] + def __getitem__(self, index: int) -> ResponseItem: + return self.__sorted_items[index] + + def __len__(self) -> int: + return len(self.__sorted_items) + def __iter__(self) -> Iterator[ResponseItem]: return iter(self.__sorted_items)