added First bot with logging
This commit is contained in:
221
DDApp/DDApplication/BotSessionLogger.cs
Normal file
221
DDApp/DDApplication/BotSessionLogger.cs
Normal file
@@ -0,0 +1,221 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Globalization;
|
||||||
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
namespace DDApplication;
|
||||||
|
|
||||||
|
internal sealed class BotSessionLogger : IDisposable
|
||||||
|
{
|
||||||
|
private readonly object _gate = new();
|
||||||
|
private readonly DateTimeOffset _startedAt = DateTimeOffset.UtcNow;
|
||||||
|
private readonly Dictionary<string, int> _actionAttempts = new(StringComparer.OrdinalIgnoreCase);
|
||||||
|
private readonly Dictionary<string, int> _actionSuccess = new(StringComparer.OrdinalIgnoreCase);
|
||||||
|
|
||||||
|
private StreamWriter? _eventsWriter;
|
||||||
|
private bool _disposed;
|
||||||
|
|
||||||
|
public string SessionId { get; } = Guid.NewGuid().ToString("N", CultureInfo.InvariantCulture);
|
||||||
|
public string DirectoryPath { get; }
|
||||||
|
public string EventsPath { get; }
|
||||||
|
public string SummaryPath { get; }
|
||||||
|
public string LatestSymlinkPath { get; }
|
||||||
|
|
||||||
|
public BotSessionLogger()
|
||||||
|
{
|
||||||
|
var baseDir = Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData);
|
||||||
|
DirectoryPath = Path.Combine(baseDir, "DDApplication", "logs");
|
||||||
|
Directory.CreateDirectory(DirectoryPath);
|
||||||
|
|
||||||
|
var stamp = DateTimeOffset.UtcNow.ToString("yyyyMMdd_HHmmss", CultureInfo.InvariantCulture);
|
||||||
|
EventsPath = Path.Combine(DirectoryPath, $"bot_{stamp}_{SessionId}.events.csv");
|
||||||
|
SummaryPath = Path.Combine(DirectoryPath, $"bot_{stamp}_{SessionId}.summary.txt");
|
||||||
|
LatestSymlinkPath = Path.Combine(DirectoryPath, "latest.log");
|
||||||
|
|
||||||
|
_eventsWriter = new StreamWriter(EventsPath, append: false, Encoding.UTF8) { AutoFlush = true };
|
||||||
|
_eventsWriter.WriteLine("timestamp_utc,event,label,executed,hp,max_hp,kills,deaths,pos_x,pos_y,pressure,details");
|
||||||
|
UpdateLatestSymlink();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void LogDecision(
|
||||||
|
string label,
|
||||||
|
bool executed,
|
||||||
|
double hp,
|
||||||
|
double maxHp,
|
||||||
|
int kills,
|
||||||
|
int deaths,
|
||||||
|
int x,
|
||||||
|
int y,
|
||||||
|
bool pressure,
|
||||||
|
string details)
|
||||||
|
{
|
||||||
|
lock (_gate)
|
||||||
|
{
|
||||||
|
if (_disposed || _eventsWriter is null)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Increment(_actionAttempts, label);
|
||||||
|
if (executed)
|
||||||
|
{
|
||||||
|
Increment(_actionSuccess, label);
|
||||||
|
}
|
||||||
|
|
||||||
|
_eventsWriter.WriteLine(string.Join(",",
|
||||||
|
Csv(DateTimeOffset.UtcNow.ToString("O", CultureInfo.InvariantCulture)),
|
||||||
|
Csv("decision"),
|
||||||
|
Csv(label),
|
||||||
|
Csv(executed ? "1" : "0"),
|
||||||
|
Csv(hp.ToString("0.00", CultureInfo.InvariantCulture)),
|
||||||
|
Csv(maxHp.ToString("0.00", CultureInfo.InvariantCulture)),
|
||||||
|
Csv(kills.ToString(CultureInfo.InvariantCulture)),
|
||||||
|
Csv(deaths.ToString(CultureInfo.InvariantCulture)),
|
||||||
|
Csv(x.ToString(CultureInfo.InvariantCulture)),
|
||||||
|
Csv(y.ToString(CultureInfo.InvariantCulture)),
|
||||||
|
Csv(pressure ? "1" : "0"),
|
||||||
|
Csv(details)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void LogTelemetry(
|
||||||
|
double hp,
|
||||||
|
double maxHp,
|
||||||
|
int kills,
|
||||||
|
int deaths,
|
||||||
|
double progress,
|
||||||
|
double remaining,
|
||||||
|
string level,
|
||||||
|
int x,
|
||||||
|
int y,
|
||||||
|
string details)
|
||||||
|
{
|
||||||
|
lock (_gate)
|
||||||
|
{
|
||||||
|
if (_disposed || _eventsWriter is null)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
_eventsWriter.WriteLine(string.Join(",",
|
||||||
|
Csv(DateTimeOffset.UtcNow.ToString("O", CultureInfo.InvariantCulture)),
|
||||||
|
Csv("telemetry"),
|
||||||
|
Csv(level),
|
||||||
|
Csv(""),
|
||||||
|
Csv(hp.ToString("0.00", CultureInfo.InvariantCulture)),
|
||||||
|
Csv(maxHp.ToString("0.00", CultureInfo.InvariantCulture)),
|
||||||
|
Csv(kills.ToString(CultureInfo.InvariantCulture)),
|
||||||
|
Csv(deaths.ToString(CultureInfo.InvariantCulture)),
|
||||||
|
Csv(x.ToString(CultureInfo.InvariantCulture)),
|
||||||
|
Csv(y.ToString(CultureInfo.InvariantCulture)),
|
||||||
|
Csv(""),
|
||||||
|
Csv($"progress={progress:0.00};remaining={remaining:0.00};{details}")));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void LogEvent(string label, string details)
|
||||||
|
{
|
||||||
|
lock (_gate)
|
||||||
|
{
|
||||||
|
if (_disposed || _eventsWriter is null)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
_eventsWriter.WriteLine(string.Join(",",
|
||||||
|
Csv(DateTimeOffset.UtcNow.ToString("O", CultureInfo.InvariantCulture)),
|
||||||
|
Csv("event"),
|
||||||
|
Csv(label),
|
||||||
|
Csv(""),
|
||||||
|
Csv(""),
|
||||||
|
Csv(""),
|
||||||
|
Csv(""),
|
||||||
|
Csv(""),
|
||||||
|
Csv(""),
|
||||||
|
Csv(""),
|
||||||
|
Csv(""),
|
||||||
|
Csv(details)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void WriteSummaryAndDispose(double finalHp, double finalMaxHp, int finalKills, int finalDeaths)
|
||||||
|
{
|
||||||
|
lock (_gate)
|
||||||
|
{
|
||||||
|
if (_disposed)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var elapsed = DateTimeOffset.UtcNow - _startedAt;
|
||||||
|
var minutes = Math.Max(elapsed.TotalMinutes, 0.01);
|
||||||
|
var kd = finalDeaths == 0 ? finalKills : (double)finalKills / finalDeaths;
|
||||||
|
|
||||||
|
var lines = new List<string>
|
||||||
|
{
|
||||||
|
$"session={SessionId}",
|
||||||
|
$"started_utc={_startedAt:O}",
|
||||||
|
$"ended_utc={DateTimeOffset.UtcNow:O}",
|
||||||
|
$"duration_minutes={minutes:0.00}",
|
||||||
|
$"kills={finalKills}",
|
||||||
|
$"deaths={finalDeaths}",
|
||||||
|
$"kd={kd:0.000}",
|
||||||
|
$"kills_per_min={(finalKills / minutes):0.000}",
|
||||||
|
$"deaths_per_min={(finalDeaths / minutes):0.000}",
|
||||||
|
$"final_hp={finalHp:0.00}/{finalMaxHp:0.00}",
|
||||||
|
"actions="
|
||||||
|
};
|
||||||
|
|
||||||
|
foreach (var attempt in _actionAttempts.OrderBy(x => x.Key))
|
||||||
|
{
|
||||||
|
_actionSuccess.TryGetValue(attempt.Key, out var success);
|
||||||
|
var rate = attempt.Value == 0 ? 0 : (double)success / attempt.Value;
|
||||||
|
lines.Add($" {attempt.Key}: attempts={attempt.Value}, success={success}, rate={rate:0.000}");
|
||||||
|
}
|
||||||
|
|
||||||
|
File.WriteAllLines(SummaryPath, lines, Encoding.UTF8);
|
||||||
|
|
||||||
|
_eventsWriter?.Dispose();
|
||||||
|
_eventsWriter = null;
|
||||||
|
_disposed = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
WriteSummaryAndDispose(0, 0, 0, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void Increment(Dictionary<string, int> dict, string key)
|
||||||
|
{
|
||||||
|
dict.TryGetValue(key, out var current);
|
||||||
|
dict[key] = current + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static string Csv(string value)
|
||||||
|
{
|
||||||
|
var safe = value.Replace("\"", "\"\"");
|
||||||
|
return $"\"{safe}\"";
|
||||||
|
}
|
||||||
|
|
||||||
|
private void UpdateLatestSymlink()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (File.Exists(LatestSymlinkPath) || Directory.Exists(LatestSymlinkPath))
|
||||||
|
{
|
||||||
|
File.Delete(LatestSymlinkPath);
|
||||||
|
}
|
||||||
|
|
||||||
|
File.CreateSymbolicLink(LatestSymlinkPath, EventsPath);
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
// Best-effort only; logging should continue even if symlink creation fails.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -2,10 +2,47 @@
|
|||||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||||
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
|
mc:Ignorable="d" d:DesignWidth="1320" d:DesignHeight="860"
|
||||||
|
Width="1320" Height="860"
|
||||||
x:Class="DDApplication.MainWindow"
|
x:Class="DDApplication.MainWindow"
|
||||||
Title="DDApplication">
|
Title="Digital Dojo Bot Controller">
|
||||||
<Panel HorizontalAlignment="Center" VerticalAlignment="Center">
|
<Grid RowDefinitions="Auto,Auto,*,Auto" ColumnDefinitions="2*,2*,3*" Margin="12">
|
||||||
<Label>Welcome to Avalonia!</Label>
|
<StackPanel Grid.Row="0" Grid.Column="0" Grid.ColumnSpan="3" Orientation="Horizontal" Spacing="8">
|
||||||
</Panel>
|
<Button x:Name="StartButton" Content="Start Bot" Width="120"/>
|
||||||
|
<Button x:Name="StopButton" Content="Stop Bot" Width="120" IsEnabled="False"/>
|
||||||
|
<TextBlock Text="API Key:" VerticalAlignment="Center"/>
|
||||||
|
<TextBox x:Name="ApiKeyBox" Width="360" Watermark="GUID player token"/>
|
||||||
|
<TextBlock x:Name="StatusText" VerticalAlignment="Center" Text="Idle"/>
|
||||||
|
</StackPanel>
|
||||||
|
|
||||||
|
<Border Grid.Row="1" Grid.Column="0" Grid.ColumnSpan="3" Margin="0,8,0,8" Padding="8" BorderThickness="1" CornerRadius="6">
|
||||||
|
<SelectableTextBlock x:Name="StatsText" TextWrapping="Wrap" Text="Waiting for game state..." Focusable="True"/>
|
||||||
|
</Border>
|
||||||
|
|
||||||
|
<Border Grid.Row="2" Grid.Column="0" Margin="0,0,8,0" Padding="8" BorderThickness="1" CornerRadius="6">
|
||||||
|
<Grid RowDefinitions="Auto,*" RowSpacing="6">
|
||||||
|
<TextBlock Text="Bot Knowledge" FontWeight="Bold"/>
|
||||||
|
<ScrollViewer Grid.Row="1" HorizontalScrollBarVisibility="Auto" VerticalScrollBarVisibility="Auto">
|
||||||
|
<UniformGrid x:Name="KnowledgeGrid" Rows="21" Columns="21"/>
|
||||||
|
</ScrollViewer>
|
||||||
|
</Grid>
|
||||||
|
</Border>
|
||||||
|
|
||||||
|
<Border Grid.Row="2" Grid.Column="1" Margin="0,0,8,0" Padding="8" BorderThickness="1" CornerRadius="6">
|
||||||
|
<Grid RowDefinitions="Auto,Auto,*" RowSpacing="8">
|
||||||
|
<TextBlock Text="Decision + Cooldowns" FontWeight="Bold"/>
|
||||||
|
<TextBlock x:Name="DecisionText" Grid.Row="1" TextWrapping="Wrap" Text="No decision yet."/>
|
||||||
|
<TextBlock x:Name="CooldownText" Grid.Row="2" TextWrapping="Wrap"/>
|
||||||
|
</Grid>
|
||||||
|
</Border>
|
||||||
|
|
||||||
|
<Border Grid.Row="2" Grid.Column="2" Padding="8" BorderThickness="1" CornerRadius="6">
|
||||||
|
<Grid RowDefinitions="Auto,*" RowSpacing="6">
|
||||||
|
<TextBlock Text="Action Log" FontWeight="Bold"/>
|
||||||
|
<ListBox x:Name="LogList" Grid.Row="1"/>
|
||||||
|
</Grid>
|
||||||
|
</Border>
|
||||||
|
|
||||||
|
<TextBlock Grid.Row="3" Grid.Column="0" Grid.ColumnSpan="3" Margin="0,8,0,0" Text="Legend: P=bot, N=scan-nearest, *=high threat, +=medium threat, .=low threat" />
|
||||||
|
</Grid>
|
||||||
</Window>
|
</Window>
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -6,18 +6,17 @@ namespace DDApplication;
|
|||||||
|
|
||||||
internal class Program
|
internal class Program
|
||||||
{
|
{
|
||||||
public static IConfiguration Configuration { get; private set; } = null!;
|
public static IConfiguration Configuration { get; private set; } = new ConfigurationBuilder()
|
||||||
|
.AddJsonFile("appsettings.json", optional: true)
|
||||||
|
.AddUserSecrets<Program>(optional: true)
|
||||||
|
.AddEnvironmentVariables()
|
||||||
|
.Build();
|
||||||
// Initialization code. Don't use any Avalonia, third-party APIs or any
|
// Initialization code. Don't use any Avalonia, third-party APIs or any
|
||||||
// SynchronizationContext-reliant code before AppMain is called: things aren't initialized
|
// SynchronizationContext-reliant code before AppMain is called: things aren't initialized
|
||||||
// yet and stuff might break.
|
// yet and stuff might break.
|
||||||
[STAThread]
|
[STAThread]
|
||||||
public static int Main(string[] args)
|
public static int Main(string[] args)
|
||||||
{
|
{
|
||||||
Configuration = new ConfigurationBuilder()
|
|
||||||
.AddJsonFile("appsettings.json", optional: true)
|
|
||||||
.AddUserSecrets<Program>(optional: true)
|
|
||||||
.AddEnvironmentVariables()
|
|
||||||
.Build();
|
|
||||||
return BuildAvaloniaApp()
|
return BuildAvaloniaApp()
|
||||||
.StartWithClassicDesktopLifetime(args);
|
.StartWithClassicDesktopLifetime(args);
|
||||||
}
|
}
|
||||||
|
|||||||
42
DDApp/DDApplication/README.md
Normal file
42
DDApp/DDApplication/README.md
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
# Digital Dojo Bot Controller
|
||||||
|
|
||||||
|
This Avalonia app runs an autonomous bot for the Digital Dojo singleplayer API and visualizes both current game state and inferred enemy knowledge.
|
||||||
|
|
||||||
|
## What it does
|
||||||
|
|
||||||
|
- Starts/uses your current game session (`/api/game/{key}/create`, `/status`)
|
||||||
|
- Runs a cooldown-aware combat loop (`move`, `hit`, `shoot`, `specialattack`, `radar`, `scan`, `peek`, `dash`)
|
||||||
|
- Tries to maximize score by prioritizing fast damage actions when enemies are nearby
|
||||||
|
- Shows live stats (kills/deaths, HP, level progress, remaining time)
|
||||||
|
- Shows a local knowledge map:
|
||||||
|
- `P` = estimated player position
|
||||||
|
- `N` = nearest enemy from latest scan
|
||||||
|
- `* + .` = inferred enemy threat intensity
|
||||||
|
- Shows cooldown timers and action reasoning/logs
|
||||||
|
- Writes per-session analytics logs for post-run analysis
|
||||||
|
|
||||||
|
## Setup
|
||||||
|
|
||||||
|
Set your API key (GUID) in one of these ways:
|
||||||
|
|
||||||
|
1. Environment variable: `APIKEY`
|
||||||
|
2. User secrets (`Program` already loads user secrets)
|
||||||
|
3. Paste it directly into the UI text box before clicking **Start Bot**
|
||||||
|
|
||||||
|
## Run
|
||||||
|
|
||||||
|
```bash
|
||||||
|
dotnet run --project /home/tikaiz/RiderProjects/digitalDojo/DDApp/DDApplication/DDApplication.csproj
|
||||||
|
```
|
||||||
|
|
||||||
|
## Notes
|
||||||
|
|
||||||
|
- Position and map are inferred from your own movement + sensor calls (not an authoritative server map).
|
||||||
|
- 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
|
||||||
|
- `*.summary.txt` contains aggregate K/D, kills/min, deaths/min, and action success rates
|
||||||
|
- `latest.log` is a symlink that auto-points to the newest `*.events.csv` session log
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
633
DDApp/DDApplication/spieleinstieg.txt
Normal file
633
DDApp/DDApplication/spieleinstieg.txt
Normal file
@@ -0,0 +1,633 @@
|
|||||||
|
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%2Fspieleinstieg> //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%2Fspieleinstieg&title=&summary=&source=> //E-Mail
|
||||||
|
<mailto:m.mustermann@countit.at?subject=Lese-
|
||||||
|
Tipp%3A%20Dojo%20Game%20%7C%20Wichtige%20Infos%20zum%20Spieleinstieg&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%20Wichtige%20Infos%20zum%20Spieleinstieg%22%0D%0ASchau%20ihn%20dir%20mal%20an%3A%20https%3A%2F%2Fkarriere.countit.at%2Fdojo-game%2Fspieleinstieg%3Fkaid%3Dsharemail%0D%0A%0D%0ABeste%20Gr%C3%BC%C3%9Fe>
|
||||||
|
|
||||||
|
|
||||||
|
Spieleinstieg
|
||||||
|
|
||||||
|
|
||||||
|
Dojo Game
|
||||||
|
|
||||||
|
|
||||||
|
//Dojo Game | Dein Einstieg ins Spiel
|
||||||
|
|
||||||
|
------------------------------------------------------------------------
|
||||||
|
|
||||||
|
In diesem Abschnitt findest du alle notwendigen Infos, um das Dojo Game
|
||||||
|
zu starten und erste Aktionen durchzuführen.
|
||||||
|
|
||||||
|
*Hinweis: *Hol dir deinen persönlichen Zugang <https://dd.countit.at/
|
||||||
|
register> bevor du startest bzw. logge dich ein <https://dd.countit.at/
|
||||||
|
login>. So erscheinst du später auch am Leaderboard!
|
||||||
|
|
||||||
|
|
||||||
|
Inhaltsverzeichnis
|
||||||
|
|
||||||
|
1. Das Spiel <#spiel>
|
||||||
|
2. Vorbereitung <#vorbereitung>
|
||||||
|
3. API-Schlüssel <#api>
|
||||||
|
4. Spiel starten & beenden <#starten>
|
||||||
|
5. Ritter steuern <#ritter>
|
||||||
|
|
||||||
|
|
||||||
|
//Das Spiel
|
||||||
|
|
||||||
|
Im Dojo Game geht es, einfach erklärt, um einen *Server*, auf welchem
|
||||||
|
ein Spiel für dich bereitgestellt wird. In diesem Spiel gibt es im
|
||||||
|
Singleplayer-Modus *einen Gegner, den sogenannten Dojo-Bot,* und deinen
|
||||||
|
Charakter. *Dein Ritter* hat dieselben Eigenschaften wie ein vom
|
||||||
|
Computer gesteuerter Ritter. Über bestimmte Befehle (diese werden über
|
||||||
|
URLs aufgerufen) kannst du deinen Spieler steuern und so programmieren,
|
||||||
|
dass dieser mit deinen Gegnern kämpft, vor ihnen wegläuft oder andere
|
||||||
|
strategische Aktionen ausführt. Ziel ist es, so viele Gegner wie möglich
|
||||||
|
zu eliminieren.
|
||||||
|
*Ein Spiel dauert maximal 15 Minuten* - danach wird deine Sitzung
|
||||||
|
geschlossen. Es gibt innerhalb dieser 15 Minuten unendlich viele Gegner.
|
||||||
|
Wird ein Bot getötet, wird dieser auf einer zufälligen anderen Stelle
|
||||||
|
der Map wiedergeboren. Bei Start eines neuen Spiels beginnst du immer
|
||||||
|
automatisch neu in Level 1.
|
||||||
|
|
||||||
|
|
||||||
|
//Vorbereitung
|
||||||
|
|
||||||
|
Um am Dojo Game teilzunehmen, benötigst du einen an das Internet
|
||||||
|
angeschlossenen Computer, einen *Digital Dojo Zugang* <https://
|
||||||
|
dd.countit.at/register>. Sobald du eingeloggt <https://dd.countit.at/
|
||||||
|
login> bist, findest du im Folgenden deinen *API-Schlüssel*, den du
|
||||||
|
schon bald brauchen wirst.
|
||||||
|
|
||||||
|
Die Logik deines Spielers kannst du in jeder beliebigen
|
||||||
|
Programmiersprache implementieren, da Web-Requests an eine API von fast
|
||||||
|
jeder verfügbaren Programmier- und Skriptsprache unterstützt werden.
|
||||||
|
|
||||||
|
Falls du Starthilfe benötigst und auf bereits erstellte Algorithmen
|
||||||
|
aufbauen möchtest, kannst du dich hier <https://dd.countit.at/dojo-game/
|
||||||
|
tipps> umsehen.
|
||||||
|
|
||||||
|
Die REST-API Befehle können auch mithilfe vom Fiddler <https://
|
||||||
|
www.telerik.com/fiddler> oder dem Postman <https://www.postman.com/
|
||||||
|
> gesendet werden. Diese Programme werden meistens zum Testen oder für
|
||||||
|
Prototypen verwendet und benötigen keinen Programm-Code zum Funktionieren.
|
||||||
|
|
||||||
|
|
||||||
|
//API-Schlüssel
|
||||||
|
|
||||||
|
Mithilfe deines Keys kannst du dich mit unseren Servern verbinden um
|
||||||
|
dein Spiel zu starten. Zudem werden damit deine gesendeten Befehle
|
||||||
|
identifiziert, damit Aktionen, welche du ausführst, auch wirklich nur
|
||||||
|
für dich gelten. Somit wird verhindert, dass du die Spiele anderer User
|
||||||
|
stören oder manipulieren kannst.
|
||||||
|
|
||||||
|
*Halte deinen Schlüssel geheim* - er könnte es anderen Nutzern
|
||||||
|
ermöglichen, Befehle auszuführen welche nicht in deinem Sinne sind!
|
||||||
|
|
||||||
|
|
||||||
|
//Los geht's
|
||||||
|
|
||||||
|
------------------------------------------------------------------------
|
||||||
|
|
||||||
|
In diesem Abschnitt erfährst du, wie du ein Spiel startest und beendest,
|
||||||
|
den Status des laufenden Spiels abfragen kannst, und wie sich dein
|
||||||
|
Ritter steuern lässt.
|
||||||
|
|
||||||
|
|
||||||
|
Wie starte ich ein Spiel? [POST]
|
||||||
|
|
||||||
|
|
||||||
|
Um ein Spiel zu starten, benötigst du deinen API-Schlüssel <#api>. Wurde
|
||||||
|
dieser Befehl erfolgreich ausgeführt, wird das Spiel automatisch
|
||||||
|
gestartet und du kannst direkt Aktionen zum Bewegen des Ritters ausführen.
|
||||||
|
|
||||||
|
Falls bereits ein Spiel mit deinem Charakter läuft, musst du dieses
|
||||||
|
zuerst beenden, bevor du ein neues erstellen kannst. Spiele werden
|
||||||
|
mithilfe eines POST-Requests erzeugt.
|
||||||
|
|
||||||
|
https://game-dd.countit.at/api/game/{key}/create
|
||||||
|
text/x-csharp
|
||||||
|
|
||||||
|
xxxxxxxxxx
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
https://game-dd.countit.at/api/game/{key}/create
|
||||||
|
|
||||||
|
➯ Problem? <https://dd.countit.at/dojo-game/tipps#fehler>
|
||||||
|
➯ Postman-Request <https://dd.countit.at/dojo-game/postman#spielstart>
|
||||||
|
|
||||||
|
|
||||||
|
<http://countit-azure-test.westeurope.cloudapp.azure.com:1337/dojo-
|
||||||
|
game/postman#spieleinstieg>
|
||||||
|
|
||||||
|
|
||||||
|
Wie beende ich ein Spiel? [POST]
|
||||||
|
|
||||||
|
|
||||||
|
Ein Spiel wird beendet, wenn du mit deinem API-Key folgenden Befehl als
|
||||||
|
POST-Request ausführst:
|
||||||
|
|
||||||
|
https://game-dd.countit.at/api/game/{key}/close
|
||||||
|
text/x-csharp
|
||||||
|
|
||||||
|
xxxxxxxxxx
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
https://game-dd.countit.at/api/game/{key}/close
|
||||||
|
|
||||||
|
➯ Problem? <https://dd.countit.at/dojo-game/tipps#fehler>
|
||||||
|
➯ Postman-Request <https://dd.countit.at/dojo-game/postman#spielende>
|
||||||
|
|
||||||
|
|
||||||
|
Status des laufenden Spiels abfragen [GET]
|
||||||
|
|
||||||
|
|
||||||
|
Um abfragen zu können, ob mit deinem API-Schlüssel bereits ein Spiel
|
||||||
|
läuft, kannst du den folgenden Befehl verwenden. Du erhältst als
|
||||||
|
Rückgabewert dasselbe wie beim Erstellen und Schließen eines Spiels
|
||||||
|
sowie eine Fehlermeldung, falls kein Spiel vorhanden ist.
|
||||||
|
|
||||||
|
https://game-dd.countit.at/api/game/{key}/status
|
||||||
|
text/x-csharp
|
||||||
|
|
||||||
|
xxxxxxxxxx
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
https://game-dd.countit.at/api/game/{key}/status
|
||||||
|
|
||||||
|
➯ Problem? <https://dd.countit.at/dojo-game/tipps#fehler>
|
||||||
|
➯ Postman-Request <https://dd.countit.at/dojo-game/postman#status>
|
||||||
|
|
||||||
|
Beim Erstellen und Beenden eines Spiels werden jeweils dieselben Daten
|
||||||
|
zurückgeliefert:
|
||||||
|
|
||||||
|
→ Game-ID: Diese macht dein Spiel identifizierbar.
|
||||||
|
→ Running: Damit werden dein Spielstatus und der Name des geladenen
|
||||||
|
Levels sichtbar.
|
||||||
|
|
||||||
|
Der zurückgegebene String ist im JSON Format.
|
||||||
|
|
||||||
|
{"gameid":"d2144a67-733a-4e06-8a6b-9ce877b99753","running":true,"level":"The Default Level"}
|
||||||
|
text/x-csharp
|
||||||
|
|
||||||
|
xxxxxxxxxx
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
{"gameid":"d2144a67-733a-4e06-8a6b-9ce877b99753","running":true,"level":"The Default Level"}
|
||||||
|
|
||||||
|
➯ Was ist JSON? <https://dd.countit.at/dojo-game/tipps#technologie>
|
||||||
|
|
||||||
|
|
||||||
|
//Steuere deinen Ritter
|
||||||
|
|
||||||
|
------------------------------------------------------------------------
|
||||||
|
|
||||||
|
Ein Ritter hat die Möglichkeit auf einem zweidimensionalen Spielfeld
|
||||||
|
verschiedenste Aktionen auszuführen. Aktionen sowie ihre Wirkungen und
|
||||||
|
REST Aufrufe sind hier gelistet. Versuche deine Aktionen nicht zu
|
||||||
|
schnell hintereinander auszuführen, da du nach jeder Aktion eine gewisse
|
||||||
|
Zeit abwarten musst, bis du diese wieder einsetzen kannst. Dein Ritter
|
||||||
|
führt nur Befehle aus, welche du ihm gibst. Sendest du deinem Spieler
|
||||||
|
keine Aktionen, welche dieser ausführen soll, steht dieser durchgehend
|
||||||
|
auf derselben Position und ist verletzbar.
|
||||||
|
|
||||||
|
|
||||||
|
Move [POST]
|
||||||
|
|
||||||
|
|
||||||
|
Du kannst deinen Ritter alle 250 Millisekunden um ein Feld in eine der
|
||||||
|
vier Himmelsrichtungen bewegen.
|
||||||
|
Das Feld "Direction" sollte eine Zahl zwischen 0 und 3 enthalten:
|
||||||
|
|
||||||
|
→ 0 für Norden
|
||||||
|
→ 1 für Osten
|
||||||
|
→ 2 für Süden
|
||||||
|
→ 3 für Westen
|
||||||
|
|
||||||
|
https://game-dd.countit.at/api/player/{key}/move/{direction}
|
||||||
|
text/x-csharp
|
||||||
|
|
||||||
|
xxxxxxxxxx
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
https://game-dd.countit.at/api/player/{key}/move/{direction}
|
||||||
|
|
||||||
|
➯ Problem? <https://dd.countit.at/dojo-game/tipps#fehler>
|
||||||
|
➯ Postman-Request <https://dd.countit.at/dojo-game/postman#move>
|
||||||
|
|
||||||
|
|
||||||
|
Dash [POST]
|
||||||
|
|
||||||
|
|
||||||
|
Dash lässt dich 5 Blöcke in eine von dir bestimmte Richtung bewegen.
|
||||||
|
Es hat außerdem einen besonderen Cooldown: Du kannst Dash schon 3
|
||||||
|
Sekunden nach der Aktivierung verwenden, aber dein Spieler wird zu
|
||||||
|
erschöpft sein und sich nur 3 Blöcke bewegen. Doch aufgepasst, wenn du
|
||||||
|
gegen eine Wand dasht nimmst du Schaden in Höhe der verbleibenden Dash-
|
||||||
|
Distanz. Nachdem du diese Aktion verwendet hast, musst du 5000
|
||||||
|
Millisekunden warten.
|
||||||
|
|
||||||
|
https://game-dd.countit.at/api/player/{key}/dash/{direction}
|
||||||
|
text/x-csharp
|
||||||
|
|
||||||
|
xxxxxxxxxx
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
https://game-dd.countit.at/api/player/{key}/dash/{direction}
|
||||||
|
|
||||||
|
➯ Problem? <https://dd.countit.at/dojo-game/tipps#fehler>
|
||||||
|
➯ Postman-Request <https://dd.countit.at/dojo-game/postman#dash>
|
||||||
|
|
||||||
|
|
||||||
|
Hit [POST]
|
||||||
|
|
||||||
|
|
||||||
|
Diese Aktion wird benutzt, um mit deinem Ritter zu schlagen. Es kann
|
||||||
|
jeweils nur in eine Himmelsrichtung (0 für Norden, 1 für Osten, 2 für
|
||||||
|
Süden und 3 für Westen) geschlagen werden und dies nur einen Block weit.
|
||||||
|
Danach musst du 250 Millisekunden warten, bis du wieder angreifen
|
||||||
|
kannst. Ein normaler Schlag, welcher mit einem Abstand von einem Block
|
||||||
|
erzielt wurde, fügt dem Gegner weniger Schaden zu als wenn du auf
|
||||||
|
demselben Block wie ein Gegner stehst. Hierbei ist es egal, wie viele
|
||||||
|
Gegner auf einem Fleck stehen. Jeder bekommt gleich viel Schaden.
|
||||||
|
|
||||||
|
https://game-dd.countit.at/api/player/{key}/hit/{direction}
|
||||||
|
text/x-csharp
|
||||||
|
|
||||||
|
xxxxxxxxxx
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
https://game-dd.countit.at/api/player/{key}/hit/{direction}
|
||||||
|
|
||||||
|
➯ Problem? <https://dd.countit.at/dojo-game/tipps#fehler>
|
||||||
|
➯ Postman-Request <https://dd.countit.at/dojo-game/postman#hit>
|
||||||
|
|
||||||
|
|
||||||
|
Shoot [POST]
|
||||||
|
|
||||||
|
|
||||||
|
Shoot benötigt, wie Peek, eine Direction (0 für Norden, 1 für Osten, 2
|
||||||
|
für Süden und 3 für Westen), also eine Richtung. Shoot verwendet diese
|
||||||
|
Richtung, um einen Schuss in diese Richtung abzugeben. Als Antwort kommt
|
||||||
|
zurück, ob diese Aktion ausgeführt wurde und ob ein Gegner getroffen
|
||||||
|
wurde. Die Kugel stoppt beim ersten Spieler. Nachdem du diese Aktion
|
||||||
|
verwendet hast, musst du 1000 Millisekunden warten.
|
||||||
|
|
||||||
|
https://game-dd.countit.at/api/player/{key}/shoot/{direction}
|
||||||
|
text/x-csharp
|
||||||
|
|
||||||
|
xxxxxxxxxx
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
https://game-dd.countit.at/api/player/{key}/shoot/{direction}
|
||||||
|
|
||||||
|
➯ Problem? <https://dd.countit.at/dojo-game/tipps#fehler>
|
||||||
|
➯ Postman-Request <https://dd.countit.at/dojo-game/postman#shoot>
|
||||||
|
|
||||||
|
|
||||||
|
Radar [GET]
|
||||||
|
|
||||||
|
|
||||||
|
Mit dem Befehl "Radar" kannst du die Umgebung um deinen Spieler im
|
||||||
|
Umkreis von 5 Blöcken auf Feinde überprüfen. Das Feld wird aufgeteilt
|
||||||
|
und durchsucht. Danach erhältst du Informationen über die Anzahl der
|
||||||
|
Spieler in den 4 Himmelsrichtungen und den Block, auf dem du stehst.
|
||||||
|
Nachdem du diese Aktion verwendet hast, musst du 250 Millisekunden warten.
|
||||||
|
|
||||||
|
Radar <https://dd.countit.at/media/dojo-game/dojo-game_radar-
|
||||||
|
himmelsrichtungen.png>
|
||||||
|
https://game-dd.countit.at/api/player/{key}/radar
|
||||||
|
text/x-csharp
|
||||||
|
|
||||||
|
xxxxxxxxxx
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
https://game-dd.countit.at/api/player/{key}/radar
|
||||||
|
|
||||||
|
➯ Problem? <https://dd.countit.at/dojo-game/tipps#fehler>
|
||||||
|
➯ Postman-Request <https://dd.countit.at/dojo-game/postman#radar>
|
||||||
|
|
||||||
|
|
||||||
|
Scan [GET]
|
||||||
|
|
||||||
|
|
||||||
|
Mit Scan kannst du den am nächsten stehenden Spieler im Umkreis von 3
|
||||||
|
Blöcken finden. Durch den Rückgabewert weißt du dann auch, was seine
|
||||||
|
relative Position zu dir ist. Nachdem du diese Aktion verwendet hast,
|
||||||
|
musst du 2000 Millisekunden warten.
|
||||||
|
|
||||||
|
https://game-dd.countit.at/api/player/{key}/scan
|
||||||
|
text/x-csharp
|
||||||
|
|
||||||
|
xxxxxxxxxx
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
https://game-dd.countit.at/api/player/{key}/scan
|
||||||
|
|
||||||
|
➯ Problem? <https://dd.countit.at/dojo-game/tipps#fehler>
|
||||||
|
➯ Postman-Request? <https://dd.countit.at/dojo-game/postman#scan>
|
||||||
|
|
||||||
|
|
||||||
|
Peek [GET]
|
||||||
|
|
||||||
|
|
||||||
|
Peek benötigt, wie Move und Hit, eine Direction (0 für Norden, 1 für
|
||||||
|
Osten, 2 für Süden und 3 für Westen). Peek verwendet diese Richtung, um
|
||||||
|
zu überprüfen, ob sich in der angegebenen Richtung ein Spieler in deinem
|
||||||
|
Sichtfeld befindet. Peek gibt dir dann die Anzahl der Gegner in der
|
||||||
|
Sichtlinie und die Distanz zum nächsten stehenden Spieler in dieser
|
||||||
|
Sichtlinie zurück. Dies kannst du alle 1000 Millisekunden verwenden.
|
||||||
|
|
||||||
|
https://game-dd.countit.at/api/player/{key}/peek/{direction}
|
||||||
|
text/x-csharp
|
||||||
|
|
||||||
|
xxxxxxxxxx
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
https://game-dd.countit.at/api/player/{key}/peek/{direction}
|
||||||
|
|
||||||
|
➯ Problem? <https://dd.countit.at/dojo-game/tipps#fehler>
|
||||||
|
➯ Postman-Request <https://dd.countit.at/dojo-game/postman#peek>
|
||||||
|
|
||||||
|
|
||||||
|
Stats [GET]
|
||||||
|
|
||||||
|
|
||||||
|
Mit Stats hast du die Möglichkeit dir deine Kills und Deaths des aktiven
|
||||||
|
Spiels anzusehen. Der Rückgabewert weicht vom Rückgabewert der anderen
|
||||||
|
Funktionen ab - enthalten sind Informationen zum derzeitigen Level,
|
||||||
|
allgemeine Stats sowie Informationen zu den Lebenspunkten eines Spielers.
|
||||||
|
|
||||||
|
*progress* - gibt an, wie weit du ein Level bereits abgeschlossen hast (%)
|
||||||
|
*remainingtime* - gibt an, wieviele Minuten noch übrig sind bevor das
|
||||||
|
Spiel gestoppt wird
|
||||||
|
*deathsleft* - gibt an, wie oft du noch sterben darfst, bevor das Spiel
|
||||||
|
gestoppt wird
|
||||||
|
|
||||||
|
https://game-dd.countit.at/api/player/{key}/stats
|
||||||
|
text/x-csharp
|
||||||
|
|
||||||
|
xxxxxxxxxx
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
https://game-dd.countit.at/api/player/{key}/stats
|
||||||
|
|
||||||
|
Der Rückgabewert dieser Funktion wurde mit dem letzten Update verändert.
|
||||||
|
Hier ein Beispiel für den neuen Rückgabewert:
|
||||||
|
|
||||||
|
{"action":"stats","executed":true,"stats":
|
||||||
|
{"kills":1,"deaths":1},"level":
|
||||||
|
{"progress":6.6,"remainingtime":14.44,"deathsleft":999,"levelid":2,"name":"Bigger Map Level"},"health":{"currenthealth":10.0,"maxhealth":10.0}}
|
||||||
|
text/x-csharp
|
||||||
|
|
||||||
|
xxxxxxxxxx
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
{"action":"stats","executed":true,"stats":{"kills":1,"deaths":1},"level":{"progress":6.6,"remainingtime":14.44,"deathsleft":999,"levelid":2,"name":"Bigger Map Level"},"health":{"currenthealth":10.0,"maxhealth":10.0}}
|
||||||
|
|
||||||
|
➯ Problem? <https://dd.countit.at/dojo-game/tipps#fehler>
|
||||||
|
➯ Postman-Request <https://dd.countit.at/dojo-game/postman#stats>
|
||||||
|
|
||||||
|
|
||||||
|
Specialattack [POST]
|
||||||
|
|
||||||
|
|
||||||
|
Specialattack ist eine Aktion, welche du viel seltener als einen
|
||||||
|
normalen Schlag ("Hit") einsetzen kannst. Diese hat allerdings eine
|
||||||
|
bestimmte Fähigkeit und verursacht dadurch mehr Schaden an deinem
|
||||||
|
Gegner. Specialattack nimmt keine Direction als Parameter entgegen,
|
||||||
|
sondern führt den Angriff in allen Richtungen mit einem Wirkungskreis
|
||||||
|
von 3 Blöcken gleichzeitig aus. Du kannst die Specialattack alle 5000
|
||||||
|
Millisekunden ausführen.
|
||||||
|
|
||||||
|
https://game-dd.countit.at/api/player/{key}/specialattack
|
||||||
|
text/x-csharp
|
||||||
|
|
||||||
|
xxxxxxxxxx
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
https://game-dd.countit.at/api/player/{key}/specialattack
|
||||||
|
|
||||||
|
➯ Problem? <https://dd.countit.at/dojo-game/tipps#fehler>
|
||||||
|
➯ Postman-Request <https://dd.countit.at/dojo-game/postman#specialattack>
|
||||||
|
|
||||||
|
|
||||||
|
Teleport [GET]
|
||||||
|
|
||||||
|
|
||||||
|
Mit Teleport kannst du dich auf ein beliebiges Feld teleportieren. Der
|
||||||
|
Trick dabei: Du musst das Feld relativ zu deiner Position mithilfe von x
|
||||||
|
und y Koordinaten angeben.
|
||||||
|
Cooldown: 20000 Millisekunden (20 Sekunden)
|
||||||
|
|
||||||
|
Achtung: Falls du in einer Wand landest bist du sofort tot. Wenn du
|
||||||
|
allerdings einen Gegner erwischst, wird dieser sofort getötet.
|
||||||
|
|
||||||
|
https://game-dd.countit.at/api/player/{key}/teleport/{x}/{y}
|
||||||
|
text/x-csharp
|
||||||
|
|
||||||
|
xxxxxxxxxx
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
https://game-dd.countit.at/api/player/{key}/teleport/{x}/{y}
|
||||||
|
|
||||||
|
➯ Problem? <https://dd.countit.at/dojo-game/tipps#fehler>
|
||||||
|
➯ Postman-Request <https://dd.countit.at/dojo-game/postman#teleport>
|
||||||
|
|
||||||
|
|
||||||
|
Rückgabewert
|
||||||
|
|
||||||
|
|
||||||
|
Jede Aktion gibt im Prinzip immer einen gleich strukturierten JSON-
|
||||||
|
String zurück. Jedoch können sich die Datentypen der einzelnen Felder je
|
||||||
|
nach Aktion unterscheiden.
|
||||||
|
Hier zwei Beispiele, um dies zu verdeutlichen:
|
||||||
|
|
||||||
|
Die Move-Aktion, ohne speziellen Rückgabewert:
|
||||||
|
|
||||||
|
{"action":"move","move":"true","executed":"true"}
|
||||||
|
text/x-csharp
|
||||||
|
|
||||||
|
xxxxxxxxxx
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
{"action":"move","move":"true","executed":"true"}
|
||||||
|
|
||||||
|
Die Radar-Aktion, mit einem Integer als Rückgabewert:
|
||||||
|
|
||||||
|
{"action":"radar","radar":2,"executed":"true"}
|
||||||
|
text/x-csharp
|
||||||
|
|
||||||
|
xxxxxxxxxx
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
{"action":"radar","radar":2,"executed":"true"}
|
||||||
|
|
||||||
|
➯ Was ist JSON? <https://dd.countit.at/dojo-game/tipps#technologie>
|
||||||
|
➯ Postman-Request <https://dd.countit.at/dojo-game/postman#rueckgabewerte>
|
||||||
|
|
||||||
|
|
||||||
|
Bereit für die ultimative Programmier-Challenge an deiner Schule?
|
||||||
|
|
||||||
|
Alle Infos dazu findest du hier //
|
||||||
|
<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>
|
||||||
|
/
|
||||||
|
|
||||||
|
/
|
||||||
|
|
||||||
|
|
||||||
|
Besiege unseren Bot
|
||||||
|
|
||||||
|
Egal ob als Einzelspieler oder im Mulitplayer-Modus: Stelle dich dem
|
||||||
|
Dojo-Bot und beweise, dass du auf das Leaderboard gehörst!
|
||||||
|
|
||||||
|
Ich bin bereit! // <https://dd.countit.at/dojo-game>
|
||||||
|
/
|
||||||
|
|
||||||
|
/
|
||||||
|
|
||||||
|
|
||||||
|
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 |
|
||||||
|
Datenschutzerklä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
|
||||||
Reference in New Issue
Block a user