This commit is contained in:
2026-04-02 00:12:02 +02:00
parent f8454d8950
commit 39e943b25e
3 changed files with 588 additions and 8 deletions

View File

@@ -36,6 +36,8 @@ public partial class MainWindow : Window
private readonly DigitalDojoApiClient _client;
private readonly ObservableCollection<string> _logEntries = [];
private readonly Dictionary<(int X, int Y), double> _enemyHeat = [];
private readonly Dictionary<(int X, int Y), double> _visitHeat = [];
private readonly Dictionary<(int X, int Y), double> _deathHeat = [];
private readonly Dictionary<string, int> _lastRadar = new(StringComparer.OrdinalIgnoreCase);
private readonly Dictionary<Direction, PeekEntitiesAsyncResponse> _lastPeek = [];
private readonly Dictionary<BotAction, DateTimeOffset> _lastUse = [];
@@ -65,9 +67,13 @@ public partial class MainWindow : Window
private DateTimeOffset _lastStatusAt = DateTimeOffset.MinValue;
private (int X, int Y)? _nearestEnemy;
private Direction _lastMoveDirection = Direction.North;
private Direction _escapeDirection = Direction.North;
private int _recentDamageTicks;
private int _survivalTicks;
private int _escapeLockTicks;
private bool _lastUnderPressure;
private int _pressureStreak;
private LevelProfile _currentLevelProfile = LevelProfile.Unknown;
public MainWindow()
{
@@ -234,6 +240,11 @@ public partial class MainWindow : Window
_survivalTicks--;
}
if (_escapeLockTicks > 0)
{
_escapeLockTicks--;
}
DecayBlockedDirections();
await PollTelemetryAsync(ct);
DecayHeat();
@@ -297,6 +308,7 @@ public partial class MainWindow : Window
_progress = stats.Level?.Progress ?? _progress;
_remainingTime = stats.Level?.Remainingtime ?? _remainingTime;
_levelName = stats.Level?.Name ?? _levelName;
UpdateLevelProfile(_levelName);
if (previousHealth > 0.1 && _currentHealth + 0.05 < previousHealth)
{
@@ -312,11 +324,15 @@ public partial class MainWindow : Window
_recentDeaths.Dequeue();
}
_survivalTicks = Math.Max(_survivalTicks, 180 + _recentDeaths.Count * 30);
_survivalTicks = Math.Max(_survivalTicks, 24 + _recentDeaths.Count * 4);
_escapeLockTicks = Math.Max(_escapeLockTicks, 8);
_escapeDirection = Opposite(_lastMoveDirection);
_pressureStreak = 0;
_x = 0;
_y = 0;
_enemyHeat.Clear();
_nearestEnemy = null;
MarkDeathZone(_x, _y);
_sessionLogger?.LogEvent("death", $"death_count={_deaths};death_window_90s={_recentDeaths.Count}");
}
@@ -330,7 +346,7 @@ public partial class MainWindow : Window
_levelName,
_x,
_y,
$"survival_ticks={_survivalTicks};damage_ticks={_recentDamageTicks}");
$"survival_ticks={_survivalTicks};damage_ticks={_recentDamageTicks};escape_lock={_escapeLockTicks};pressure_streak={_pressureStreak}");
}
catch (Exception ex)
{
@@ -420,6 +436,7 @@ public partial class MainWindow : Window
private BotDecision? BuildDecision()
{
var hpRatio = _maxHealth > 0.1 ? _currentHealth / _maxHealth : 1.0;
var profile = _currentLevelProfile;
var immediateDir = _lastPeek
.Where(x => x.Value.Executed && x.Value.PlayersInSight > 0 && x.Value.SightedPlayerDistance == 1)
@@ -432,10 +449,22 @@ public partial class MainWindow : Window
closeThreats++;
}
var underPressure = hpRatio < 0.58 || _recentDamageTicks > 0 || closeThreats >= 2 || _survivalTicks > 0;
if (hpRatio < 0.75 || _recentDamageTicks > 0 || closeThreats >= 2)
{
_pressureStreak = Math.Min(_pressureStreak + 1, 12);
}
else
{
_pressureStreak = Math.Max(_pressureStreak - 1, 0);
}
var underPressure = hpRatio < PressureHpThreshold(profile) || _recentDamageTicks > 0 || closeThreats >= PressureThreatThreshold(profile) || _survivalTicks > 0 || _pressureStreak >= 2;
_lastUnderPressure = underPressure;
if (Ready(BotAction.Special) && closeThreats >= 2)
var specialThreatThreshold = SpecialThreatThreshold(profile);
var specialHpFloor = SpecialHpFloor(profile);
if (Ready(BotAction.Special) && closeThreats >= specialThreatThreshold && (hpRatio >= specialHpFloor || closeThreats >= specialThreatThreshold + 1))
{
return new BotDecision(
"specialattack",
@@ -448,7 +477,7 @@ public partial class MainWindow : Window
});
}
if (immediateDir.HasValue && !underPressure && Ready(BotAction.Hit))
if (immediateDir.HasValue && Ready(BotAction.Hit) && ShouldUseImmediateHit(profile, hpRatio, closeThreats, underPressure))
{
var dir = immediateDir.Value;
return new BotDecision(
@@ -462,11 +491,11 @@ public partial class MainWindow : Window
});
}
if (immediateDir.HasValue && Ready(BotAction.Move))
if (immediateDir.HasValue && Ready(BotAction.Move) && ShouldRetreatOnImmediate(profile, hpRatio, closeThreats))
{
var retreatDirection = Opposite(immediateDir.Value);
if (Ready(BotAction.Dash) && (hpRatio < 0.40 || _survivalTicks > 0))
if (Ready(BotAction.Dash) && (hpRatio < DashHpThreshold(profile) || _pressureStreak >= 3 || _survivalTicks > 0))
{
return new BotDecision(
"dash-retreat",
@@ -478,6 +507,8 @@ public partial class MainWindow : Window
if (response.Executed)
{
ApplyMovement(retreatDirection, Math.Max(response.BlocksDashed, 1));
_escapeDirection = retreatDirection;
_escapeLockTicks = Math.Max(_escapeLockTicks, EscapeLockTicks(profile));
}
return response.Executed;
@@ -496,6 +527,8 @@ public partial class MainWindow : Window
if (moved)
{
ApplyMovement(retreatDirection, 1);
_escapeDirection = retreatDirection;
_escapeLockTicks = Math.Max(_escapeLockTicks, EscapeLockTicks(profile));
}
return response.Executed;
@@ -558,6 +591,11 @@ public partial class MainWindow : Window
if (moved)
{
ApplyMovement(moveDirection, 1);
if (underPressure)
{
_escapeDirection = moveDirection;
_escapeLockTicks = Math.Max(_escapeLockTicks, EscapeLockTicks(profile));
}
}
return response.Executed;
@@ -569,6 +607,14 @@ public partial class MainWindow : Window
private Direction GetBestMoveDirection(bool chase)
{
if (!chase && _escapeLockTicks > 0)
{
if (!_blockedDirectionTicks.TryGetValue(_escapeDirection, out var blocked) || blocked <= 0)
{
return _escapeDirection;
}
}
var scored = new Dictionary<Direction, double>
{
[Direction.North] = RadarScore(Direction.North),
@@ -615,6 +661,20 @@ public partial class MainWindow : Window
}
}
var visitPenalty = VisitHeatFor(dir);
var deathPenalty = DeathHeatFor(dir);
if (_currentLevelProfile == LevelProfile.BiggerMap)
{
score -= visitPenalty * 1.4;
}
else
{
score -= visitPenalty * 0.8;
}
score -= deathPenalty * 1.6;
if (_survivalTicks > 0 && _nearestEnemy.HasValue)
{
var safest = Opposite(DirectionFromVector(_nearestEnemy.Value.X, _nearestEnemy.Value.Y));
@@ -624,6 +684,18 @@ public partial class MainWindow : Window
}
}
if (_escapeLockTicks > 0)
{
if (dir == _escapeDirection)
{
score += 4.5;
}
else if (dir == Opposite(_escapeDirection))
{
score -= 4.0;
}
}
if (_blockedDirectionTicks.TryGetValue(dir, out var blockedTicks) && blockedTicks > 0)
{
score -= 5.0 + blockedTicks * 0.4;
@@ -690,6 +762,8 @@ public partial class MainWindow : Window
{
if (_enemyHeat.Count == 0)
{
DecaySpatialHeat(_visitHeat, 0.94, 0.15);
DecaySpatialHeat(_deathHeat, 0.97, 0.10);
return;
}
@@ -702,6 +776,9 @@ public partial class MainWindow : Window
_enemyHeat.Remove(key);
}
}
DecaySpatialHeat(_visitHeat, 0.94, 0.15);
DecaySpatialHeat(_deathHeat, 0.97, 0.10);
}
private void ApplyMovement(Direction direction, int steps)
@@ -710,6 +787,7 @@ public partial class MainWindow : Window
_x += dx * steps;
_y += dy * steps;
AddHeat(_x, _y, -2.5);
MarkVisit(_x, _y, 1.0);
}
private void AddHeat(int worldX, int worldY, double value)
@@ -764,6 +842,151 @@ public partial class MainWindow : Window
};
}
private void UpdateLevelProfile(string? levelName)
{
var newProfile = ResolveLevelProfile(levelName);
if (newProfile == _currentLevelProfile)
{
return;
}
_currentLevelProfile = newProfile;
_sessionLogger?.LogEvent("level-profile", $"level={levelName ?? "unknown"};profile={newProfile}");
}
private static LevelProfile ResolveLevelProfile(string? levelName)
{
var value = levelName?.Trim().ToLowerInvariant() ?? string.Empty;
if (value.Contains("bigger")) return LevelProfile.BiggerMap;
if (value.Contains("more bots")) return LevelProfile.MoreBots;
if (value.Contains("new bots")) return LevelProfile.NewBots;
if (value.Contains("default")) return LevelProfile.Default;
return LevelProfile.Unknown;
}
private double PressureHpThreshold(LevelProfile profile) => profile switch
{
LevelProfile.BiggerMap => 0.66,
LevelProfile.MoreBots => 0.62,
LevelProfile.NewBots => 0.68,
LevelProfile.Default => 0.58,
_ => 0.60,
};
private int PressureThreatThreshold(LevelProfile profile) => profile switch
{
LevelProfile.BiggerMap => 2,
LevelProfile.MoreBots => 2,
LevelProfile.NewBots => 2,
LevelProfile.Default => 2,
_ => 2,
};
private int SpecialThreatThreshold(LevelProfile profile) => profile switch
{
LevelProfile.MoreBots => 4,
LevelProfile.NewBots => 3,
LevelProfile.BiggerMap => 2,
LevelProfile.Default => 2,
_ => 2,
};
private double SpecialHpFloor(LevelProfile profile) => profile switch
{
LevelProfile.MoreBots => 0.78,
LevelProfile.NewBots => 0.55,
LevelProfile.BiggerMap => 0.42,
LevelProfile.Default => 0.35,
_ => 0.40,
};
private double DashHpThreshold(LevelProfile profile) => profile switch
{
LevelProfile.BiggerMap => 0.50,
LevelProfile.NewBots => 0.58,
LevelProfile.MoreBots => 0.40,
LevelProfile.Default => 0.30,
_ => 0.45,
};
private int EscapeLockTicks(LevelProfile profile) => profile switch
{
LevelProfile.BiggerMap => 8,
LevelProfile.NewBots => 9,
LevelProfile.MoreBots => 6,
LevelProfile.Default => 5,
_ => 6,
};
private bool ShouldUseImmediateHit(LevelProfile profile, double hpRatio, int closeThreats, bool underPressure) => profile switch
{
LevelProfile.Default => hpRatio >= 0.22 && closeThreats <= 2,
LevelProfile.BiggerMap => hpRatio >= 0.25 && closeThreats <= 2,
LevelProfile.MoreBots => hpRatio >= 0.35 && closeThreats <= 3,
LevelProfile.NewBots => !underPressure && hpRatio >= 0.50,
_ => hpRatio >= 0.30 && closeThreats <= 2,
};
private bool ShouldRetreatOnImmediate(LevelProfile profile, double hpRatio, int closeThreats) => profile switch
{
LevelProfile.Default => hpRatio < 0.22 || closeThreats >= 3,
LevelProfile.BiggerMap => hpRatio < 0.30 || closeThreats >= 3,
LevelProfile.MoreBots => hpRatio < 0.32 || closeThreats >= 3,
LevelProfile.NewBots => hpRatio < 0.68 || closeThreats >= 2,
_ => hpRatio < 0.30 || closeThreats >= 3,
};
private void MarkVisit(int x, int y, double amount)
{
var key = (x, y);
_visitHeat.TryGetValue(key, out var current);
_visitHeat[key] = Math.Min(current + amount, 20);
}
private void MarkDeathZone(int x, int y)
{
for (var dx = -1; dx <= 1; dx++)
{
for (var dy = -1; dy <= 1; dy++)
{
var key = (x + dx, y + dy);
_deathHeat.TryGetValue(key, out var current);
_deathHeat[key] = Math.Min(current + (dx == 0 && dy == 0 ? 4.0 : 1.5), 12);
}
}
}
private static void DecaySpatialHeat(Dictionary<(int X, int Y), double> heatMap, double decay, double minimum)
{
if (heatMap.Count == 0)
{
return;
}
foreach (var key in heatMap.Keys.ToArray())
{
heatMap[key] *= decay;
if (heatMap[key] < minimum)
{
heatMap.Remove(key);
}
}
}
private double VisitHeatFor(Direction direction)
{
var (dx, dy) = Delta(direction);
var key = (_x + dx, _y + dy);
return _visitHeat.TryGetValue(key, out var heat) ? heat : 0;
}
private double DeathHeatFor(Direction direction)
{
var (dx, dy) = Delta(direction);
var key = (_x + dx, _y + dy);
return _deathHeat.TryGetValue(key, out var heat) ? heat : 0;
}
private bool Ready(BotAction action)
{
if (!_lastUse.TryGetValue(action, out var time))
@@ -794,10 +1017,15 @@ public partial class MainWindow : Window
_nearestEnemy = null;
_recentDamageTicks = 0;
_survivalTicks = 0;
_escapeLockTicks = 0;
_lastUnderPressure = false;
_lastMoveDirection = Direction.North;
_escapeDirection = Direction.North;
_pressureStreak = 0;
_enemyHeat.Clear();
_visitHeat.Clear();
_deathHeat.Clear();
_lastRadar.Clear();
_lastPeek.Clear();
_lastUse.Clear();
@@ -819,7 +1047,7 @@ public partial class MainWindow : Window
$"Level: {_levelName} | Kills: {_kills} | Deaths: {_deaths} | K/D: {kdr} | " +
$"HP: {_currentHealth.ToString("0.0", CultureInfo.InvariantCulture)}/{_maxHealth.ToString("0.0", CultureInfo.InvariantCulture)} ({hpPercent.ToString("0", CultureInfo.InvariantCulture)}%) | " +
$"Progress: {_progress.ToString("0.0", CultureInfo.InvariantCulture)}% | Remaining: {_remainingTime.ToString("0.00", CultureInfo.InvariantCulture)} min | " +
$"Pos (estimated): ({_x}, {_y}) | SurvivalMode: {(_survivalTicks > 0 ? "ON" : "OFF")}";
$"Pos (estimated): ({_x}, {_y}) | Profile: {_currentLevelProfile} | SurvivalMode: {(_survivalTicks > 0 ? "ON" : "OFF")}";
var nearest = _nearestEnemy.HasValue ? $"({_nearestEnemy.Value.X}, {_nearestEnemy.Value.Y})" : "none";
var radar = _lastRadar.Count == 0
@@ -955,6 +1183,15 @@ public partial class MainWindow : Window
string Reason,
Func<CancellationToken, Task<bool>> Execute);
private enum LevelProfile
{
Unknown,
Default,
BiggerMap,
MoreBots,
NewBots,
}
private enum Direction
{
North = 0,

View File

@@ -32,6 +32,11 @@ dotnet run --project /home/tikaiz/RiderProjects/digitalDojo/DDApp/DDApplication/
## Notes
- Position and map are inferred from your own movement + sensor calls (not an authoritative server map).
- The strategy is level-aware:
- `Default Level`: balanced combat with short escape commitments
- `Bigger Map Level`: more scouting and stronger anti-loop exploration
- `More Bots Level`: safer special-attack usage and tighter targeting
- `New Bots Level`: more ranged pressure and less chasing of teleporting targets
- The strategy is heuristic and tunable; it is designed for high kill throughput while respecting API cooldowns.
- Session logs are written to `~/.local/share/DDApplication/logs` on Linux:
- `*.events.csv` contains timestamped telemetry, decisions, and events

View File

@@ -0,0 +1,338 @@
Digital Dojo <https://dd.countit.at/> Menü //
* //Coden lernen<https://dd.countit.at/programmieren-lernen>
o //Programmier-Roadmap <https://dd.countit.at/programmieren-lernen>
o //Programmierschule <https://dd.countit.at/programmierschule>
o //Übungsräume <https://dd.countit.at/dojos>
o //Katas <https://dd.countit.at/katas>
o //Tutorials <https://dd.countit.at/tutorials>
* //Dojo Game<https://dd.countit.at/dojo-game/multiplayer-modus>
o //Besiege unseren Bot <https://dd.countit.at/dojo-game>
o //Spieleinstieg <https://dd.countit.at/dojo-game/spieleinstieg>
o //Levels & Bots <https://dd.countit.at/dojo-game/levels>
o //Leaderboard <https://dd.countit.at/dojo-game/leaderboard>
o //Multiplayer Modus <https://dd.countit.at/dojo-game/
multiplayer-modus>
o //Tipps <https://dd.countit.at/dojo-game/tipps>
* //Programmier-Challenge <https://dd.countit.at/programmierwettbewerb>
* //Bewerben <https://dd.countit.at/bewerben>
* //Feedback <https://dd.countit.at/feedback>
* // <#>
Ausloggen
/
/
/
/
//Teilen //Facebook <https://www.facebook.com/sharer/sharer.php?
u=https%3A%2F%2Fdd.countit.at%2Fdojo-game%2Flevels> //Instagram
<https://www.instagram.com/count_it_group/> //LinkedIn <https://
www.linkedin.com/shareArticle?
mini=true&url=https%3A%2F%2Fdd.countit.at%2Fdojo-
game%2Flevels&title=&summary=&source=> //E-Mail
<mailto:m.mustermann@countit.at?subject=Lese-
Tipp%3A%20Dojo%20Game%20%7C%20%C3%9Cbersicht%20der%20Levels%20%26%20Bots&body=Hey%2C%0D%0A%0D%0Aich%20habe%20auf%20https%3A%2F%2Fkarriere.countit.at%20einen%20Beitrag%20gefunden%2C%20der%20dich%20interessieren%20k%C3%B6nnte%3A%0D%0A%22Dojo%20Game%20%7C%20%C3%9Cbersicht%20der%20Levels%20%26%20Bots%22%0D%0ASchau%20ihn%20dir%20mal%20an%3A%20https%3A%2F%2Fkarriere.countit.at%2Fdojo-game%2Flevels%3Fkaid%3Dsharemail%0D%0A%0D%0ABeste%20Gr%C3%BC%C3%9Fe>
Übersicht der Levels & Bots
Dojo Game
//Dojo Game | Levelübersicht
------------------------------------------------------------------------
Im Folgenden findest du wichtige Infos und Eckdaten zu den einzelnen
Levels, welche im Spiel implementiert sind. Bestimmte Informationen
können sich unter den einzelnen Levels unterscheiden, daher ist es
wichtig, in deinem Algorithmus auf diese Attribute einzugehen.
Einen Einblick in die verschiedenen Bot-Typen findest du hier. <https://
dd.countit.at/dojo-game/levels#bots>
//1. Default Level
Das Default Level ist das erste Level und gleichzeitig auch das
Einsteiger-Level im Dojo Game.
Während der Laufzeit des Spiels wird jeder Gegner und auch dein Ritter,
sobald dieser getötet wird, sofort an einer anderen Stelle des
Spielfelds neu geboren. Nach Ablauf der Zeit wird das Spiel automatisch
beendet und die Kills und Deaths dieses Spiels dem Leaderboard
hinzugefügt. Danach kann direkt ein neues Spiel erstellt werden.
Generell ist es möglich, mehrere Gegner auf einmal zu schlagen. Stehen 2
Spieler auf demselben Block oder ineinander, so wird beiden gleich viel
Schaden zugefügt.
*Spielfeldgröße:* 15x15
*Bots:* (4) Default Bot x2, Tank Bot x2
*Dauer des Spiels:* erfolgreicher Abschluss des Levels oder 15 Minuten
*Erfolgreicher Abschluss:* 20 Kills
*Cooldowns:* Move = 250, Hit = 250, Radar = 250, SpecialAttack = 5000,
Peek = 1000, Scan = 2000, Dash = 3000, Teleport = 20000, Shoot = 1000
//2. Bigger Map Level
Im 2. Level des Games vergrößert sich die Spielfläche und die Default
Bots werden mehr!
Dieses Level wird nach 15 Minuten beendet. Wenn du nach Ablauf der Zeit
100% Progress hast, wirst du ins nächste Level weitergeleitet.
Während der Laufzeit des Spiels wird jeder Gegner und auch dein Ritter,
sobald dieser getötet wird, sofort an einer anderen Stelle des
Spielfelds neu geboren. Nach Ablauf der Zeit wird das Spiel automatisch
beendet und die Kills und Deaths dieses Spiels dem Leaderboard
hinzugefügt. Danach kann direkt ein neues Spiel erstellt werden.
Generell ist es möglich, mehrere Gegner auf einmal zu schlagen. Stehen 2
Spieler auf demselben Block oder ineinander, so wird beiden gleich viel
Schaden zugefügt.
*Spielfeldgröße:* 25x25
*Bots:* (5) Default Bot x5
*Dauer des Spiels:* 15 Minuten
*Erfolgreicher Abschluss:* 5 Kills
Cooldowns: Move = 250, Hit = 250, Radar = 250, SpecialAttack = 5000,
Peek = 1000, Scan = 2000, Dash = 3000, Teleport = 20000, Shoot = 1000
//3. More Bots Level
In diesem Level kämpfst du gegen 6 Tank Bots - pass auf, der Radius der
Specialattack ist in diesem Level von 3 Blöcken auf 1 Block geschrumpft!
Während der Laufzeit des Spiels wird jeder Gegner und auch dein Ritter,
sobald dieser getötet wird, sofort an einer anderen Stelle des
Spielfelds neu geboren. Nach Ablauf der Zeit wird das Spiel automatisch
beendet und die Kills und Deaths dieses Spiels dem Leaderboard
hinzugefügt. Danach kann direkt ein neues Spiel erstellt werden.
Generell ist es möglich, mehrere Gegner auf einmal zu schlagen. Stehen 2
Spieler auf demselben Block oder ineinander, so wird beiden gleich viel
Schaden zugefügt.
*Spielfeldgröße:* 25x25
*Bots:* (6) Tank Bot x6
*Dauer des Spiels: *15 Minuten oder erfolgreicher Abschluss des Levels
*Erfolgreicher Abschluss:* 10 Kills
Cooldowns: Move = 250, Hit = 250, Radar = 250, SpecialAttack = 5000,
Peek = 1000, Scan = 2000, Dash = 3000, Teleport = 20000, Shoot = 1000
//4. New Bots Level
Hier kämpfst du gegen 5 Psy Bots, welche mit einer neuen Fähigkeit
ausgestattet wurden.
Während der Laufzeit des Spiels wird jeder Gegner und auch dein Ritter,
sobald dieser getötet wird, sofort an einer anderen Stelle des
Spielfelds neu geboren. Nach Ablauf der Zeit wird das Spiel automatisch
beendet und die Kills und Deaths dieses Spiels dem Leaderboard
hinzugefügt. Danach kann direkt ein neues Spiel erstellt werden.
Generell ist es möglich, mehrere Gegner auf einmal zu schlagen. Stehen 2
Spieler auf demselben Block oder ineinander, so wird beiden gleich viel
Schaden zugefügt.
*Spielfeldgröße:* 15x15
*Bots:* (5) Psy Bot x5
*Dauer des Spiels: *15 Minuten
*Erfolgreicher Abschluss:* 10 Kills
Cooldowns: Move = 250, Hit = 250, Radar = 250, SpecialAttack = 5000,
Peek = 1000, Scan = 2000, Dash = 3000, Teleport = 20000, Shoot = 1000
//Übersicht der Bots
------------------------------------------------------------------------
In den Dojo Game Levels sind verschiedene Bot-Typen vorhanden. Jeder Bot
hat eine individuelle Fähigkeit und eigene Attribute, welche ihn
einzigartig machen. Hier findest du eine Liste der Bots und ihren Eckdaten.
//The Default Bot
Der Default Bot hat die selben Rahmenbedingungen wie ein echter Spieler.
Dies macht ihn, die Werte betreffend, gleich stark wie einen Spieler.
Sie unterscheiden sich nur in deren Implementierung.
*Lebenspunkte beim Start:* 10.0
*Maximale Lebenspunkte:* 10.0
*Einfacher Schaden:* 3
*Special-Attack:* 3 Blöcke Rundumschlag mit einfachem Schaden
//The Tank Bot
Der Tank Bot ist ein auf den ersten Blick schwächer erscheinender Bot,
welcher aber mit ansteigender Spieldauer immer stärker wird.
*Lebenspunkte beim Start:* 5.0
*Maximale Lebenspunkte:* 10.0
*Einfacher Schaden:* 3
*Special-Attack:* +1 Lebenspunkt zusätzlich und 3 Blöcke Rundumschlag
mit einfachem Schaden
//The Psy Bot
Der Psy Bot verhält sich gleich wie der Default Bot, jedoch
unterscheidet er sich deutlich von diesem durch seinen Special-Attack.
Dieser hat nämlich die Fähigkeit, sich beim Erhalten von Schaden oder
alle 5 Sekunden seinen Standort zu ändern und sich an eine zufällige
Position zu teleportieren.
*Lebenspunkte beim Start:* 10.0
*Maximale Lebenspunkte: *10.0
*Einfacher Schaden:* 3
*Special-Attack:* Standort ändern an einen zufälligen Ort am Spielfeld
Los geht's mit dem Dojo-Game!
Erster Platz am Leaderboard? Klingt genial!
Dojo-Game //
<https://dd.countit.at/dojo-game>
/
/
Programmier-Challenge
Stell dich der Programmier-Challenge und miss dich mit deinen
Klassenkolleg*innen.
Jetzt teilnehmen! // <https://dd.countit.at/programmierwettbewerb>
/
/
Ultimative Coding-Roadmap
Unsere Roadmap weist dir den Weg zum Coding-Profi!
Mehr erfahren // <https://dd.countit.at/programmieren-lernen>
/
/
Bewerbung bei COUNT IT
Starte deine Karriere als Softwareentwickler*in bei COUNT IT.
Zum Formular! // <https://dd.countit.at/bewerben>
Über Digital Dojo
Das Digital Dojo ist der virtuelle Übungsraum von COUNT IT.
Angehende Programmierer*innen, Code-Neulinge, Wiedereinsteiger*innen und
Fortgeschrittene finden hier das nötige Rüstzeug für ihre Karriere.
Du möchtest deine Lehre bei COUNT IT starten? Dann bist du hier richtig
- besiege deine Gegner im Dojo Game und sichere dir deine Lehrstelle!
Inspire your career.
Navigation
Programmieren lernen <https://dd.countit.at/programmieren-lernen> News
<https://dd.countit.at/news>
Programmierschule <https://dd.countit.at/programmierschule> Partner
<https://dd.countit.at/partner>
Programmier-Challenge <https://dd.countit.at/programmierwettbewerb>
Dojo Game <https://dd.countit.at/dojo-game>
Datenschutz <https://www.countit.at/datenschutz> Karriere @ COUNT IT
<https://karriere.countit.at/>
Impressum <https://www.countit.at/impressum> COUNT IT
Softwarehouse <https://it.countit.at/>
Newsletter abonnieren
Der COUNT IT Newsletter liefert viermal jährlich interessante
Neuigkeiten über das Unternehmen. Gleich anfordern!
E-Mail-Adresse
Senden
// <https://de-de.facebook.com/COUNTITGroup/> // <https://
www.instagram.com/count_it_group/> // <https://de.linkedin.com/company/
count-it-group>
//
COUNT IT Group verwendet Cookies, um die Website bestmöglich an die
Bedürfnisse der User anpassen zu können.
* Google
* Microsoft
* Ahrefs
* Statistik
Akzeptieren
Individuelle EinstellungenIndividuelle Einstellungen ausblenden |
Datenschutz­erklärung <https://www.countit.at/datenschutz>
Google
Google Analytics und Optimize aggregiert Daten über unsere Besucher und
ihr Verhalten auf unserer Website. Wir nutzen diese Informationen zur
Verbesserung unserer Seite.
Microsoft
Microsoft aggregiert Daten über unsere Besucher und ihr Verhalten auf
unserer Website. Wir nutzen diese Informationen zur Verbesserung unserer
Seite.
Ahrefs
Ahrefs aggregiert Daten über unsere Besucher und ihr Verhalten auf
unserer Website. Wir nutzen diese Informationen zur Verbesserung unserer
Seite.
Statistik
Es werden grundlegend notwendige, anonymisierte Userdaten aufgezeichnet,
welche nur von uns für Auswertungen verwendet werden!
Cookie Entscheidung speichern