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...
Isso parece uma evolução de uma de suas perguntas anteriores , com pelo menos a diferença de que aqui temos um
minColumns
requisito.Não entendi muito bem por que no seu código há um tratamento específico para o caso
length==7
.Além disso, os dois blocos que verificam
length % maxColumns === 0
elength % (maxColumns - 1) === 0
parecem bastante arbitrários (como, por que então não tambémlength % (maxColumns - 2) === 0
, ...etc?): eles não parecem casos limites reais que precisam de tratamento especial.A condição de saída dentro do loop principal, quando
width <= minColumns
, não deve depender de você ter obtido um resultado bem-sucedido, mas pode ter sido considerada como umafor
condição de loop (o oposto disso).Há também um problema com
maxColumns -= maxColumns % dec
: ele tornamaxColumns
par quando era ímpar elength
é par. Em vez disso, você vai querermaxColumns
que seja tornado ímpar quandolength
é ímpar. Não me lembro por que isso aconteceu na resposta à sua pergunta anterior, onde a pergunta tinha menos especificações. De qualquer forma, isso precisa ser alterado. Pode ser mais fácil para a manutenção do código ter apenas uma condição dentro do loop principal.Parece haver pelo menos dois erros nos resultados esperados:
Vou assumir que deveria ser:
Aqui está o código corrigido com alguns dos seus casos de teste.