Если бы мне пришлось делать это самому, я бы, вероятно, выбрал бы 2-мерный массив логических значений (особенно уменьшенный по масштабам, как предлагает jdv или использующий ускоренные графические процедуры) или подход со случайной точкой.
Если вы действительно хотите сделать более умный подход, вы можете просто рассмотреть прямоугольники. Начните с прямоугольника с углами (0,0), (1600,1200) = (lx, ly), (rx, ry) и «вычтите» первое окно (wx1, wy1) (wx2, wy2).
Это может генерировать не более 4 новых «еще доступных» прямоугольников, если оно полностью содержится в исходном свободном прямоугольнике: (например, все 4 угла нового окна содержатся в старом), они (lx, ly) - (rx, wy1), (lx, wy1) - (wx1, wy2), (wx2, wy1) - (rx, wy2) и (lx, wy2) - (rx, ry). Если только один угол окна перекрывается (только один угол находится внутри свободного прямоугольника), он разбивает его на два новых прямоугольника; если сторона (2 угла) выступает в нее, она разбивается на 3; и если нет перекрытия, ничего не меняется. (Если все они выровнены по осям, у вас не может быть 3 углов внутри).
Так что продолжайте циклически проходить по окнам, проверяя прямоугольники пересечения и деления, пока у вас не будет списка (если таковой имеется) всего оставшегося свободного пространства в виде прямоугольников.
Вероятно, это будет медленнее, чем любой из описанных выше подходов на основе графических библиотек, но было бы интереснее написать:)