Tenho iterado com o Claude 3.7 Sonnet e o ChatGPT 4o por dias e dias, tentando fazer com que fique exatamente como eu quero, mas ele continua cometendo erros no algoritmo e, de vez em quando, cometendo os mesmos erros, basicamente em um círculo vicioso.
Como faço para criar um "layout" (matriz de inteiros), que representa uma grade, que tem as seguintes restrições:
- A função é
generateGridLayout(n, minColumns, maxColumns)
, onde na prática ela é normalmente chamada degen(n, 3, 7)
, mas em teoria poderia ser qualquer coisa que formaria uma grade legal,gen(n, 2, 256)
como o intervalo máximo. - Ele deve manipular um número arbitrário de elementos (digamos, até
Number.MAX_SAFE_INTEGER
, que é9007199254740991
, mas, na prática, meus "layouts de grade" terão apenas até 1000 itens). - Se o número de itens
n
for ímpar, cada linha deverá ter apenas um número ímpar de valores. Sen
for par, cada linha poderá ter números pares ou ímpares (pense em 30, podem ser 10 linhas de 3, ou 3 linhas de 10). - As linhas só podem diferir
2
em tamanho, sempre decrescente. Elas nunca podem diferir em 3, 4, etc. Isso significa que 7 NÃO PODE ser [5, 2] ou [4, 4, 1], pois esses têm saltos > 2. Só pode ser [7] ou [3, 3, 1], segen(7, 3, 7)
. - (nota meta: isso é para um layout de interface de usuário, então é baseado no tamanho da janela de visualização/contêiner, então se dissermos "máximo 7", mas houver espaço apenas para 5, ele definirá o máximo como 5, mas esse fato não é realmente relevante para a solução)
- Se dissermos "máximo é 7", mas houver um número par de itens, e o número par não puder satisfazer "todas as linhas pares ou ímpares", então tente
maxColumns - 1
, e assim por diante, atéminColumns
. - Importante: deve minimizar o número de linhas pequenas. Portanto, para 29, com 6 maxColumns, deve ser [5, 5, 5, 5, 5, 3, 1], e não [5, 5, 5, 5, 3, 3, 3]. Ou seja, maximiza o número de linhas grandes e minimiza o número de linhas pequenas. Da mesma forma, para 29, definitivamente não deve ser [5, 5, 5, 5, 3, 3, 1, 1, 1].
Aqui estão alguns exemplos para demonstrar o objetivo:
31
[5, 5, 5, 5, 5, 3, 3]
[3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 1]
30
[5, 5, 5, 5, 5, 5]
[3, 3, 3, 3, 3, 3, 3, 3, 3, 3]
29
[5, 5, 5, 5, 5, 3, 1]
[3, 3, 3, 3, 3, 3, 3, 3, 3, 1, 1]
28
[6, 6, 6, 6, 4]
[4, 4, 4, 4, 4, 4, 4]
27
[5, 5, 5, 5, 3, 3, 1]
[3, 3, 3, 3, 3, 3, 3, 3, 3]
26
[6, 6, 6, 4, 2, 2]
[4, 4, 4, 4, 4, 4, 4]
23
[5, 5, 5, 5, 3]
[3, 3, 3, 3, 3, 3, 3, 1, 1]
Elas mostram, se 5 ou 6 forem o máximo de colunas, o que ele faria, e o que deveria fazer se 4 ou 3 forem o máximo de colunas.
Por exemplo, 26 em 7 colunas no máximo NÃO devem ser:
[6, 6, 6, 6, 2] # jumps more than 2
[4, 4, 4, 4, 4, 4, 2] # doesn't maximize maxColumns
O ideal seria:
[6, 6, 6, 4, 2, 2] # jumps max 2, maximizes large columns, minimizes small columns.
Aqui está minha solução atual:
log(29, 2, 7)
log(29, 2, 6)
log(29, 2, 5)
log(29, 2, 4)
log(44, 2, 3)
function distributeGridLayout(
length,
minColumns,
maxColumns
) {
function recur(
dp,
length,
width,
) {
if (length == 0) {
return []
}
if (length < width - 2 || width <= 0) {
return
}
if (dp[width].has(length)) {
return
}
dp[width].add(length)
for (let i = 0; i < 2; i++) {
let result = recur(dp, length - width, width)
if (result) {
return [width, ...result]
}
width -= 2
}
return
}
if (length <= maxColumns) {
return [length]
}
if (maxColumns >= 3 && length === 7) {
return [3, 3, 1]
}
if (maxColumns >= minColumns && length % maxColumns === 0) {
const result = []
while (length) {
result.push(maxColumns)
length -= maxColumns
}
return result
}
if (maxColumns > 4) {
if (maxColumns > minColumns && length % (maxColumns - 1) === 0) {
const result = []
maxColumns--
while (length) {
result.push(maxColumns)
length -= maxColumns
}
return result
}
}
const dec = 2 - (length % 2)
maxColumns -= maxColumns % dec
const dp = Array.from(
{ length: maxColumns + 1 },
() => new Set(),
)
for (let width = maxColumns; width > 0; width -= dec) {
const result = recur(dp, length - width, width)
if (result) {
if (width <= minColumns) {
return
}
return [width, ...result]
}
}
return
}
function log(n, min, max) {
const grid = distributeGridLayout(n, min, max)
console.log(`gen(${n}, ${min}, ${max})`, grid)
}
Isso funciona para a maioria, como este layout tibetano (29 caracteres):

Mas não está funcionando para este layout tailandês (44 caracteres, em 2-3 colunas), aqui está o final (na minha interface, se o algoritmo retornar indefinido, ele volta para um layout de grade básico):

O que preciso mudar exatamente para que isso sempre se ajuste às minhas regras? O layout 44 de 3 no máximo e 2 minutos deve ser basicamente um layout de 2 colunas...