{"id":31897284,"url":"https://github.com/pbwebmedia/tank-game","last_synced_at":"2025-10-13T11:19:05.928Z","repository":{"id":316224603,"uuid":"1062470405","full_name":"PBWebMedia/tank-game","owner":"PBWebMedia","description":null,"archived":false,"fork":false,"pushed_at":"2025-09-23T12:09:34.000Z","size":25835,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2025-09-23T12:29:46.211Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/PBWebMedia.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2025-09-23T09:49:30.000Z","updated_at":"2025-09-23T12:09:37.000Z","dependencies_parsed_at":"2025-09-23T12:40:00.512Z","dependency_job_id":null,"html_url":"https://github.com/PBWebMedia/tank-game","commit_stats":null,"previous_names":["pbwebmedia/tank-game"],"tags_count":null,"template":false,"template_full_name":null,"purl":"pkg:github/PBWebMedia/tank-game","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/PBWebMedia%2Ftank-game","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/PBWebMedia%2Ftank-game/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/PBWebMedia%2Ftank-game/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/PBWebMedia%2Ftank-game/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/PBWebMedia","download_url":"https://codeload.github.com/PBWebMedia/tank-game/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/PBWebMedia%2Ftank-game/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":279014766,"owners_count":26085593,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-10-13T02:00:06.723Z","response_time":61,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2025-10-13T11:19:04.145Z","updated_at":"2025-10-13T11:19:05.922Z","avatar_url":"https://github.com/PBWebMedia.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Tank Game\n\nA competitive AI programming environment where developers create intelligent tank controllers to battle against each other in a 2D arena. This project serves as both an educational tool for learning AI programming concepts and a competitive platform for testing different AI strategies.\n\n## 🎮 Game Overview\n\nTank Game is a real-time combat simulation where AI-controlled tanks fight in a physics-based arena. Each tank is controlled by a custom AI script that makes decisions about movement, aiming, and firing. The last tank standing wins!\n\n### Key Features\n\n- **Real-time Combat**: Tanks move, aim, and fire projectiles with realistic physics\n- **Multiple AI Support**: Run up to 15 different AI implementations simultaneously\n- **Physics-Based Movement**: Acceleration, friction, and collision detection\n- **Health \u0026 Damage System**: Tanks start with 100 HP, projectiles deal 5 damage\n- **Firing Mechanics**: 0.5-second cooldown between shots prevents spam\n- **Arena Boundaries**: 600x450 pixel battlefield with water obstacles\n- **Visual Feedback**: SDL3-based graphics with colorful tank identification\n\n### Game Mechanics\n\n- **Arena Size**: 600x450 pixels\n- **Tank Health**: 100 HP (eliminated at 0 HP)\n- **Projectile Damage**: 5 HP per hit\n- **Fire Cooldown**: 0.5 seconds between shots\n- **Tank Speed**: Max 150 pixels/second with acceleration\n- **Turn Rate**: 180 degrees per second (π radians/second)\n- **Tank Colors**: Red, Green, Blue, Yellow, Magenta, Cyan\n\n## 🚀 Installation \u0026 Setup\n\n### Prerequisites\n\n**SDL3 Library** is required for graphics rendering.\n\n#### Windows\n1. Download `sdl3.dll` from the [SDL3 GitHub releases](https://github.com/libsdl-org/SDL/releases)\n2. Place `sdl3.dll` in the project root directory\n\n#### Linux (Ubuntu/Debian)\n```bash\nsudo apt-get install libsdl3 libsdl3-image\n```\n\n#### Linux (Fedora/Red Hat)\n```bash\nsudo dnf install SDL3 SDL3_image\n```\n\n#### macOS\n```bash\nbrew install sdl3\n```\n\n### Building and Running\n\n1. **Clone the repository**:\n   ```bash\n   git clone \u003crepository-url\u003e\n   cd tank-game\n   ```\n\n2. **Install Go dependencies**:\n   ```bash\n   go mod tidy\n   ```\n\n3. **Run the game**:\n   ```bash\n   go run main.go\n   ```\n\nThe game will automatically load all registered AI implementations and start the battle!\n\n## 🎯 How to Play\n\nThe game runs automatically once started. You'll see:\n\n- **Colored tanks** representing different AI implementations\n- **Projectiles** flying across the battlefield\n- **Real-time combat** as AIs make decisions and battle\n- **Health indicators** showing tank status\n- **Victory condition** when only one tank remains\n\n### Controls\n\nThis is an AI-only game - there are no manual controls. All tanks are controlled by their respective AI scripts.\n\n## 🤖 Creating Your Own AI\n\n### AI Interface\n\nEvery AI must implement the `game.AI` interface with three methods:\n\n```go\ntype AI interface {\n    GetName() string\n    Initialize(tank *Tank, gameState *GameState) error\n    Update(tank *Tank, gameState *GameState, commands *Commands) error\n}\n```\n\n### Available Commands\n\nYour AI can control the tank using these commands:\n\n```go\ntype Commands struct {\n    MoveForward  bool  // Accelerate forward\n    MoveBackward bool  // Accelerate backward\n    TurnLeft     bool  // Turn counterclockwise\n    TurnRight    bool  // Turn clockwise\n    Fire         bool  // Shoot projectile (if cooldown ready)\n}\n```\n\n### Tank Properties\n\nYour AI has access to your tank's properties:\n\n```go\n// Position and movement\ntank.Position     // Vector2 - current position\ntank.Rotation     // float64 - current rotation in radians\ntank.Velocity     // Vector2 - current velocity\n\n// Combat stats\ntank.Health       // int - current health (0-100)\ntank.IsAlive      // bool - whether tank is still active\ntank.CanFire()    // bool - whether tank can fire (cooldown ready)\n\n// Physics properties\ntank.MaxSpeed     // float64 - maximum speed (150)\ntank.ViewRange    // float64 - sight range (200)\n```\n\n### Game State Information\n\nYour AI can access global game information:\n\n```go\n// All tanks in the game\ngameState.Tanks         // []*Tank - all tanks (including yours)\ngameState.Projectiles   // []*Projectile - all active projectiles\n\n// Arena information\ngameState.ArenaWidth    // float64 - arena width (1024)\ngameState.ArenaHeight   // float64 - arena height (512)\ngameState.GameTime      // float64 - elapsed game time\n\n// Utility methods\ngameState.GetAliveTanks()                    // Get only living tanks\ngameState.IsValidPosition(pos, radius)       // Check if position is valid\n```\n\n## 📝 Simple AI Example\n\nHere's a basic AI that moves forward and shoots at the nearest enemy:\n\n```go\npackage ai\n\nimport (\n    \"math\"\n    \"tank-game/lib/game\"\n)\n\ntype SimpleAI struct {\n    name string\n}\n\nfunc NewSimpleAI() *SimpleAI {\n    return \u0026SimpleAI{name: \"Simple AI\"}\n}\n\nfunc (ai *SimpleAI) GetName() string {\n    return ai.name\n}\n\nfunc (ai *SimpleAI) Initialize(tank *game.Tank, gameState *game.GameState) error {\n    return nil\n}\n\nfunc (ai *SimpleAI) Update(tank *game.Tank, gameState *game.GameState, commands *game.Commands) error {\n    // Always move forward\n    commands.MoveForward = true\n    \n    // Find nearest enemy\n    nearestEnemy := ai.findNearestEnemy(tank, gameState)\n    if nearestEnemy != nil {\n        // Calculate angle to enemy\n        dx := nearestEnemy.Position.X - tank.Position.X\n        dy := nearestEnemy.Position.Y - tank.Position.Y\n        targetAngle := math.Atan2(dy, dx)\n        \n        // Calculate angle difference\n        angleDiff := targetAngle - tank.Rotation\n        \n        // Normalize angle (-π to π)\n        for angleDiff \u003e math.Pi {\n            angleDiff -= 2 * math.Pi\n        }\n        for angleDiff \u003c -math.Pi {\n            angleDiff += 2 * math.Pi\n        }\n        \n        // Turn towards enemy\n        if angleDiff \u003e 0.1 {\n            commands.TurnRight = true\n        } else if angleDiff \u003c -0.1 {\n            commands.TurnLeft = true\n        }\n        \n        // Fire if aimed at enemy\n        if math.Abs(angleDiff) \u003c 0.2 {\n            commands.Fire = true\n        }\n    }\n    \n    return nil\n}\n\nfunc (ai *SimpleAI) findNearestEnemy(myTank *game.Tank, gameState *game.GameState) *game.Tank {\n    var nearest *game.Tank\n    minDistance := math.MaxFloat64\n    \n    for _, tank := range gameState.Tanks {\n        if tank == myTank || !tank.IsAlive {\n            continue\n        }\n        \n        dx := tank.Position.X - myTank.Position.X\n        dy := tank.Position.Y - myTank.Position.Y\n        distance := math.Sqrt(dx*dx + dy*dy)\n        \n        if distance \u003c minDistance {\n            minDistance = distance\n            nearest = tank\n        }\n    }\n    \n    return nearest\n}\n```\n\n## 🧠 Advanced AI Example\n\nHere's a more sophisticated AI with projectile dodging and tactical positioning:\n\n```go\npackage ai\n\nimport (\n    \"math\"\n    \"tank-game/lib/common\"\n    \"tank-game/lib/game\"\n)\n\ntype AdvancedAI struct {\n    name            string\n    lastDodgeTime   float64\n    targetPosition  *common.Vector2\n    patrolRadius    float64\n}\n\nfunc NewAdvancedAI() *AdvancedAI {\n    return \u0026AdvancedAI{\n        name:         \"Advanced AI\",\n        patrolRadius: 150.0,\n    }\n}\n\nfunc (ai *AdvancedAI) GetName() string {\n    return ai.name\n}\n\nfunc (ai *AdvancedAI) Initialize(tank *game.Tank, gameState *game.GameState) error {\n    // Set initial patrol center\n    ai.targetPosition = \u0026common.Vector2{\n        X: tank.Position.X,\n        Y: tank.Position.Y,\n    }\n    return nil\n}\n\nfunc (ai *AdvancedAI) Update(tank *game.Tank, gameState *game.GameState, commands *game.Commands) error {\n    // Priority 1: Dodge incoming projectiles\n    if ai.shouldDodge(tank, gameState) {\n        ai.performDodge(tank, gameState, commands)\n        ai.lastDodgeTime = gameState.GameTime\n        return nil\n    }\n    \n    // Priority 2: Attack nearest enemy\n    nearestEnemy := ai.findNearestEnemy(tank, gameState)\n    if nearestEnemy != nil \u0026\u0026 ai.getDistance(tank.Position, nearestEnemy.Position) \u003c tank.ViewRange {\n        ai.attackEnemy(tank, nearestEnemy, commands)\n        return nil\n    }\n    \n    // Priority 3: Tactical positioning\n    ai.tacticalMovement(tank, gameState, commands)\n    \n    return nil\n}\n\nfunc (ai *AdvancedAI) shouldDodge(tank *game.Tank, gameState *game.GameState) bool {\n    // Don't dodge too frequently\n    if gameState.GameTime-ai.lastDodgeTime \u003c 1.0 {\n        return false\n    }\n    \n    // Check for incoming projectiles\n    for _, projectile := range gameState.Projectiles {\n        if !projectile.IsActive {\n            continue\n        }\n        \n        // Calculate if projectile is heading towards us\n        distance := ai.getDistance(tank.Position, projectile.Position)\n        if distance \u003c 100 { // Danger zone\n            // Predict projectile path\n            futurePos := common.Vector2{\n                X: projectile.Position.X + projectile.Velocity.X*0.5,\n                Y: projectile.Position.Y + projectile.Velocity.Y*0.5,\n            }\n            \n            if ai.getDistance(tank.Position, futurePos) \u003c 30 {\n                return true\n            }\n        }\n    }\n    \n    return false\n}\n\nfunc (ai *AdvancedAI) performDodge(tank *game.Tank, gameState *game.GameState, commands *game.Commands) {\n    // Find safest direction to dodge\n    bestAngle := tank.Rotation + math.Pi/2 // Default: turn 90 degrees\n    \n    // Check multiple dodge directions\n    for angle := 0.0; angle \u003c 2*math.Pi; angle += math.Pi / 4 {\n        testPos := common.Vector2{\n            X: tank.Position.X + math.Cos(angle)*50,\n            Y: tank.Position.Y + math.Sin(angle)*50,\n        }\n        \n        if ai.isPositionSafe(testPos, gameState) {\n            bestAngle = angle\n            break\n        }\n    }\n    \n    // Turn towards safe direction\n    angleDiff := bestAngle - tank.Rotation\n    ai.normalizeAngle(\u0026angleDiff)\n    \n    if angleDiff \u003e 0.1 {\n        commands.TurnRight = true\n    } else if angleDiff \u003c -0.1 {\n        commands.TurnLeft = true\n    }\n    \n    commands.MoveForward = true\n}\n\nfunc (ai *AdvancedAI) attackEnemy(tank *game.Tank, enemy *game.Tank, commands *game.Commands) {\n    distance := ai.getDistance(tank.Position, enemy.Position)\n    \n    // Maintain optimal combat distance\n    optimalDistance := 120.0\n    \n    if distance \u003e optimalDistance+20 {\n        // Too far - move closer\n        ai.moveTowards(tank, enemy.Position, commands)\n    } else if distance \u003c optimalDistance-20 {\n        // Too close - back away\n        commands.MoveBackward = true\n    }\n    \n    // Aim at enemy with prediction\n    predictedPos := ai.predictEnemyPosition(enemy, 0.3) // Predict 0.3 seconds ahead\n    ai.aimAt(tank, predictedPos, commands)\n    \n    // Fire if well-aimed\n    targetAngle := math.Atan2(predictedPos.Y-tank.Position.Y, predictedPos.X-tank.Position.X)\n    aimError := targetAngle - tank.Rotation\n    ai.normalizeAngle(\u0026aimError)\n    \n    if math.Abs(aimError) \u003c 0.15 \u0026\u0026 tank.CanFire() {\n        commands.Fire = true\n    }\n}\n\nfunc (ai *AdvancedAI) tacticalMovement(tank *game.Tank, gameState *game.GameState, commands *game.Commands) {\n    // Move to strategic position\n    centerX := gameState.ArenaWidth / 2\n    centerY := gameState.ArenaHeight / 2\n    \n    // Patrol around center with some randomness\n    patrolAngle := gameState.GameTime * 0.5 // Slow patrol\n    targetX := centerX + math.Cos(patrolAngle)*ai.patrolRadius\n    targetY := centerY + math.Sin(patrolAngle)*ai.patrolRadius\n    \n    targetPos := common.Vector2{X: targetX, Y: targetY}\n    ai.moveTowards(tank, targetPos, commands)\n}\n\nfunc (ai *AdvancedAI) moveTowards(tank *game.Tank, target common.Vector2, commands *game.Commands) {\n    targetAngle := math.Atan2(target.Y-tank.Position.Y, target.X-tank.Position.X)\n    angleDiff := targetAngle - tank.Rotation\n    ai.normalizeAngle(\u0026angleDiff)\n    \n    // Turn towards target\n    if angleDiff \u003e 0.1 {\n        commands.TurnRight = true\n    } else if angleDiff \u003c -0.1 {\n        commands.TurnLeft = true\n    }\n    \n    // Move forward if roughly facing target\n    if math.Abs(angleDiff) \u003c math.Pi/2 {\n        commands.MoveForward = true\n    }\n}\n\nfunc (ai *AdvancedAI) aimAt(tank *game.Tank, target common.Vector2, commands *game.Commands) {\n    targetAngle := math.Atan2(target.Y-tank.Position.Y, target.X-tank.Position.X)\n    angleDiff := targetAngle - tank.Rotation\n    ai.normalizeAngle(\u0026angleDiff)\n    \n    if angleDiff \u003e 0.05 {\n        commands.TurnRight = true\n    } else if angleDiff \u003c -0.05 {\n        commands.TurnLeft = true\n    }\n}\n\nfunc (ai *AdvancedAI) predictEnemyPosition(enemy *game.Tank, timeAhead float64) common.Vector2 {\n    return common.Vector2{\n        X: enemy.Position.X + enemy.Velocity.X*timeAhead,\n        Y: enemy.Position.Y + enemy.Velocity.Y*timeAhead,\n    }\n}\n\nfunc (ai *AdvancedAI) isPositionSafe(pos common.Vector2, gameState *game.GameState) bool {\n    // Check arena bounds\n    margin := 30.0\n    if pos.X \u003c margin || pos.X \u003e gameState.ArenaWidth-margin ||\n       pos.Y \u003c margin || pos.Y \u003e gameState.ArenaHeight-margin {\n        return false\n    }\n    \n    // Check for nearby projectiles\n    for _, projectile := range gameState.Projectiles {\n        if ai.getDistance(pos, projectile.Position) \u003c 40 {\n            return false\n        }\n    }\n    \n    return gameState.IsValidPosition(pos, 25.0)\n}\n\nfunc (ai *AdvancedAI) findNearestEnemy(myTank *game.Tank, gameState *game.GameState) *game.Tank {\n    var nearest *game.Tank\n    minDistance := math.MaxFloat64\n    \n    for _, tank := range gameState.Tanks {\n        if tank == myTank || !tank.IsAlive {\n            continue\n        }\n        \n        distance := ai.getDistance(myTank.Position, tank.Position)\n        if distance \u003c minDistance {\n            minDistance = distance\n            nearest = tank\n        }\n    }\n    \n    return nearest\n}\n\nfunc (ai *AdvancedAI) getDistance(pos1, pos2 common.Vector2) float64 {\n    dx := pos1.X - pos2.X\n    dy := pos1.Y - pos2.Y\n    return math.Sqrt(dx*dx + dy*dy)\n}\n\nfunc (ai *AdvancedAI) normalizeAngle(angle *float64) {\n    for *angle \u003e math.Pi {\n        *angle -= 2 * math.Pi\n    }\n    for *angle \u003c -math.Pi {\n        *angle += 2 * math.Pi\n    }\n}\n```\n\n## 🔧 Registering Your AI\n\nTo add your AI to the game:\n\n1. **Create your AI file** in the `ai/` directory (e.g., `ai/my_ai.go`)\n\n2. **Implement the AI interface** as shown in the examples above\n\n3. **Register your AI** in `ai/registry.go`:\n   ```go\n   func init() {\n       RegisterAI(\"example\", func() game.AI { return NewExampleAI() })\n       RegisterAI(\"example_2\", func() game.AI { return NewExampleAI2() })\n       RegisterAI(\"my_ai\", func() game.AI { return NewMyAI() })  // Add this line\n   }\n   ```\n\n4. **Run the game** - your AI will automatically be loaded and assigned a colored tank!\n\n## 🎯 AI Strategy Tips\n\n### Basic Strategies\n- **Aggressive**: Always move towards enemies and fire frequently\n- **Defensive**: Maintain distance and only engage when advantageous\n- **Evasive**: Focus on dodging and hit-and-run tactics\n\n### Advanced Techniques\n- **Projectile Prediction**: Calculate where enemies will be when your shot arrives\n- **Collision Avoidance**: Use `gameState.IsValidPosition()` for pathfinding\n- **Tactical Positioning**: Control key areas of the battlefield\n- **Resource Management**: Balance aggression with survival\n\n### Performance Considerations\n- Avoid expensive calculations in the `Update()` method (called 60 times per second)\n- Cache frequently used calculations\n- Use efficient algorithms for distance calculations and enemy detection\n\n## 🏆 Victory Conditions\n\nThe game ends when only one tank remains alive. Victory strategies include:\n\n- **Elimination**: Destroy all enemy tanks\n- **Survival**: Outlast opponents through superior tactics\n- **Positioning**: Control the battlefield and force enemies into disadvantageous positions\n\n## 🐛 Troubleshooting\n\n### Common Issues\n\n**Game won't start**: Ensure SDL3 is properly installed and `sdl3.dll` is in the project directory (Windows)\n\n**AI not appearing**: Check that your AI is registered in `ai/registry.go` and implements all required methods\n\n**Compilation errors**: Run `go mod tidy` to ensure all dependencies are installed\n\n**Tank gets stuck**: Use `gameState.IsValidPosition()` to check for valid movement positions\n\n### Debug Tips\n\n- Use `fmt.Printf()` in your AI's `Update()` method for debugging (remove before final submission)\n- Check tank health and position values to understand behavior\n- Monitor `gameState.GameTime` for time-based debugging\n\n---\n\n**Ready to create your AI?** Start with the simple example and gradually add more sophisticated behaviors. Good luck in the arena! 🚀\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpbwebmedia%2Ftank-game","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fpbwebmedia%2Ftank-game","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpbwebmedia%2Ftank-game/lists"}