srecord noeq G22ChallengePanel(G22Challenge challenge) extends HasChangeListeners is Swingable { settableWithChange long randomSeed = 1; //randomUnsignedInt(); //transient JPanel imagesPanel = jline(); transient DynamicHStack imagesPanel; transient L entries = syncL(); transient JComponent imagesSection; transient GazelleV_LeftArrowScript.Script parsedScript; settableWithChange Set solutionTypes = syncSet(); transient JButton btnShowSolutions; transient G22LAScriptIDE recognizerIDE; transient settable G22Utils g22utils; settable bool autoRunChallenge; settable double timeoutToMakeAnImage = 10.0; settable double timeoutToRecognizeAnImage = 10.0; settable int imagesToPaint = 3; settable int interval = 100; settable int imageDisplaySize = 100; settable Color imageBorderColor1 = Color.green; settable Color imageBorderColor2 = Color.red; settable int imageBorderSize = 1; void init { recognizerIDE = new G22LAScriptIDE(g22utils); //recognizerIDE.sectionTitle("Recognizer " + roundBracket(recognizerIDE.sectionTitle)); recognizerIDE.modifyIDE = ide -> { ide.runScript = -> { var compileResult = ide.freshCompileResult(); var script = compileResult.parsedScript; if (script == null) ret; var bg = g22utils.backgroundProcessesUI(); temp bg?.tempAdd("Run recognizer on " + challenge); new FlexibleVarContext ctx; try { L results = syncL(); long time = sysNow(); for (Entry entry : filter(entries, e -> e.image != null)) { ctx.put(image := entry.image); var result = okOrError(-> ide.callCompiledObjectWithTimeout( timeoutToRecognizeAnImage, script, ctx)); results.add(result); entry.computerResult(result); } time = sysNow()-time; ide.showScriptResult(OKOrError.ok("Got " + nResults(results) + " in " + formatSeconds(time, 3) + " s")); } catch print e { ide.showScriptResult(OKOrError.error(e)); } }; }; } visualize { if (recognizerIDE == null) init(); imagesPanel = (DynamicHStack) dynamicHStack().spacing(20); awtCalcEvery(imagesPanel, interval, r _paintAnImage); ret withCenteredBoldTitle("Challenge: " + challenge, withTopMargin(jvsplit( northCenterAndSouthWithMargin( centerAndEastWithMargin( centeredLiveValueLabel( liveValue_hasChangeListeners(this, -> "Looking for: " + solutionTypeDesc())), swing(-> JPopDownButton(menu -> menu.add(jMenuItem("Random seed " + n2(randomSeed))))) ), imagesSection = jCenteredRaisedSection("Images", jBorderlessHigherScrollPane(jfullcenter(imagesPanel))), withBottomMargin(jCenteredLine(btnShowSolutions = jbutton("Show solutions", l0 showSolutions))) /*jRightAlignedLine( withLabel("Random seed:", liveValueLabel(liveValue_hasChangeListeners(this, -> randomSeed)))),*/ ), recognizerIDE.visualize() ))); } void _paintAnImage { if (!autoRunChallenge) ret; if (l(entries) >= imagesToPaint) ret; int index = l(entries)+1; Entry entry = new(index, (int) (randomSeed+index-1)); entries.add(entry); try { if (parsedScript == null) { var parser = g22utils.leftArrowParser(); var cleared = challenge.clearedForAutoRun(); parsedScript = parser.parse(cleared?!); } new FlexibleVarContext ctx; var returnedObject = evalWithTimeoutOrTypedException(timeoutToMakeAnImage, -> { temp tempSetRandomSeed((int) entry.seed); ret parsedScript.get(ctx); }); // can return image or put in variables "image" or "img" if (returnedObject == null) returnedObject = ctx.get("image"); if (returnedObject == null) returnedObject = ctx.get("img"); // convert to BufferedImage if (returnedObject instanceof MakesBufferedImage || returnedObject instanceof Image) returnedObject = toBufferedImage(returnedObject); if (returnedObject cast BufferedImage) { entry.solution(ctx.get("solution")); updateSolutionType(entry.solution); addImage(entry, returnedObject); } else if (returnedObject == null) addImage(entry, null, jcenteredlabel("No image"); else addImage(entry, null, jcenteredlabel("Not an image: " + shortClassName(returnedObject))); } catch print e { entry.error(e); addImage(entry, null, jSmallErrorView(e)); } finally { entry.calculating(false); } } void addImage(Entry entry, BufferedImage image, JComponent component) { entry.image(image).component(component); addAndRevalidate(imagesPanel, component); setSectionTitle(imagesSection, firstToUpper(nImages(entries)) + " calculated"); } void addImage(Entry entry, BufferedImage image) { entry.image(image); addImage(entry, image, new EntryComponent(entry).visualize()); } record noeq EntryComponent(Entry entry) is Swingable { // !customConstructor *(Entry *entry) { entry.entryComponent(this); } SingleComponentPanel scpSolution = singleComponentPanel(); SingleComponentPanel scpComputerResult = singleComponentPanel(); SingleComponentPanel scpCheckmark = singleComponentPanel(); visualize { var image = entry.image; double scale = calcFitScale(image, imageDisplaySize); var image2 = scaleImageWithOp(image, scale, AffineTransformOp.TYPE_NEAREST_NEIGHBOR); for (color : ll(imageBorderColor1, imageBorderColor2)) image2 = addBorderToImage(image2, color, imageBorderSize); S toolTip = "Image " + n2(entry.index) + " of " + challenge + " (seed " + n2(entry.seed) + ", " + image.getWidth() + "*" + image.getHeight() + " px)"; JButton b = withToolTip(toolTip, jimageButton(image2)); setMargin(10, b); ret centerAndSouthWithMargin(b, vstackWithSpacing(scpCheckmark, scpSolution, scpComputerResult)); } JComponent answerToComponent(O answer) { JComponent c; try { c = jCenteredLabel(shorten(g22utils.stringify(answer))); } catch e { c = jSmallErrorView(e); } ret jMaxWidth(imageDisplaySize+20, c); } void showSolution { scpSolution.set(withCenteredTitle("Solution", answerToComponent(entry.solution))); } void computerResult(OKOrError result) { scpComputerResult.set(withCenteredTitle("Computer Result", result.isOK() ? answerToComponent(result) : jSmallErrorView(result.error()))); scpCheckmark.set(entry.computerIsCorrect() ? jImage_scaledToHeight(32, checkmarkIconID(), "Computer is correct!!") : null); } } class Entry { int index; // index in sequence starting with 1 long seed; // seed for randomizer settable BufferedImage image; settable Throwable error; settable O solution; OKOrError computerResult; settable bool calculating = true; settable JComponent component; settable EntryComponent entryComponent; settable bool computerIsCorrect; *(int *index, long *seed) {} void computerResult(OKOrError result) { this.computerResult = result; computerIsCorrect(result.isOK() && eq(solution, result!)); entryComponent?.computerResult(result); } } void updateSolutionType(O solution) { Class c = _getClass(solution); if (solutionTypes.add(c)) change(); } S solutionTypeDesc() { LS types = map solutionTypeDesc(solutionTypes); ret textOut_or(types, "Calculating..."); } S solutionTypeDesc(Class c) { if (c == null) ret "no solution given"; if (c == Rect) ret "a rectangular area in the image"; ret aOrAn(shortClassName(c)); } void showSolutions { disableButton(btnShowSolutions); for (e : cloneList(entries)) if (e.entryComponent != null) e.entryComponent.showSolution(); } }