Not logged in.  Login/Logout/Register | List snippets | | Create snippet | Upload image | Upload data

332
LINES

< > BotCompany Repo | #1006753 // Second A. I. Game Simplified & Solved

JavaX source code [tags: use-pretranspiled] - run with: x30.jar

Uses 3874K of libraries. Click here for Pure Java version (6909L/49K/174K).

!7

///////////////////////////
// Your API to work with //
///////////////////////////

abstract sclass GameForAI {
  abstract RGBImage getImage();
  abstract L<Rect> submit(Pt point); // returns correct solution so AI can learn from it
}

abstract sclass AI {
  // stuff you get
  
  GameForAI game;
  RGBImage image;
  int steps;
  RGBImage image() { ret image; }
  int w() { ret image.w(); }
  int h() { ret image.h(); }
  L<Rect> submit(Pt p) { ret game.submit(p); }
  L<Rect> submit(Rect r) { ret submit(middleOfRect(r)); }
  L<Rect> submitNothing() { ret game.submit(null); }

  // implement this method and call submit()
  abstract void go();
  
  void done() {}
}

//////////////////////////////////////
// Test AIs. Just add your own here //
//////////////////////////////////////

AI > ClickAnyNumber {
  void go {
    submit(random(segment(image;
  }
}

static ImageSurface isFound;

AI > FindPairs {
  void go {
    L<Rect> solution = submitNothing();
    if (l(solution) == 2)
      isFound = setFrameWidth(showImage(isFound, "Pairs!", mergeImagesHorizontally(rgbClips(image, solution))), 200);
  }
}

AI > FindNonPairs {
  void go {
    L<Rect> solution = submitNothing();
    if (l(solution) == 1) {
      L<Rect> myRects = segment(image);
      Rect sol = autoCropOfRGBImage(image, first(solution));
      myRects = dropRectsIntersectingWith(myRects, sol);
      if (l(myRects) == 1)
        isFound = setFrameWidth(showImage(isFound, "Non-Pairs!", mergeImagesHorizontally(rgbClips(image, concatLists(ll(sol), myRects)))), 250);
    }
  }
}

AI > JARVIS {
  new BWImageCategorizer cat;
  bool firstRun = true;
  static ImageSurface is;
  
  BWImage simplifyImage(RGBImage img) {
    ret new Image2B(img).toBW();
  }
  
  Rect guess() {
    L<Rect> myRects = segment(image);
    if (l(myRects) != 2) null;
    int i = cat.locateImage(simplifyImage(image.clip(first(myRects;
    int j = cat.locateImage(simplifyImage(image.clip(second(myRects;
    ret get(myRects, i < j ? 0 : 1);
  }
  
  void go {
    L<Rect> solution = submit(guess());
    Analysis analysis = analyzePair(image, solution);
    if (analysis == null) ret;
    int n = cat.numCategories();
    int i = cat.addImage(simplifyImage(first(analysis.images)));
    int j = cat.addImage(simplifyImage(second(analysis.images)));
    bool update = cat.numCategories() > n;
    if (analysis.hetero && i > j) {
      swap(cat.images, i, j);
      update = true;
    }
    if (cat.numCategories() > 10) {
      cat.allowedDistance += 0.01f;
      print("Got 11 categories after " + steps + " rounds. Upping allowed distance to: " + cat.allowedDistance);
      cat.clear();
      steps = 0;
    } else if (update) {
      bool first = is == null;
      is = showImage_centered(is, "JARVIS Has Learned These Numbers", mergeImagesHorizontally(cat.rgbImages()));
      if (first) {
        setFrameWidth(is, 400);
        moveToTopRightCorner(getFrame(is));
      }
    }
    if (firstRun && steps < 50) sleep(blend(1000, 0, steps/50.0));
  }
  
  void done() {
    print("Categories: " + cat.numCategories() + " (should probably be 10)");
    steps = 0; firstRun = false;
  }
  
  void cleanMeUp() {
    print("Jarvis cleaning up");
    if (is != null) is.setImage((BufferedImage) null);
  }
}

sclass Analysis {
  bool hetero;
  L<RGBImage> images;
  
  *() {}
  *(bool *hetero, L<RGBImage> *images) {}
}

static Analysis analyzePair(RGBImage image, L<Rect> solution) {
  if (l(solution) == 2)
    ret new Analysis(false, rgbClips(image, rgbAutoCropRects(image, solution)));
  if (l(solution) == 1) {
    L<Rect> myRects = segment(image);
    Rect sol = autoCropOfRGBImage(image, first(solution));
    myRects = dropRectsIntersectingWith(myRects, sol);
    if (l(myRects) == 1)
      ret new Analysis(true, rgbClips(image, concatLists(ll(sol), myRects)));
  }
  null; // no insights today
}

static L<Rect> segment(RGBImage img) {
  ret autoSegment(new BWImage(img), 3); // 2 is too small
}

///////////////
// Main Game //
///////////////

static int w = 150, h = 150;
static int border = 10, fontSize = 30, numberMargin = 3;
static int rounds = 1000, numbers = 2;
static S font = #1004887;
static bool alwaysNewImage = true; // prevents AIs being stuck on an image
static int fps = 50;

static int points, clicks;
static ImageSurface is, isWrong;
static long isWrongLast;
static RGBImage img;
static new HashMap<Rect, Int> words;
static L<Rect> solution;
volatile sbool aiMode;
static JLabel lblScore, lblTiming;
static new HashMap<Class, AI> ais;

p-substance {
  thread { loadBinarySnippet(#1004373); } // preload applause animation
  nextImage();
  addToWindow(is, withMargin(lblScore = jcenteredBoldLabel("Your score: 0 of 0")));
  for (final Class c : myNonAbstractClassesImplementing(AI)) {
    final S name = shortClassName(c);
    final JButton btn = jbutton(name);
    onClick(btn, r {
      if (aiMode) ret;
      btn.setText(name + " Running...");
      thread {
        Game game = testAI(c, voidfunc(Game game) {
          if (game.step < 50 || (game.step % 10) == 0 || game.step == rounds) {
            S text = name + " scored " + game.points + " of " + game.step;
            if (game.error != null)
              text += " - ERROR: " + game.error;
            setText_noWait(btn, text);
          }
        });
      }
    });
    addToWindow(is, withMargin(btn));
  }
  addToWindow(is, lblTiming = jCenteredLabel(;
  titlePopupMenuItem(is, "Restart AIs", r { clearMapWithCleanUp(ais); });
  addToWindow(is, withMargin(jbutton("Restart AIs", r { clearMapWithCleanUp(ais); })));
  
  packFrame(is);
  setFrameWidth(is, 400);
  centerTopFrame(is);
  hideConsole();
}

svoid nextImage {
  RGBImage img = rgbImage(Color.white, w, h);
  words.clear();
  new L<Rect> taken;
  for i to numbers: {
    int num = random(10);
    S s = str(num);
    RGB color = new RGB(random(0.5), random(0.5), random(0.5));
    renderText_fg.set(color.getColor());
    BufferedImage ti = renderText(font, fontSize, s);
    Rect r;
    int safety = 0;
    do {
      r = randomRect(w, h, border, ti.getWidth(), ti.getHeight());
      if (r == null || ++safety >= 1000) fail("Image too small: \*ti.getWidth()*/*\*ti.getHeight()*/ > \*w*/*\*h*/");
    } while (anyRectOverlaps(taken, r));
    rgbCopy(ti, img, r.x, r.y);
    words.put(r, num);
    taken.add(growRect(r, numberMargin));
  }
  solution = keysWithBiggestValue(words);
  
  main.img = img;
  if (aiMode) ret; // occasional updates only when AI is running
  showTheImage();
}

svoid showTheImage {
  bool first = is == null;
  is = showZoomedImage_centered(is, img, "Click On The Highest Number!", 1.5);
  if (first) {
    onLeftClick(is, voidfunc(Pt p) {
      ++clicks;
      if (anyRectContains(solution, is.pointFromComponentCoordinates(p))) {
        ++points;
        nextImage();
      } else if (alwaysNewImage) nextImage();
      lblScore.setText(print("Your score: " + points + " of " + clicks));
    });
    disableImageSurfaceSelector(is);
    
    // animate if idle
    awtEvery(is, 1000, r {
      if (!aiMode && isInForeground(is) && !mouseInComponent(is))
        nextImage();
    });
    
    // show current image occasionally when AI is running
    awtEvery(is, 1000/fps, r {
      if (aiMode) showTheImage();
    });
  }
}

// AI stuff

sclass Game extends GameForAI {
  int points, step;
  Pt submitted;
  Throwable error;
  
  RGBImage getImage() { ret img; }

  L<Rect> submit(Pt p) {
    if (submitted != null) fail("No multi-submit please");
    submitted = p == null ? new Pt(-9, -9) : p;
    if (p != null && anyRectContains(solution, p)) {
      ++points;
      if (!alwaysNewImage) nextImage();
    }
    ret solution;
  }
}

static Game scoreAI(AI ai, O onScore) {
  aiMode = true;
  final long start = sysNow();
  try {
    final new Game game;
    setOpt(ai, +game);
    while (game.step < rounds) {
      ++game.step;
      ++ai.steps;
      game.submitted = null;
      int points = game.points;
      RGBImage image = img;
      try {
        setOpt(ai, +image);
        ai.go();
      } catch e {
        if (game.error == null) { // print first error to console
          showConsole();
          printStackTrace(e);
        }
        game.error = e;
      } finally {
        setOpt(ai, image := null);
      }
      if (points == game.points && hasElapsed(isWrongLast, 50)) {
        isWrongLast = sysNow();
        bool first = isWrong == null;
        isWrong = showImage(isWrong, "Last Blunder", rgbMarkPoint(image, game.submitted, Color.red, 3));
        if (first) {
          setFrameWidth(isWrong, 230);
          moveToTopRightCorner(isWrong);
          moveFrameDown(isWrong, 100);
        }
      }
      pcallF(onScore, game);
      if (alwaysNewImage) nextImage();
    }
    print("AI " + shortClassName(ai) + " points after " + rounds + " rounds: " + game.points);
    ai.done();
    if (game.points >= rounds) thread { showAnimationInTopLeftCorner(#1004373, game.points + " of " + rounds + " points!!", 3.0); }
    ret game;
  } finally {
    aiMode = false;
    awt {
      lblTiming.setText(formatDouble(toSeconds(sysNow()-start), 1) + " s");
      nextImage();
    }
  }
}

static AI getAI(Class<? extends AI> c) {
  AI ai = ais.get(c);
  if (ai == null) ais.put(c, ai = nu(c));
  ret ai;
}

// onScore: voidfunc(Game)
static Game testAI(Class<? extends AI> c, O onScore) {
  ret scoreAI(getAI(c), onScore);
}

Author comment

Began life as a copy of #1006752

download  show line numbers  debug dex  old transpilations   

Travelled to 14 computer(s): aoiabmzegqzx, bhatertpkbcr, cbybwowwnfue, cfunsshuasjs, gwrvuhgaqvyk, ishqpsrjomds, lpdgvwnxivlt, mqqgnosmbjvj, onxytkatvevr, pyentgdyhuwx, pzhvpgtvlbxg, tslmcundralx, tvejysmllsmz, vouqrxazstgt

No comments. add comment

Snippet ID: #1006753
Snippet name: Second A. I. Game Simplified & Solved
Eternal ID of this version: #1006753/130
Text MD5: 2e737c0b59655989c054e0c2444c7af2
Transpilation MD5: 8120804f7ea57b2990fbcfd34691461d
Author: stefan
Category: javax / gui
Type: JavaX source code
Public (visible to everyone): Yes
Archived (hidden from active list): No
Created/modified: 2017-02-03 23:58:17
Source code size: 9723 bytes / 332 lines
Pitched / IR pitched: No / No
Views / Downloads: 641 / 1095
Version history: 129 change(s)
Referenced in: [show references]