un clásico el 4, el que más ganas tengo de hacer y tengo la mañana liada :-(
bueno, hoy tenia ganas porque este problema lo he resuelto mil veces de mil maneras distintas, hoy he usado esta estrategia que es SIMD friendly y facil de paralelizar.
para cada posicion de la grid, genero todos los posibles neighbours, pero ojo, si busco XMAS, se que tengo que buscar 3 posciones para MAS, asique ya genero esto:
fn vectors(i: isize, j: isize) -> [[(isize, isize); 3]; 8] {
[
[(i - 1, j), (i - 2, j), (i - 3, j)],
[(i - 1, j + 1), (i - 2, j + 2), (i - 3, j + 3)],
[(i - 1, j - 1), (i - 2, j - 2), (i - 3, j - 3)],
[(i, j + 1), (i, j + 2), (i, j + 3)],
[(i, j - 1), (i, j - 2), (i, j - 3)],
[(i + 1, j + 1), (i + 2, j + 2), (i + 3, j + 3)],
[(i + 1, j - 1), (i + 2, j - 2), (i + 3, j - 3)],
[(i + 1, j), (i + 2, j), (i + 3, j)],
]
}
todos los movimientos, y el siguiente paso es acceder a estos valores y comprobar si es "MAS", obviamente la X me la salto xq ya se que he encontrado una X.
for vector in vectors {
let mas = vector
.iter()
.filter(|(i, j)| *i >= 0 && *j >= 0)
.filter_map(|(i, j)| {
grid.get(*i as usize)
.and_then(|row| row.get(*j as usize))
.copied()
})
.collect::<Vec<char>>();
if mas == ['M', 'A', 'S'] {
count += 1;
}
y voila, en lugar de ir comprovando de uno en uno con una stack, como en algunos problemas en que buscas caminos, haciendo busquedas/dfs/bfs y complicandote, he aplicado dos tecnicas:
- encoding del problema* tecnica de data oriented design avanzada, en este caso uso el conocimiento de las propiedades para hardcodear, aunque podria hacerlo con macros.
- vectores, en lugar de ir de uno en uno buscando, genero todo lo que quiero y hago match, trivial y SIMD friendly.
ahora si queremos podemos tirar 16 hilos, y que cada uno vaya buscando en posiciones randoms... como lo importante es que deben empezar por una X, y cada X es una (i, j) unica nunca tendremos colisiones.
y la parte dos la idea es similar, ahora desde la A, y cada A es una (i, j) unica, por tanto se peude paralelizar, y desde cada A solo tengo que buscar en las diagonales... trivial.
genero vectores
fn vectors_ms(i: isize, j: isize) -> [[(isize, isize); 2]; 2] {
[
[(i - 1, j - 1), (i + 1, j + 1)], // up-left + down-right
[(i - 1, j + 1), (i + 1, j - 1)], // up-right + down-left
]
}
y al mapear compruebo
if (left == ['M', 'S'] || left == ['S', 'M']) && (right == ['M', 'S'] || right == ['S', 'M']) {
count += 1;
}
mi solucion de hoy de nuevo full data oriented design, tratando de practicar y exprimir la cpu, ademas me ha salido paralelizable asique contento. me la pela la eficiencia cuando resuelvo decenas de millones de elementos en la sopa de letras en <1s