Aimbot für Moorhuhnjagd


Wieder einmal ist mir aufgefallen, dass das Spiel noch viel zu kompliziert ist, und weitere Vereinfachung not tut. Anstatt einer Auto-Simulation gibt es jetzt das beliebte Mohrhuhnjagd-Spiel. Das enthält noch weniger Aktionsmöglichkeiten und lässt sich hoffentlich leichter als Referenz-Implementierung für eine Künstliche Intelligenz umsetzen. Für den Anfang sieht man im Screenshot zwei Modi: einmal die normale Version ohne Head up Display und einmal die Version mit Headup Display. Der User kann zwischen beiden Modi umschalten.

Wie nicht anders zu erwarten war, ist die Version mit Head-Up-Display um einiges effizienter zu bedienen. Wenn damit der menschlicher Spieler interagiert, wird er mehr Moorhühner pro Sekunde erlegen als jemals zuvor. Die Features sind dort im Detail: einmal gibt es oben in der Statuszeile eine Positionsangabe in absoluten Pixeln, dann gibt es die Zahl der erfolgreichen Schüssen, die Zahl der misslungenen Schüsse, den Framecounter. Ferner gibt es noch einen Aimbot-artigen Kreis der sich verfärbt man in die Nähe des Ziels kommt und ganz wichtig gibt es noch eine Linie zwischen Ist und Soll Position so dass man immer weiß, in welche Richtung man die Maus bewegen muss.

Das Spielprinzip selber ist das gleiche, es geht darum, dass man das Fadenkreuz über das blaue Moorhuhn bringt und dann auf die Fire-Taste drückt. Der Unterschied ist der, dass die Variante mit eingeblendetem HuD zu einer besseren kognitiven Performance führt. Ich habe das jetzt nicht genau ausgerechnet, aber vermutlich wird egal wer das Spiel ausprobiert mit dem HuD einen höheren Punktestand erzielen, weniger oft daneben schießen und effizienter die Maus bewegen.

Jetzt fehlt nur noch die Variante 3, wo man zusätzlich zum Headup Display noch eine Automatik aktiviert, also eine Software, die das Fadenkreuz über das Ziel bewegt und automatisch abdrückt. Diese Automatik wäre dann die eigentliche KI, welche aller voraussicht nach die beste Performance erzielt, weil sie das Spiel 24/7 durchspielen kann und niemals einen Fehler macht.

Es gilt also zwischen 3 Modi zu unterscheiden: einmal das normale Moorhuhn-Spiel, dann die Version mit Headup Display und zuletzt die Künstliche Intelligenz mit Automatik-Zielvorrichtung. Wenn man direkt eine KI programmiert ohne zuvor den Modus mit dem Head-up Display wird es schwer bis unmöglich. Das heißt, man müsste sich er grundlegende Dinge überlegen, also das HuD vorwegnehmen. Einfacher ist es, wenn man zuerst das HuD implementiert und erst danach die KI programmiert.

Vielleicht fragt der eine oder andere: wozu das ganze? Zugegeben, Moorhuhnjagd ist nicht besonders anspruchsvoll, der Hauptgrund warum ich diese Domäne gewählt habe war, dass sie sich in unter 100 Lines of Code implementieren lässt. Man anhand dieses Beispiel aber gut erklären kann was ein HuD ist.

UPDATE
Soeben habe ich den dritten Mode “Auto” implementiert. Wenn man den aktiviert wird der Schriftzug “Auto” angezeigt und die KI setzt das Fadenkreuz auf das Ziel und drückt auf Fire. Das ergebnis kann sich sehen lassen. Pro Sekunde erzielt das System mindestens 5 Treffer. Man kann dabei zuschauen wie ein Treffer nach dem anderen durchgeführt wird. Unmöglich zu schlagen für einen menschlichen Spieler. Die KI agiert perfekt.

Wichtig zu erwähnen, dass man jederzeit auf den normalen Mode zurückschalten kann, also entweder ohne oder mit HuD. Das heißt, der Spieler hat die volle Kontrolle. Die KI selber ist lächerlich einfach, sie besteht aus zwei Befehlen:

self.mouse = self.myenemy.pos
self.fire()

Was die machen ist selbsterklärend. Es handelt sich um einen klassischen Aimbot, also ein System was zielt und feuert. Ausnahmsweise gibt es hier keine Möglichkeit die KI großartig zu verbessern, sie hat das Spiel im Griff, was damit zutun hat, dass Moorhuhnjagd ein sehr übersichtliches Spiel ist. Es ist jedoch vorzuglich geeignet um die Grundprinzipien von User-Interfaces zu erläutern. Also einen kompletten Entwicklungszyklus abzufilden, angefangen vom Programmieren des Spiels, über das Programmieren eines HuD bis hin zur Implementierung einer KI.

Obwohl der Automode die meisten Treffer pro Sekunde erzielt ist der HuD Mode am eindrucksvollsten. Weil in diesem Modus der Human-Operator in-the-loop verbleibt, das heißt er muss manuell den Cursor positionieren erhält aber Zusatzinformationen eingeblendet um effizienter zu werden.

Der Vollständigkeit halber folgt zum Abschluss dieses Kapitels der komplette Sourcecode.

import pygame, random, math, threading, sys

class Stats():
  def __init__(self):
    self.hits = 0
    self.failshots = 0

class Enemy():
  def __init__(self):
    self.pos = (200,100)
    self.width = 30
    self.height = 20
   
class Game():
  def __init__(self):
    self.screen = (600, 338)
    self.fps = 20  # 30 fps
    self.framestep=0
    self.white = (220, 220, 220)
    self.black = (0, 0, 0)
    self.grey = (150, 150, 150)
    self.red = (230, 0, 0)
    self.blue = (0, 0, 230)    
    self.mouse = (0,0)
    self.myenemy = Enemy()
    self.mystats = Stats()
    self.headupdisplay = "low"
    random.seed()
    pygame.init()
    self.window = pygame.display.set_mode(self.screen)
    for self.framestep in range(10000000):
      self.updateGUI()
      if self.headupdisplay=="middle" or self.headupdisplay=="high": self.hud()
      pygame.display.update() 
  def hud(self):
    # aiming
    radius = 50
    p1 = self.mouse
    p2 = self.myenemy.pos
    if self.incircle(p1,radius,p2): color=self.red
    else: color = self.black
    pygame.draw.circle(self.window, color, self.mouse, radius, 3) 
    pygame.draw.line(self.window, self.black, p1, p2, 1)
    # mouseposition
    myfont = pygame.font.SysFont("freesans", 16)
    text = str(self.mouse)+" "+str(self.framestep)
    label = myfont.render(text, True, self.black)
    self.window.blit(label, (220,30))
    # stats
    text = str(self.mystats.hits)+" "+str(self.mystats.failshots)
    label = myfont.render(text, True, self.black)
    self.window.blit(label, (220,50))
    if self.headupdisplay == "high": self.automode()
  def automode(self):
    # high
    myfont = pygame.font.SysFont("freesans", 16)
    text = "Auto"
    label = myfont.render(text, True, self.black)
    self.window.blit(label, (self.mouse[0],self.mouse[1]+20))
    # pos
    self.mouse = self.myenemy.pos
    self.fire()
  def updateGUI(self):
    pygame.time.wait(1000/self.fps)
    self.window.fill(self.white)
    self.inputhandling()
    # aiming
    offset=20
    p1=(self.mouse[0]-offset,self.mouse[1])
    p2=(self.mouse[0]+offset,self.mouse[1])
    p3=(self.mouse[0],self.mouse[1]-offset)
    p4=(self.mouse[0],self.mouse[1]+offset)
    pygame.draw.line(self.window, self.black, p1, p2, 2)
    pygame.draw.line(self.window, self.black, p3, p4, 2)
    # enemy
    pygame.draw.rect(self.window, self.blue, (self.myenemy.pos[0]-self.myenemy.width/2,self.myenemy.pos[1]-self.myenemy.height/2,self.myenemy.width,self.myenemy.height), 0) 
  def incircle(self,p1,radius,p2):
    """ checks if p2 is in circle """
    square_dist = (p1[0] - p2[0]) ** 2 + (p1[1] - p2[1]) ** 2
    return square_dist <= radius ** 2    
  def fire(self):
    if self.incircle(self.myenemy.pos,self.myenemy.width,self.mouse):
      self.mystats.hits +=1
      self.myenemy.pos = (random.randint(0,self.screen[0]),random.randint(0,self.screen[1]))
    else: self.mystats.failshots+=1
  def inputhandling(self):
    for event in pygame.event.get(): 
      if event.type == pygame.QUIT: sys.exit(0) 
      if event.type == pygame.MOUSEMOTION: self.mouse= event.pos
      if event.type == pygame.KEYDOWN:
        if event.key == pygame.K_1: self.fire()
        if event.key == pygame.K_2: 
          if self.headupdisplay == "high": self.headupdisplay = "low"
          elif self.headupdisplay == "low": self.headupdisplay = "middle"
          elif self.headupdisplay == "middle": self.headupdisplay = "high"
      
if __name__ == "__main__":
  myGame = Game()

Advertisements

Kommentar verfassen

Trage deine Daten unten ein oder klicke ein Icon um dich einzuloggen:

WordPress.com-Logo

Du kommentierst mit Deinem WordPress.com-Konto. Abmelden / Ändern )

Twitter-Bild

Du kommentierst mit Deinem Twitter-Konto. Abmelden / Ändern )

Facebook-Foto

Du kommentierst mit Deinem Facebook-Konto. Abmelden / Ändern )

Google+ Foto

Du kommentierst mit Deinem Google+-Konto. Abmelden / Ändern )

Verbinde mit %s