This commit is contained in:
h z
2026-02-15 02:28:28 +00:00
commit 95b22c595d
36 changed files with 1884 additions and 0 deletions

View File

@@ -0,0 +1,115 @@
# CLAUDE.md
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
## Workspace Architecture
**DungeonSolver.Workspace** is a multi-project C# solution (.NET 8.0) organized as a modular game development workspace. Each project serves a specific purpose and can be built independently.
### Project Structure
- **DungeonSolver/**: Main Godot 4.5 game project with Python integration (see `DungeonSolver/CLAUDE.md` for detailed game-specific guidance)
- **DungeonSolver.Global/**: Core game systems and global providers, outputs to `DungeonSolver/Data/` for game consumption
- **DungeonSolver.PythonBridge/**: Python integration layer using IronPython/pythonnet
- **DungeonSolver.Game/**: Game-specific logic and systems
- **DungeonSolver.Generators/**: Roslyn source generators for automated code generation
- **DungeonSolver.Global.Generators/**: Source generators specifically for the Global project
- **DungeonSolver.Tasks/**: Build tasks and utilities
### Key Architectural Patterns
**Modular Project Design**: Each component is isolated in its own project with specific responsibilities:
- Global project compiles to `DungeonSolver/Data/` for runtime access
- Source generators use `OutputItemType="Analyzer" ReferenceOutputAssembly="false"` pattern
- Python bridge allows C# game systems to be accessed from Python via `clr.AddReference()`
**Source Generator Integration**: Projects use Roslyn source generators for code generation:
- Generators project contains sample incremental source generators
- Target classes use `[Generators.ReportAttribute]` for report generation
- Build generators to see generated code in IDE
**Python-C# Interop**:
- **Python Package Generator**: Automatically generates Python wrapper classes for C# types marked with `[PythonSharedType]` attributes
- Generates type-safe Python interfaces from C# classes, interfaces, and enums
- Handles complex generic types and nested class hierarchies
- Supports inheritance, member access, and method calls with proper type hints
- Generated Python packages are output to `user://dungeon_solver/types/`
- **Type Registration System**: Uses `PythonSharedTypeRegister` to map C# types to Python equivalents
- **Shared Memory Communication**: Advanced IPC system for real-time C#-Python communication (see `Documents/SharedMemoryCommunicationProtocol.md`)
- **Runtime Access**: Python scripts access C# via `DungeonSolver.Global.dll` using IronPython/pythonnet
- **Bridge Pattern**: Example implementation in `DungeonSolver/Data/Solver.py`
## Build and Development Commands
**Building Individual Projects**:
```bash
# Build specific project
dotnet build DungeonSolver.Global/
dotnet build DungeonSolver.Generators/
dotnet build DungeonSolver.PythonBridge/
# Build main game project (includes all dependencies)
cd DungeonSolver && dotnet build
```
**Building the Entire Workspace**:
```bash
# Build all projects from workspace root
dotnet build DungeonSolver/DungeonSolver.sln
```
**Source Generator Development**:
```bash
# Build generators to see generated code
dotnet build DungeonSolver.Generators/
dotnet build DungeonSolver.Global.Generators/
```
**Testing**:
```bash
# Run generator unit tests
cd DungeonSolver.Generators && dotnet test
cd DungeonSolver.Global.Generators && dotnet test
```
## Code Style Guidelines
**C# Coding Standards**:
- **No `var` keyword**: Always use explicit types instead of `var`
```csharp
string name = "example"; // Correct
List<int> numbers = new List<int>(); // Correct
// var name = "example"; // Wrong
```
- **No comments**: Do not write any comments in code (XML documentation, inline comments, or block comments)
- Write self-documenting code with clear variable and method names
## Development Workflow Notes
**Project Dependencies**: The main solution (`DungeonSolver/DungeonSolver.sln`) references all other projects, creating a unified build process while maintaining modular development.
**Global System Access**: Python scripts can access the Global project's compiled output via the established bridge pattern in `Data/Solver.py`.
**Source Generator Workflow**:
1. Modify generator code in `*.Generators` projects
2. Build generator project to compile changes
3. Target projects automatically regenerate code during their build
4. Use Rossynt plugin for syntax tree analysis during development
**Cross-Project Development**: Each project can be developed and tested independently, with the main game project serving as the integration point.
**Python Type System Development**:
1. Mark C# types with appropriate `[PythonSharedType]` attributes (`[PythonSharedClass]`, `[PythonSharedInterface]`, `[PythonSharedEnum]`)
2. Add `[PythonSharedMember]` and `[PythonSharedMethod]` attributes to expose specific members
3. Build `DungeonSolver.Global` project to register types in `PythonSharedTypeRegister`
4. Generated Python types automatically handle complex scenarios like:
- Generic type parameters and constraints
- Nested class inheritance hierarchies
- Interface implementation and multiple inheritance
- Enum value mapping and type safety
**Important Development Notes**:
- Always build `DungeonSolver.Global` before the main game project to ensure Python bindings are up-to-date
- When modifying Python-shared types, rebuild is required to regenerate Python wrapper classes
- Use `PythonPackageGenerator.Generate()` to manually trigger Python code generation during development
- Nested classes inherit sharing attributes from parent classes automatically via `NestedClassWrapper` pattern

Submodule DungeonSolver.Workspace/DungeonSolver added at 0d81d98a35

Submodule DungeonSolver.Workspace/DungeonSolver.Analyzer added at b82ca1657e

Submodule DungeonSolver.Workspace/DungeonSolver.Core added at 9de186f41a

Submodule DungeonSolver.Workspace/DungeonSolver.Core.Analyzer added at d7d39d2332

Submodule DungeonSolver.Workspace/DungeonSolver.Core.Generators added at 056e924943

Submodule DungeonSolver.Workspace/DungeonSolver.Generator.Core added at 8c66583d23

Submodule DungeonSolver.Workspace/DungeonSolver.Generators added at 57afa2cc50

View File

@@ -0,0 +1,132 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="AutoGeneratedRunConfigurationManager">
<projectFile profileName="DebugRoslynAnalyzers">DungeonSolver.Global.Analyzer/DungeonSolver.Global.Analyzer.csproj</projectFile>
</component>
<component name="AutoImportSettings">
<option name="autoReloadType" value="SELECTIVE" />
</component>
<component name="ChangeListManager">
<list default="true" id="e8a473e9-efa8-4c17-9674-1989a6c91473" name="Changes" comment="" />
<option name="SHOW_DIALOG" value="false" />
<option name="HIGHLIGHT_CONFLICTS" value="true" />
<option name="HIGHLIGHT_NON_ACTIVE_CHANGELIST" value="false" />
<option name="LAST_RESOLUTION" value="IGNORE" />
</component>
<component name="Git.Settings">
<option name="RECENT_GIT_ROOT_PATH" value="$PROJECT_DIR$" />
</component>
<component name="MetaFilesCheckinStateConfiguration" checkMetaFiles="true" />
<component name="ProjectColorInfo">{
&quot;associatedIndex&quot;: 6
}</component>
<component name="ProjectId" id="34mRHwSVMSZy66teK5Ol8c3JLUl" />
<component name="ProjectViewState">
<option name="hideEmptyMiddlePackages" value="true" />
<option name="showLibraryContents" value="true" />
</component>
<component name="PropertiesComponent">{
&quot;keyToString&quot;: {
&quot;ModuleVcsDetector.initialDetectionPerformed&quot;: &quot;true&quot;,
&quot;RunOnceActivity.ShowReadmeOnStart&quot;: &quot;true&quot;,
&quot;RunOnceActivity.TerminalTabsStorage.copyFrom.TerminalArrangementManager.252&quot;: &quot;true&quot;,
&quot;RunOnceActivity.git.unshallow&quot;: &quot;true&quot;,
&quot;com.intellij.ml.llm.matterhorn.ej.ui.settings.DefaultAutoModeForALLUsers.v1&quot;: &quot;true&quot;,
&quot;com.intellij.ml.llm.matterhorn.ej.ui.settings.DefaultModelSelectionForGA.v1&quot;: &quot;true&quot;,
&quot;git-widget-placeholder&quot;: &quot;master&quot;,
&quot;junie.onboarding.icon.badge.shown&quot;: &quot;true&quot;,
&quot;node.js.detected.package.eslint&quot;: &quot;true&quot;,
&quot;node.js.detected.package.tslint&quot;: &quot;true&quot;,
&quot;node.js.selected.package.eslint&quot;: &quot;(autodetect)&quot;,
&quot;node.js.selected.package.tslint&quot;: &quot;(autodetect)&quot;,
&quot;nodejs_package_manager_path&quot;: &quot;npm&quot;,
&quot;to.speed.mode.migration.done&quot;: &quot;true&quot;,
&quot;vue.rearranger.settings.migration&quot;: &quot;true&quot;
}
}</component>
<component name="RunManager">
<configuration name="DungeonSolver.Global.Analyzer: DebugRoslynAnalyzers" type="LaunchSettings" factoryName=".NET Launch Settings Profile">
<option name="LAUNCH_PROFILE_PROJECT_FILE_PATH" value="$PROJECT_DIR$/DungeonSolver.Global.Analyzer/DungeonSolver.Global.Analyzer.csproj" />
<option name="LAUNCH_PROFILE_TFM" value=".NETStandard,Version=v2.0" />
<option name="LAUNCH_PROFILE_NAME" value="DebugRoslynAnalyzers" />
<option name="USE_EXTERNAL_CONSOLE" value="0" />
<option name="USE_MONO" value="0" />
<option name="RUNTIME_ARGUMENTS" value="" />
<option name="GENERATE_APPLICATIONHOST_CONFIG" value="1" />
<option name="SHOW_IIS_EXPRESS_OUTPUT" value="0" />
<option name="SEND_DEBUG_REQUEST" value="1" />
<option name="ADDITIONAL_IIS_EXPRESS_ARGUMENTS" value="" />
<option name="AUTO_ATTACH_CHILDREN" value="0" />
<method v="2">
<option name="Build" />
</method>
</configuration>
</component>
<component name="TaskManager">
<task active="true" id="Default" summary="Default task">
<changelist id="e8a473e9-efa8-4c17-9674-1989a6c91473" name="Changes" comment="" />
<created>1761816676447</created>
<option name="number" value="Default" />
<option name="presentableId" value="Default" />
<updated>1761816676447</updated>
<workItem from="1761816677692" duration="695000" />
<workItem from="1762861373046" duration="167000" />
</task>
<task id="LOCAL-00001" summary="init">
<option name="closed" value="true" />
<created>1761816967095</created>
<option name="number" value="00001" />
<option name="presentableId" value="LOCAL-00001" />
<option name="project" value="LOCAL" />
<updated>1761816967095</updated>
</task>
<task id="LOCAL-00002" summary="clean">
<option name="closed" value="true" />
<created>1761817160460</created>
<option name="number" value="00002" />
<option name="presentableId" value="LOCAL-00002" />
<option name="project" value="LOCAL" />
<updated>1761817160460</updated>
</task>
<task id="LOCAL-00003" summary="re init">
<option name="closed" value="true" />
<created>1761817211100</created>
<option name="number" value="00003" />
<option name="presentableId" value="LOCAL-00003" />
<option name="project" value="LOCAL" />
<updated>1761817211100</updated>
</task>
<option name="localTasksCounter" value="4" />
<servers />
</component>
<component name="TypeScriptGeneratedFilesManager">
<option name="version" value="3" />
</component>
<component name="UnityCheckinConfiguration" checkUnsavedScenes="true" />
<component name="UnityProjectConfiguration" hasMinimizedUI="false" />
<component name="VcsManagerConfiguration">
<option name="CLEAR_INITIAL_COMMIT_MESSAGE" value="true" />
<MESSAGE value="init" />
<MESSAGE value="clean" />
<MESSAGE value="re init" />
<option name="LAST_COMMIT_MESSAGE" value="re init" />
</component>
<component name="XDebuggerManager">
<breakpoint-manager>
<breakpoints>
<breakpoint enabled="true" type="DotNet_Exception_Breakpoints">
<properties exception="System.OperationCanceledException" breakIfHandledByOtherCode="false" displayValue="System.OperationCanceledException" />
<option name="timeStamp" value="1" />
</breakpoint>
<breakpoint enabled="true" type="DotNet_Exception_Breakpoints">
<properties exception="System.Threading.Tasks.TaskCanceledException" breakIfHandledByOtherCode="false" displayValue="System.Threading.Tasks.TaskCanceledException" />
<option name="timeStamp" value="2" />
</breakpoint>
<breakpoint enabled="true" type="DotNet_Exception_Breakpoints">
<properties exception="System.Threading.ThreadAbortException" breakIfHandledByOtherCode="false" displayValue="System.Threading.ThreadAbortException" />
<option name="timeStamp" value="3" />
</breakpoint>
</breakpoints>
</breakpoint-manager>
</component>
</project>

View File

@@ -0,0 +1,2 @@
<wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
<s:Boolean x:Key="/Default/ResxEditorPersonal/CheckedGroups/=DungeonSolver_002ECore_002EAnalyzer_002FResources/@EntryIndexedValue">True</s:Boolean></wpf:ResourceDictionary>

View File

@@ -0,0 +1,120 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="AutoGeneratedRunConfigurationManager">
<projectFile profileName="DebugRoslynSourceGenerator">../DungeonSolver.Core.Generators/DungeonSolver.Core.Generators.csproj</projectFile>
<projectFile profileName="DebugRoslynSourceGenerator">DungeonSolver.Global.Generators/DungeonSolver.Global.Generators/DungeonSolver.Global.Generators.csproj</projectFile>
</component>
<component name="AutoImportSettings">
<option name="autoReloadType" value="SELECTIVE" />
</component>
<component name="ChangeListManager">
<list default="true" id="a079404d-2a75-4a6c-acbc-be2886fe3cec" name="Changes" comment="" />
<option name="SHOW_DIALOG" value="false" />
<option name="HIGHLIGHT_CONFLICTS" value="true" />
<option name="HIGHLIGHT_NON_ACTIVE_CHANGELIST" value="false" />
<option name="LAST_RESOLUTION" value="IGNORE" />
</component>
<component name="Git.Settings">
<option name="RECENT_GIT_ROOT_PATH" value="$PROJECT_DIR$/../DungeonSolver.Core.Generators" />
</component>
<component name="ProblemsViewState">
<option name="selectedTabId" value="Toolset" />
</component>
<component name="ProjectColorInfo">{
&quot;associatedIndex&quot;: 7
}</component>
<component name="ProjectId" id="2okB8CsMteI0pzMz1Ui1IJ6NbpA" />
<component name="ProjectViewState">
<option name="hideEmptyMiddlePackages" value="true" />
<option name="showLibraryContents" value="true" />
</component>
<component name="PropertiesComponent"><![CDATA[{
"keyToString": {
"RunOnceActivity.ShowReadmeOnStart": "true",
"RunOnceActivity.git.unshallow": "true",
"com.intellij.ml.llm.matterhorn.ej.ui.settings.DefaultAutoModeForALLUsers.v1": "true",
"com.intellij.ml.llm.matterhorn.ej.ui.settings.DefaultModelSelectionForGA.v1": "true",
"git-widget-placeholder": "master",
"junie.onboarding.icon.badge.shown": "true",
"node.js.detected.package.eslint": "true",
"node.js.detected.package.tslint": "true",
"node.js.selected.package.eslint": "(autodetect)",
"node.js.selected.package.tslint": "(autodetect)",
"nodejs_package_manager_path": "npm",
"to.speed.mode.migration.done": "true",
"vue.rearranger.settings.migration": "true"
}
}]]></component>
<component name="RunManager" selected=".NET Launch Settings Profile.DungeonSolver.Global.Generators: DebugRoslynSourceGenerator">
<configuration name="DungeonSolver.Core.Generators: DebugRoslynSourceGenerator" type="LaunchSettings" factoryName=".NET Launch Settings Profile">
<option name="LAUNCH_PROFILE_PROJECT_FILE_PATH" value="$PROJECT_DIR$/../DungeonSolver.Core.Generators/DungeonSolver.Core.Generators.csproj" />
<option name="LAUNCH_PROFILE_TFM" value=".NETStandard,Version=v2.0" />
<option name="LAUNCH_PROFILE_NAME" value="DebugRoslynSourceGenerator" />
<option name="USE_EXTERNAL_CONSOLE" value="0" />
<option name="USE_MONO" value="0" />
<option name="RUNTIME_ARGUMENTS" value="" />
<option name="GENERATE_APPLICATIONHOST_CONFIG" value="1" />
<option name="SHOW_IIS_EXPRESS_OUTPUT" value="0" />
<option name="SEND_DEBUG_REQUEST" value="1" />
<option name="ADDITIONAL_IIS_EXPRESS_ARGUMENTS" value="" />
<option name="AUTO_ATTACH_CHILDREN" value="0" />
<method v="2">
<option name="Build" />
</method>
</configuration>
<configuration name="DungeonSolver.Global.Generators: DebugRoslynSourceGenerator" type="LaunchSettings" factoryName=".NET Launch Settings Profile">
<option name="LAUNCH_PROFILE_PROJECT_FILE_PATH" value="$PROJECT_DIR$/DungeonSolver.Global.Generators/DungeonSolver.Global.Generators/DungeonSolver.Global.Generators.csproj" />
<option name="LAUNCH_PROFILE_TFM" value=".NETStandard,Version=v2.0" />
<option name="LAUNCH_PROFILE_NAME" value="DebugRoslynSourceGenerator" />
<option name="USE_EXTERNAL_CONSOLE" value="0" />
<option name="USE_MONO" value="0" />
<option name="RUNTIME_ARGUMENTS" value="" />
<option name="GENERATE_APPLICATIONHOST_CONFIG" value="1" />
<option name="SHOW_IIS_EXPRESS_OUTPUT" value="0" />
<option name="SEND_DEBUG_REQUEST" value="1" />
<option name="ADDITIONAL_IIS_EXPRESS_ARGUMENTS" value="" />
<option name="AUTO_ATTACH_CHILDREN" value="0" />
<method v="2">
<option name="Build" />
</method>
</configuration>
</component>
<component name="SpellCheckerSettings" RuntimeDictionaries="0" Folders="0" CustomDictionaries="0" DefaultDictionary="application-level" UseSingleDictionary="true" transferred="true" />
<component name="TaskManager">
<task active="true" id="Default" summary="Default task">
<changelist id="a079404d-2a75-4a6c-acbc-be2886fe3cec" name="Changes" comment="" />
<created>1731403531514</created>
<option name="number" value="Default" />
<option name="presentableId" value="Default" />
<updated>1731403531514</updated>
<workItem from="1731403532630" duration="194000" />
<workItem from="1762860510814" duration="327000" />
</task>
<servers />
</component>
<component name="TypeScriptGeneratedFilesManager">
<option name="version" value="3" />
</component>
<component name="UnityProjectConfiguration" hasMinimizedUI="false" />
<component name="VcsManagerConfiguration">
<option name="CLEAR_INITIAL_COMMIT_MESSAGE" value="true" />
</component>
<component name="XDebuggerManager">
<breakpoint-manager>
<breakpoints>
<breakpoint enabled="true" type="DotNet_Exception_Breakpoints">
<properties exception="System.OperationCanceledException" breakIfHandledByOtherCode="false" displayValue="System.OperationCanceledException" />
<option name="timeStamp" value="1" />
</breakpoint>
<breakpoint enabled="true" type="DotNet_Exception_Breakpoints">
<properties exception="System.Threading.Tasks.TaskCanceledException" breakIfHandledByOtherCode="false" displayValue="System.Threading.Tasks.TaskCanceledException" />
<option name="timeStamp" value="2" />
</breakpoint>
<breakpoint enabled="true" type="DotNet_Exception_Breakpoints">
<properties exception="System.Threading.ThreadAbortException" breakIfHandledByOtherCode="false" displayValue="System.Threading.ThreadAbortException" />
<option name="timeStamp" value="3" />
</breakpoint>
</breakpoints>
</breakpoint-manager>
</component>
</project>

View File

@@ -0,0 +1,87 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="AutoImportSettings">
<option name="autoReloadType" value="SELECTIVE" />
</component>
<component name="ChangeListManager">
<list default="true" id="da8668bf-f36a-441e-9a5c-e37101dd3fe9" name="Changes" comment="" />
<option name="SHOW_DIALOG" value="false" />
<option name="HIGHLIGHT_CONFLICTS" value="true" />
<option name="HIGHLIGHT_NON_ACTIVE_CHANGELIST" value="false" />
<option name="LAST_RESOLUTION" value="IGNORE" />
</component>
<component name="Git.Settings">
<option name="RECENT_GIT_ROOT_PATH" value="$PROJECT_DIR$/../DungeonSolver.Core" />
</component>
<component name="HighlightingSettingsPerFile">
<setting file="file://$PROJECT_DIR$/Class1.cs" root0="FORCE_HIGHLIGHTING" />
</component>
<component name="ProblemsViewState">
<option name="selectedTabId" value="Toolset" />
</component>
<component name="ProjectColorInfo">{
&quot;associatedIndex&quot;: 7
}</component>
<component name="ProjectId" id="2mmtyf0EpF2l5xWX0Aory29SVMk" />
<component name="ProjectViewState">
<option name="hideEmptyMiddlePackages" value="true" />
<option name="showLibraryContents" value="true" />
</component>
<component name="PropertiesComponent"><![CDATA[{
"keyToString": {
"RunOnceActivity.ShowReadmeOnStart": "true",
"RunOnceActivity.git.unshallow": "true",
"com.intellij.ml.llm.matterhorn.ej.ui.settings.DefaultAutoModeForALLUsers.v1": "true",
"com.intellij.ml.llm.matterhorn.ej.ui.settings.DefaultModelSelectionForGA.v1": "true",
"git-widget-placeholder": "master",
"junie.onboarding.icon.badge.shown": "true",
"last_opened_file_path": "/home/hzhang/RiderProjects/Marshmallow/DungeonSolver.Workspace/DungeonSolver.Global.Generators/DungeonSolver.Global.Generators.sln",
"node.js.detected.package.eslint": "true",
"node.js.detected.package.tslint": "true",
"node.js.selected.package.eslint": "(autodetect)",
"node.js.selected.package.tslint": "(autodetect)",
"nodejs_package_manager_path": "npm",
"to.speed.mode.migration.done": "true",
"vue.rearranger.settings.migration": "true"
}
}]]></component>
<component name="SpellCheckerSettings" RuntimeDictionaries="0" Folders="0" CustomDictionaries="0" DefaultDictionary="application-level" UseSingleDictionary="true" transferred="true" />
<component name="TaskManager">
<task active="true" id="Default" summary="Default task">
<changelist id="da8668bf-f36a-441e-9a5c-e37101dd3fe9" name="Changes" comment="" />
<created>1727693834377</created>
<option name="number" value="Default" />
<option name="presentableId" value="Default" />
<updated>1727693834377</updated>
<workItem from="1727693835415" duration="220000" />
<workItem from="1732397814070" duration="338000" />
<workItem from="1762860049139" duration="457000" />
</task>
<servers />
</component>
<component name="TypeScriptGeneratedFilesManager">
<option name="version" value="3" />
</component>
<component name="UnityProjectConfiguration" hasMinimizedUI="false" />
<component name="VcsManagerConfiguration">
<option name="CLEAR_INITIAL_COMMIT_MESSAGE" value="true" />
</component>
<component name="XDebuggerManager">
<breakpoint-manager>
<breakpoints>
<breakpoint enabled="true" type="DotNet_Exception_Breakpoints">
<properties exception="System.OperationCanceledException" breakIfHandledByOtherCode="false" displayValue="System.OperationCanceledException" />
<option name="timeStamp" value="1" />
</breakpoint>
<breakpoint enabled="true" type="DotNet_Exception_Breakpoints">
<properties exception="System.Threading.Tasks.TaskCanceledException" breakIfHandledByOtherCode="false" displayValue="System.Threading.Tasks.TaskCanceledException" />
<option name="timeStamp" value="2" />
</breakpoint>
<breakpoint enabled="true" type="DotNet_Exception_Breakpoints">
<properties exception="System.Threading.ThreadAbortException" breakIfHandledByOtherCode="false" displayValue="System.Threading.ThreadAbortException" />
<option name="timeStamp" value="3" />
</breakpoint>
</breakpoints>
</breakpoint-manager>
</component>
</project>

Submodule DungeonSolver.Workspace/Skeleton added at 7299a2dba3

View File

@@ -0,0 +1,20 @@
import os
def count_cs_lines(root_dir: str):
total = 0
for dirpath, _, filenames in os.walk(root_dir):
for filename in filenames:
if filename.endswith(".cs"):
filepath = os.path.join(dirpath, filename)
with open(filepath, "r", encoding="utf-8", errors="ignore") as f:
lines = [
line for line in f
if line.strip() and not line.strip().startswith("//")
]
total += len(lines)
print(f"Total non-empty lines in .cs files: {total}")
if __name__ == "__main__":
os.chdir(os.path.dirname(os.path.abspath(__file__)))
count_cs_lines(".")