1
0

feat: update legacy

This commit is contained in:
2026-06-16 19:57:15 +08:00
parent 1c81b24f74
commit 480e11dbf4
3 changed files with 252 additions and 35 deletions

View File

@@ -1,6 +1,6 @@
from typing import Iterable
from pathlib import Path
from .common import LcrConnException
from common import LcrConnException
class Dataset:

View File

@@ -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:
class AppResolver(enum.StrEnum):
"""
The resolver for the app.
"""
LUT = "lut"
"""The look-up table resolver."""
ASTAR = "astar"
"""The A* resolver."""
@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(circuit: Circuit) -> None:
match circuit.len_devices():
case 1:
dev1 = to_human_readable_value(circuit.__first_device_value)
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 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}")
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 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}")
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}")
case _:
raise LcrConnException("Circuit too complex to illustrate")
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()

View File

@@ -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)