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>
184 lines
6.0 KiB
Python
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()) |