warfactoryracine/tools/count_project_stats.py
StillHammer 78e31fc765 Create world-generation-realist module architecture interfaces
Core serialization interfaces:
- ISerializable → ASerializable with auto-registration concept
- SerializationRegistry singleton interface
- Template-based factory system with PhaseRegistry

Shared interfaces (moved to core):
- IAttachedElement for element relationships
- IElementData for polymorphic data
- IRegion interface with attachment capabilities
- Resource interface for gameData integration

World generation interfaces:
- IWorldGenerationPhase and IWorldGenerationStep
- GTile optimized 16-byte structure definition
- GMap interface for contiguous memory layout
- WorldGenerationOrchestrator interface

Phase 1 structure definitions:
- PlanetaryCore interface with composition tracking
- Meteorite data structure
- MeteoriteImpact parameterizable interface
- RegionManager interface

Climate token system design:
- Water/wind tokens for climate simulation
- Destruction tokens (highWind/flood/hurricane) packed design
- Elevation range: -32km to +32km geological scale
- Budget system integration ready

Note: Interfaces and structure definitions only - implementations pending.
Architecture designed for Regular_world.json integration and SIMD optimization.

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-09-29 23:16:14 +08:00

184 lines
6.0 KiB
Python

#!/usr/bin/env python3
"""
Project Statistics Counter
Counts lines, characters, and files in the Warfactory project
"""
import os
import sys
from pathlib import Path
from collections import defaultdict
def get_file_extension(file_path):
"""Get file extension, handling special cases"""
if file_path.name in ['CLAUDE.md', 'README.md', 'TODO.md']:
return '.md'
return file_path.suffix.lower()
def is_text_file(file_path):
"""Determine if file is likely a text file"""
text_extensions = {
'.md', '.txt', '.json', '.cpp', '.h', '.hpp', '.c', '.cc', '.cxx',
'.py', '.js', '.ts', '.html', '.css', '.xml', '.yaml', '.yml',
'.cmake', '.sh', '.bat', '.ps1', '.toml', '.ini', '.cfg', '.conf'
}
# Special files without extensions
special_files = {'CLAUDE.md', 'README.md', 'TODO.md', 'CMakeLists.txt', 'Makefile'}
return (get_file_extension(file_path) in text_extensions or
file_path.name in special_files)
def should_skip_directory(dir_path):
"""Check if directory should be skipped"""
dir_name = Path(dir_path).name
# Skip common build/temp directories
skip_dirs = {
'.git', '.vs', '.vscode', '__pycache__', 'node_modules',
'build', 'bin', 'obj', 'Debug', 'Release', '.idea', 'external'
}
# Skip any directory starting with build
if dir_name.startswith('build'):
return True
# Skip any _deps directories (external dependencies)
if '_deps' in dir_name:
return True
# Skip CMakeFiles directories
if 'CMakeFiles' in dir_name:
return True
# Skip external libraries directory
if dir_name == 'external':
return True
return dir_name in skip_dirs
def count_file_stats(file_path):
"""Count lines and characters in a file"""
try:
with open(file_path, 'r', encoding='utf-8', errors='ignore') as f:
content = f.read()
lines = content.count('\n') + (1 if content and not content.endswith('\n') else 0)
chars = len(content)
return lines, chars
except Exception as e:
print(f"Warning: Could not read {file_path}: {e}")
return 0, 0
def main():
"""Main function to count project statistics"""
# Get project root (parent of tools directory)
script_dir = Path(__file__).parent
project_root = script_dir.parent
print(f"Analyzing project: {project_root}")
print("=" * 60)
# Statistics tracking
total_files = 0
total_lines = 0
total_chars = 0
stats_by_extension = defaultdict(lambda: {'files': 0, 'lines': 0, 'chars': 0})
stats_by_directory = defaultdict(lambda: {'files': 0, 'lines': 0, 'chars': 0})
# Walk through all files
processed_files = 0
for root, dirs, files in os.walk(project_root):
# Skip unwanted directories
dirs[:] = [d for d in dirs if not should_skip_directory(d)]
root_path = Path(root)
relative_root = root_path.relative_to(project_root)
# Show progress for each directory
if files:
print(f"Processing: {relative_root}")
for file in files:
file_path = root_path / file
# Only process text files
if not is_text_file(file_path):
continue
processed_files += 1
if processed_files % 10 == 0:
print(f" Processed {processed_files} files...")
lines, chars = count_file_stats(file_path)
total_files += 1
total_lines += lines
total_chars += chars
# Track by extension
ext = get_file_extension(file_path)
if not ext:
ext = '(no extension)'
stats_by_extension[ext]['files'] += 1
stats_by_extension[ext]['lines'] += lines
stats_by_extension[ext]['chars'] += chars
# Track by directory
dir_name = str(relative_root) if relative_root != Path('.') else '(root)'
stats_by_directory[dir_name]['files'] += 1
stats_by_directory[dir_name]['lines'] += lines
stats_by_directory[dir_name]['chars'] += chars
# Print overall statistics
print(f"📊 TOTAL PROJECT STATISTICS")
print(f"Files: {total_files:,}")
print(f"Lines: {total_lines:,}")
print(f"Characters: {total_chars:,}")
print()
# Print statistics by file type
print("📝 BY FILE TYPE:")
print(f"{'Extension':<15} {'Files':<8} {'Lines':<12} {'Characters':<15}")
print("-" * 60)
for ext in sorted(stats_by_extension.keys()):
stats = stats_by_extension[ext]
print(f"{ext:<15} {stats['files']:<8} {stats['lines']:<12,} {stats['chars']:<15,}")
print()
# Print statistics by directory (top level)
print("📁 BY DIRECTORY:")
print(f"{'Directory':<20} {'Files':<8} {'Lines':<12} {'Characters':<15}")
print("-" * 65)
# Sort by line count (descending)
sorted_dirs = sorted(stats_by_directory.items(),
key=lambda x: x[1]['lines'], reverse=True)
for dir_name, stats in sorted_dirs:
if stats['files'] > 0: # Only show directories with files
display_name = dir_name[:19] + "..." if len(dir_name) > 19 else dir_name
print(f"{display_name:<20} {stats['files']:<8} {stats['lines']:<12,} {stats['chars']:<15,}")
print()
print("🎯 Analysis complete!")
# Calculate some fun metrics
avg_lines_per_file = total_lines / total_files if total_files > 0 else 0
avg_chars_per_line = total_chars / total_lines if total_lines > 0 else 0
print(f"📈 METRICS:")
print(f"Average lines per file: {avg_lines_per_file:.1f}")
print(f"Average characters per line: {avg_chars_per_line:.1f}")
# Estimate pages (assuming ~50 lines per page)
estimated_pages = total_lines / 50
print(f"Estimated printed pages: {estimated_pages:.0f}")
return 0
if __name__ == "__main__":
sys.exit(main())