import java.util.*;
import java.util.zip.*;
import java.util.List;
import java.util.regex.*;
import java.util.concurrent.*;
import java.util.concurrent.atomic.*;
import java.util.concurrent.locks.*;
import java.util.function.*;
import javax.swing.*;
import javax.swing.event.*;
import javax.swing.text.*;
import javax.swing.table.*;
import java.io.*;
import java.net.*;
import java.lang.reflect.*;
import java.lang.ref.*;
import java.lang.management.*;
import java.security.*;
import java.security.spec.*;
import java.awt.*;
import java.awt.event.*;
import java.awt.image.*;
import java.awt.geom.*;
import javax.imageio.*;
import java.math.*;
import static x30_pkg.x30_util.DynamicObject;
import java.awt.image.DataBufferByte;
import java.awt.geom.*;
import java.text.*;
import java.text.NumberFormat;
import java.util.TimeZone;
import java.text.SimpleDateFormat;
import java.nio.charset.Charset;
class main {
static String test_G22RegionThinner(int repetitions, String imgString) {
return applyNTimes(__16 -> test_G22RegionThinner(__16), repetitions, imgString);
}
static String test_G22RegionThinner(String imgString) { return test_G22RegionThinner(imgString, false); }
static String test_G22RegionThinner(String imgString, boolean allSteps) {
var img = bwImageFromString(imgString);
//img = bwWhiteBorder(1, 1, img);
var image = toBufferedImage(img);
var itr = new Gazelle22_ImageToRegions(
new FunctionTimings(), image, new SnPSettings(image, 2));
itr.withDiagonals(true);
var region = g22_darkestRegion(itr.get());
G22RegionThinner_v2 thinner = new G22RegionThinner_v2(region);
step(thinner);
return bwImageToString(regionToBWImage_fullImageSize(thinner.get()));
}
static void test_G22RegionThinner_test(String in, String out) { test_G22RegionThinner_test(in, out, false); }
static void test_G22RegionThinner_test(String in, String out, boolean allSteps) {
testFunctionValue(s -> "\n" + test_G22RegionThinner(s), in, "\n" + mlsUnindent(out));
}
static void test_G22RegionThinner() {
test_G22RegionThinner_test(
"\r\n #####\r\n #####\r\n #####\r\n ",
"\r\n _____\r\n _###_\r\n _____\r\n ");
test_G22RegionThinner_test(
"\r\n #####\r\n #####\r\n ",
"\r\n #####\r\n #####\r\n ");
test_G22RegionThinner_test(
"\r\n ______\r\n _##___\r\n _###__\r\n __##__\r\n ____#_\r\n ______\r\n ",
"\r\n ______\r\n ______\r\n __##__\r\n __##__\r\n ____#_\r\n ______\r\n ");
test_G22RegionThinner_test(
"\r\n ######_\r\n #####__\r\n #####__\r\n ######_\r\n ######_\r\n #######\r\n ######_\r\n #######\r\n ########_\r\n #######__\r\n ",
"\r\n _______\r\n _###___\r\n _###___\r\n _####__\r\n _####__\r\n _#####_\r\n _####__\r\n _#####_\r\n _#####_\r\n _______\r\n ");
//theKProblem();
}
static void test_G22RegionThinner_theKProblem() {
test_G22RegionThinner_test(
"\r\n #___###\r\n #__###_\r\n #_###__\r\n ####___\r\n ",
"\r\n #___###\r\n #__###_\r\n #_###__\r\n ####___\r\n ", true);
}
static A applyNTimes(IF1 f, int n, A a) {
for (int _repeat_0 = 0; _repeat_0 < n; _repeat_0++) { a = f.get(a); }
return a;
}
// use x for black and _ for white
static BWImage bwImageFromString(String s) {
List lines = tlft(s);
if (empty(lines)) return null;
int h = l(lines), w = l(first(lines));
BWImage out = new BWImage(w, h);
for (int y = 0; y < h; y++) {
String line = lines.get(y);
for (int x = 0; x < w; x++)
if (charAt(line, x) == '_')
out.setInt(x, y, 255);
}
return out;
}
static BufferedImage toBufferedImage(Object o) {
return toBufferedImageOpt(o);
}
static IImageRegion g22_darkestRegion(IImageRegions regions) {
return regions == null ? null : lowest(regions.regions(), r -> r.brightness());
}
static boolean step(Steppable steppable) {
return steppable == null ? null : steppable.step();
}
// uses # for black and _ for white
static String bwImageToString(BWImage img) {
if (img == null) return null;
int w = img.getWidth(), h = img.getHeight();
return lines(countIterator(h, y ->
join(countIterator(w, x -> img.getInt(x, y) >= 128 ? '_' : '#'))));
}
static BWImage regionToBWImage_fullImageSize(IImageRegion region) {
RegionToBWImage maker = new RegionToBWImage(region);
maker.bounds(imageBounds(region.image()));
return maker.get();
}
// TODO: make work again for IF2 etc
static void testFunctionValue(IF1 function, A in, B expected) {
String what = print(renderFunctionCall(str(function), in));
assertEqualsVerbose(what, expected, function.get(in));
}
static String mlsUnindent(String s) {
return autoUnindent_mls(s);
}
static List tlft(String s) { return toLinesFullTrim(s); }
static List tlft(File f) { return toLinesFullTrim(f); }
static boolean empty(Collection c) { return c == null || c.isEmpty(); }
static boolean empty(Iterable c) { return c == null || !c.iterator().hasNext(); }
static boolean empty(CharSequence s) { return s == null || s.length() == 0; }
static boolean empty(Map map) { return map == null || map.isEmpty(); }
static boolean empty(Object[] o) { return o == null || o.length == 0; }
static boolean empty(BitSet bs) { return bs == null || bs.isEmpty(); }
static boolean empty(Object o) {
if (o instanceof Collection) return empty((Collection) o);
if (o instanceof String) return empty((String) o);
if (o instanceof Map) return empty((Map) o);
if (o instanceof Object[]) return empty((Object[]) o);
if (o instanceof byte[]) return empty((byte[]) o);
if (o == null) return true;
throw fail("unknown type for 'empty': " + getType(o));
}
static boolean empty(Iterator i) { return i == null || !i.hasNext(); }
static boolean empty(double[] a) { return a == null || a.length == 0; }
static boolean empty(float[] a) { return a == null || a.length == 0; }
static boolean empty(int[] a) { return a == null || a.length == 0; }
static boolean empty(long[] a) { return a == null || a.length == 0; }
static boolean empty(byte[] a) { return a == null || a.length == 0; }
static boolean empty(short[] a) { return a == null || a.length == 0; }
static boolean empty(IMultiMap mm) { return mm == null || mm.size() == 0; }
static boolean empty(File f) { return getFileSize(f) == 0; }
static boolean empty(IntRange r) { return r == null || r.empty(); }
static boolean empty(DoubleRange r) { return r == null || r.isEmpty(); }
static boolean empty(IntBuffer b) { return b == null || b.isEmpty(); }
static boolean empty(LongBuffer b) { return b == null || b.isEmpty(); }
static boolean empty(Rect r) { return !(r != null && r.w != 0 && r.h != 0); }
static boolean empty(Chain c) { return c == null; }
static boolean empty(AppendableChain c) { return c == null; }
static int l(Object[] a) { return a == null ? 0 : a.length; }
static int l(boolean[] a) { return a == null ? 0 : a.length; }
static int l(byte[] a) { return a == null ? 0 : a.length; }
static int l(short[] a) { return a == null ? 0 : a.length; }
static int l(long[] a) { return a == null ? 0 : a.length; }
static int l(int[] a) { return a == null ? 0 : a.length; }
static int l(float[] a) { return a == null ? 0 : a.length; }
static int l(double[] a) { return a == null ? 0 : a.length; }
static int l(char[] a) { return a == null ? 0 : a.length; }
static int l(Collection c) { return c == null ? 0 : c.size(); }
static int l(Iterator i) { return iteratorCount_int_close(i); } // consumes the iterator && closes it if possible
static int l(Map m) { return m == null ? 0 : m.size(); }
static int l(CharSequence s) { return s == null ? 0 : s.length(); }
static long l(File f) { return f == null ? 0 : f.length(); }
static int l(IMultiMap mm) { return mm == null ? 0 : mm.size(); }
static int l(IntRange r) { return r == null ? 0 : r.length(); }
static double l(DoubleRange r) { return r == null ? 0 : r.length(); }
static int l(IntBuffer b) { return b == null ? 0 : b.size(); }
static int l(LongBuffer b) { return b == null ? 0 : b.size(); }
static int l(AppendableChain a) { return a == null ? 0 : a.size; }
static Object first(Object list) {
return first((Iterable) list);
}
static A first(List list) {
return empty(list) ? null : list.get(0);
}
static A first(A[] bla) {
return bla == null || bla.length == 0 ? null : bla[0];
}
static Pair first(Map map) {
return mapEntryToPair(first(entrySet(map)));
}
static Pair first(MultiMap mm) {
if (mm == null) return null;
var e = first(mm.data.entrySet());
if (e == null) return null;
return pair(e.getKey(), first(e.getValue()));
}
static A first(IterableIterator i) {
return first((Iterator) i);
}
static A first(Iterator i) {
return i == null || !i.hasNext() ? null : i.next();
}
static A first(Iterable i) {
if (i == null) return null;
Iterator it = i.iterator();
return it.hasNext() ? it.next() : null;
}
static Character first(String s) { return empty(s) ? null : s.charAt(0); }
static Character first(CharSequence s) { return empty(s) ? null : s.charAt(0); }
static A first(Pair p) {
return p == null ? null : p.a;
}
static A first(T3 t) {
return t == null ? null : t.a;
}
static Byte first(byte[] l) {
return empty(l) ? null : l[0];
}
static int first(IntBuffer buf) {
return buf.get(0);
}
static byte first(ByteBuffer buf) {
return buf.get(0);
}
static A first(A[] l, IF1 pred) {
return firstThat(l, pred);
}
static A first(Iterable l, IF1 pred) {
return firstThat(l, pred);
}
static A first(IF1 pred, Iterable l) {
return firstThat(pred, l);
}
static A first(AppendableChain a) {
return a == null ? null : a.element;
}
static char charAt(String s, int i) {
return s != null && i >= 0 && i < s.length() ? s.charAt(i) : '\0';
}
static BufferedImage toBufferedImageOpt(Object o) {
if (o instanceof BufferedImage) return ((BufferedImage) o);
if (o instanceof Image) return copyImage((Image) o);
if (o instanceof MakesBufferedImage)
return ((MakesBufferedImage) o).getBufferedImage();
String c = getClassName(o);
// Keep this because it also works on imported objects
if (eqOneOf(c, "main$BWImage", "main$RGBImage"))
return (BufferedImage) call(o, "getBufferedImage");
return null;
}
static A lowest(Map map) {
A best = null;
Number bestScore = null;
for (A key : keys(map)) {
Number score = map.get(key);
if (best == null || cmp(score, bestScore) < 0) {
best = key;
bestScore = score;
}
}
return best;
}
static A lowest(Iterable l, IF1 f) {
return lowestByScoreFunction(l, f);
}
static String lines(Iterable lines) { return fromLines(lines); }
static String lines(Object[] lines) { return fromLines(asList(lines)); }
static List lines(String s) { return toLines(s); }
// convenience map call
static String lines(Iterable l, IF1 f) {
return mapToLines(l, f);
}
static IterableIterator countIterator(int b) { return countIterator(0, b); }
static IterableIterator countIterator(int a, int b) {
return countIterator_exclusive(a, b);
}
static IterableIterator countIterator(int b, IF1 f) { return countIterator(0, b, f); }
static IterableIterator countIterator(int a, int b, IF1 f) {
return countIterator_exclusive(a, b, f);
}
static IterableIterator countIterator(int a, int b, int step) {
return countIterator_exclusive_step(a, b, step);
}
static IterableIterator countIterator(double a, double b, double step, IF1 f) {
return countIterator_exclusive_step(a, b, step, f);
}
static IterableIterator countIterator(double a, double b, double step) {
return countIterator_exclusive_step(a, b, step);
}
static IterableIterator countIterator(IF1 f, double a, double b, double step) {
return countIterator(a, b, step, f);
}
static IterableIterator countIterator(IF1 f, int b) { return countIterator(f, 0, b); }
static IterableIterator countIterator(IF1 f, int a, int b) {
return countIterator_exclusive(a, b, f);
}
static IterableIterator countIterator(List l) {
return countIterator(l(l));
}
public static String join(String glue, Iterable strings) {
if (strings == null) return "";
if (strings instanceof Collection) {
if (((Collection) strings).size() == 1) return str(first((Collection) strings));
}
StringBuilder buf = new StringBuilder();
Iterator i = strings.iterator();
if (i.hasNext()) {
buf.append(i.next());
while (i.hasNext())
buf.append(glue).append(i.next());
}
return buf.toString();
}
public static String join(String glue, String... strings) {
return join(glue, Arrays.asList(strings));
}
public static String join(String glue, Object... strings) {
return join(glue, Arrays.asList(strings));
}
static String join(Iterable strings) {
return join("", strings);
}
static String join(Iterable strings, String glue) {
return join(glue, strings);
}
public static String join(String[] strings) {
return join("", strings);
}
static String join(String glue, Pair p) {
return p == null ? "" : str(p.a) + glue + str(p.b);
}
static Rect imageBounds(BufferedImage img) {
return imgRect(img);
}
static Rect imageBounds(WidthAndHeight img) {
return imgRect(img);
}
static volatile StringBuffer local_log = new StringBuffer(); // not redirected
static boolean printAlsoToSystemOut = true;
static volatile Appendable print_log = local_log; // might be redirected, e.g. to main bot
// in bytes - will cut to half that
static volatile int print_log_max = 1024*1024;
static volatile int local_log_max = 100*1024;
static boolean print_silent = false; // total mute if set
static Object print_byThread_lock = new Object();
static volatile ThreadLocal