Skip to content

Commit 41c646b

Browse files
Grimyianh
authored andcommitted
Refactor output handling
1 parent b73f3c5 commit 41c646b

File tree

2 files changed

+67
-196
lines changed

2 files changed

+67
-196
lines changed

sim.c

Lines changed: 66 additions & 188 deletions
Original file line numberDiff line numberDiff line change
@@ -291,7 +291,7 @@ static void apply_conduit(struct solution *solution, struct board *board, struct
291291
remove_atom(board, (struct atom_ref_at_position){ a, p });
292292
} else {
293293
// bonds are consumed even if the atoms aren't.
294-
*a &= ~(ALL_BONDS & ~RECENT_BONDS & conduit->atoms[base + k].atom);
294+
*a &= ~(REAL_BONDS & conduit->atoms[base + k].atom);
295295
}
296296
add_produced_atom_collider(board, mechanism_relative_position(other_side, delta.u, delta.v, 1));
297297
}
@@ -1449,7 +1449,7 @@ static void match_repeating_output_with_chain_atoms(struct board *board, struct
14491449
if (!found_chain_atom)
14501450
return;
14511451
}
1452-
if ((a & (ANY_ATOM | (ALL_BONDS & ~RECENT_BONDS))) != output.atom)
1452+
if ((a & (ANY_ATOM | REAL_BONDS)) != output.atom)
14531453
return;
14541454
}
14551455
}
@@ -1458,217 +1458,96 @@ static void match_repeating_output_with_chain_atoms(struct board *board, struct
14581458
io->maximum_feed_rate = maximum_feed_rate;
14591459
}
14601460

1461-
static bool mark_output_position(struct board *board, struct vector pos)
1461+
static bool is_ignored_output_position(struct input_output *io, struct vector pos)
14621462
{
1463-
atom *a = lookup_atom(board, pos);
1464-
if ((*a & VISITED) || !(*a & VALID) || (*a & REMOVED))
1463+
// atoms cannot appear outside the vertical bounds of the
1464+
// infinite product.
1465+
if (pos.v < io->min_v || pos.v > io->max_v)
14651466
return false;
1466-
*a |= VISITED;
1467-
size_t capacity = board->marked.capacity;
1468-
while (board->marked.length >= capacity)
1469-
capacity = 4 * (capacity + 12) / 3;
1470-
if (capacity != board->marked.capacity) {
1471-
struct vector *positions = realloc(board->marked.positions,
1472-
sizeof(struct movement) * capacity);
1473-
if (!positions)
1474-
abort();
1475-
board->marked.positions = positions;
1476-
board->marked.capacity = capacity;
1477-
}
1478-
board->marked.positions[board->marked.length++] = pos;
1479-
return true;
1467+
// atoms cannot appear between atoms in a row of the infinite
1468+
// product. the row_min_v and row_max_v arrays track the
1469+
// disallowed range of positions for each row.
1470+
size_t row = pos.v - io->min_v;
1471+
return pos.u < io->row_min_u[row] || pos.u > io->row_max_u[row];
14801472
}
14811473

1482-
static void consume_output_with_overlap(struct solution *solution, struct board *board, struct input_output *io)
1474+
static void consume_output(struct solution *solution, struct board *board, struct input_output *io, int output_index)
14831475
{
1476+
bool fail_on_wrong_output = board->fails_on_wrong_output_mask & (1ULL << io->puzzle_index);
1477+
bool fail_on_wrong_bonds = board->fails_on_wrong_output_bonds_mask & (1ULL << io->puzzle_index);
1478+
bool wrong_output = false;
1479+
bool wrong_bonds = false;
1480+
bool repeating = io->type & REPEATING_OUTPUT;
1481+
14841482
struct mechanism m = { 0, io->atoms[io->center_atom_index].position };
14851483
struct molecule *molecule = get_molecule(board, get_atom(board, m, 0, 0));
14861484

1487-
if (molecule->size != io->number_of_atoms)
1485+
if (!repeating && molecule->size != io->number_of_atoms)
1486+
return;
1487+
if (repeating && molecule->size < io->number_of_atoms - 1)
14881488
return;
14891489

14901490
for (uint32_t i = 0; i < molecule->size; ++i) {
1491-
bool match = false;
14921491
struct atom_ref_at_position a = molecule->atoms[i];
1492+
if (repeating && is_ignored_output_position(io, a.position))
1493+
continue;
1494+
if (!repeating && (*a.atom & GRABBED))
1495+
return;
1496+
atom target = 0;
14931497
for (uint32_t j = 0; j < io->number_of_atoms; ++j) {
14941498
if (vectors_equal(a.position, io->atoms[j].position)) {
1495-
match = (*a.atom & (ANY_ATOM | (ALL_BONDS & ~RECENT_BONDS) | GRABBED)) == io->atoms[j].atom;
1499+
target = io->atoms[j].atom;
14961500
break;
14971501
}
14981502
}
1499-
if (!match)
1503+
if (!target)
1504+
return;
1505+
atom differences = *a.atom ^ target;
1506+
1507+
if ((differences & REAL_BONDS) && repeating && !wrong_bonds) {
1508+
// bonds that lead to an ignored position are allowed
1509+
for (int dir = 0; dir < 6; ++dir) {
1510+
struct vector d = u_offset_for_direction(dir);
1511+
struct vector neighbor = { a.position.u + d.u, a.position.v + d.v };
1512+
if (is_ignored_output_position(io, neighbor))
1513+
differences &= ~(BOND_LOW_BITS << dir);
1514+
}
1515+
}
1516+
1517+
wrong_output = wrong_output || ((differences & ANY_ATOM) && !(target & VARIABLE_OUTPUT));
1518+
wrong_bonds = wrong_bonds || (differences & REAL_BONDS);
1519+
if (!(fail_on_wrong_output || fail_on_wrong_bonds) && (wrong_output || wrong_bonds))
15001520
return;
15011521
}
15021522

1503-
remove_molecule(board, molecule);
1504-
io->number_of_outputs++;
1523+
if (fail_on_wrong_output && wrong_output) {
1524+
report_collision(board, io->atoms[0].position, "output didn't match");
1525+
board->wrong_output_index = output_index;
1526+
}
1527+
if (fail_on_wrong_bonds && wrong_bonds) {
1528+
report_collision(board, io->atoms[0].position, "output bonds didn't match");
1529+
board->wrong_output_index = output_index;
1530+
}
1531+
if (wrong_output || wrong_bonds)
1532+
return;
1533+
1534+
// if the output is a match remove the output and increment the output counter.
1535+
if (repeating) {
1536+
io->number_of_outputs = io->number_of_repetitions * io->outputs_per_repetition;
1537+
if (board->chain_mode == EXTEND_CHAIN)
1538+
match_repeating_output_with_chain_atoms(board, io);
1539+
} else {
1540+
remove_molecule(board, molecule);
1541+
io->number_of_outputs++;
1542+
}
15051543
}
15061544

15071545
static void consume_outputs(struct solution *solution, struct board *board)
15081546
{
15091547
for (size_t i = 0; i < solution->number_of_inputs_and_outputs; ++i) {
15101548
struct input_output *io = &solution->inputs_and_outputs[i];
1511-
if (!(io->type & OUTPUT))
1512-
continue;
1513-
bool fails_on_wrong_output = board->fails_on_wrong_output_mask & (1ULL << io->puzzle_index);
1514-
1515-
if (board->number_of_overlapped_atoms > 0
1516-
&& io->number_of_atoms > 1
1517-
&& !fails_on_wrong_output
1518-
&& !(io->type & REPEATING_OUTPUT)) {
1519-
consume_output_with_overlap(solution, board, io);
1520-
continue;
1521-
}
1522-
1523-
bool wrong_output = fails_on_wrong_output;
1524-
board->marked.length = 0;
1525-
// first, check the entire output to see if it matches.
1526-
bool match = true;
1527-
for (uint32_t j = 0; j < io->number_of_atoms; ++j) {
1528-
atom output = io->atoms[j].atom;
1529-
if (output & REPEATING_OUTPUT_PLACEHOLDER)
1530-
continue;
1531-
atom *a = lookup_atom(board, io->atoms[j].position);
1532-
// printf("checking %d %d... ", io->atoms[j].position.u, io->atoms[j].position.v);
1533-
if (!(*a & VALID) || (*a & REMOVED)) {
1534-
// printf("no atom\n");
1535-
match = false;
1536-
wrong_output = false;
1537-
break;
1538-
}
1539-
// variable outputs match any atom.
1540-
if (output & VARIABLE_OUTPUT) {
1541-
output &= ~VARIABLE_OUTPUT;
1542-
output |= *a & ANY_ATOM;
1543-
}
1544-
if (io->type & REPEATING_OUTPUT) {
1545-
uint64_t bond_mask = (((output & RECENT_BONDS) >> RECENT_BOND) * BOND_LOW_BITS) & ~RECENT_BONDS;
1546-
if ((*a & (ANY_ATOM | bond_mask)) != (output & (ANY_ATOM | bond_mask))) {
1547-
// printf("did not match at %d %d: %llx vs %llx\n", io->atoms[j].position.u, io->atoms[j].position.v, (*a & (ANY_ATOM | bond_mask)), output & (ANY_ATOM | bond_mask));
1548-
match = false;
1549-
break;
1550-
}
1551-
mark_output_position(board, io->atoms[j].position);
1552-
} else if (fails_on_wrong_output) {
1553-
if ((*a & (ALL_BONDS & ~RECENT_BONDS)) != (output & ALL_BONDS & ~RECENT_BONDS) || (*a & GRABBED)) {
1554-
match = false;
1555-
wrong_output = false;
1556-
break;
1557-
}
1558-
if ((*a & ANY_ATOM) != (output & ANY_ATOM)) {
1559-
match = false;
1560-
// this could be a wrong output.
1561-
}
1562-
} else {
1563-
if ((*a & (ANY_ATOM | (ALL_BONDS & ~RECENT_BONDS))) != output || (*a & GRABBED)) {
1564-
// printf("did not match at %d %d: %llx vs %llx\n", io->atoms[j].position.u, io->atoms[j].position.v, (*a & (ANY_ATOM | (ALL_BONDS & ~RECENT_BONDS))), output);
1565-
match = false;
1566-
break;
1567-
}
1568-
}
1569-
// printf("match!\n");
1570-
}
1571-
bool wrong_output_bonds = false;
1572-
if (board->fails_on_wrong_output_bonds_mask & (1ULL << io->puzzle_index)) {
1573-
wrong_output_bonds = true;
1574-
for (uint32_t j = 0; j < io->number_of_atoms; ++j) {
1575-
if (io->atoms[j].atom & REPEATING_OUTPUT_PLACEHOLDER)
1576-
continue;
1577-
atom *a = lookup_atom(board, io->atoms[j].position);
1578-
if (!(*a & VALID) || (*a & REMOVED) || (*a & GRABBED)) {
1579-
wrong_output_bonds = false;
1580-
break;
1581-
}
1582-
mark_output_position(board, io->atoms[j].position);
1583-
}
1584-
// if wrong_output_bonds is set at this point, then the molecule
1585-
// covers the output completely. the goal now is to determine
1586-
// whether there are any bonds leading out of the output shape. if
1587-
// so, the footprint doesn't match, so the output doesn't have wrong
1588-
// bonds.
1589-
for (uint32_t j = 0; !match && wrong_output_bonds && j < io->number_of_atoms; ++j) {
1590-
if (io->atoms[j].atom & REPEATING_OUTPUT_PLACEHOLDER)
1591-
continue;
1592-
atom a = *lookup_atom(board, io->atoms[j].position);
1593-
for (int bond_direction = 0; bond_direction < 6; ++bond_direction) {
1594-
if (!(a & (BOND_LOW_BITS << bond_direction) & ~RECENT_BONDS))
1595-
continue;
1596-
struct vector next = io->atoms[j].position;
1597-
struct vector d = u_offset_for_direction(bond_direction);
1598-
next.u += d.u;
1599-
next.v += d.v;
1600-
atom b = *lookup_atom(board, next);
1601-
if (!(b & VISITED)) {
1602-
wrong_output_bonds = false;
1603-
break;
1604-
}
1605-
}
1606-
}
1607-
}
1608-
// validating infinite products requires visiting all the atoms in the
1609-
// molecule. that's what this loop does.
1610-
if (io->type & REPEATING_OUTPUT) {
1611-
size_t cursor = 0;
1612-
while (match && cursor < board->marked.length) {
1613-
struct vector p = board->marked.positions[cursor++];
1614-
atom a = *lookup_atom(board, p);
1615-
if (a & IS_CHAIN_ATOM && board->chain_mode == EXTEND_CHAIN) {
1616-
// ensure atoms stay within the vertical region forever.
1617-
struct chain_atom ca = board->chain_atoms[lookup_chain_atom(board, p)];
1618-
if (ca.current_position.v - ca.original_position.v != 0) {
1619-
match = false;
1620-
break;
1621-
}
1622-
}
1623-
for (int bond_direction = 0; bond_direction < 6; ++bond_direction) {
1624-
if (!(a & (BOND_LOW_BITS << bond_direction) & ~RECENT_BONDS))
1625-
continue;
1626-
struct vector next = p;
1627-
struct vector d = u_offset_for_direction(bond_direction);
1628-
next.u += d.u;
1629-
next.v += d.v;
1630-
if (!mark_output_position(board, next))
1631-
continue;
1632-
// atoms cannot appear outside the vertical bounds of the
1633-
// infinite product.
1634-
if (next.v < io->min_v || next.v > io->max_v) {
1635-
match = false;
1636-
break;
1637-
}
1638-
// atoms cannot appear between atoms in a row of the infinite
1639-
// product. the row_min_v and row_max_v arrays track the
1640-
// disallowed range of positions for each row.
1641-
size_t row = next.v - io->min_v;
1642-
if (next.u >= io->row_min_u[row] && next.u <= io->row_max_u[row]) {
1643-
match = false;
1644-
break;
1645-
}
1646-
}
1647-
}
1648-
}
1649-
// reset the visited flag for all the marked atoms.
1650-
for (size_t j = 0; j < board->marked.length; ++j) {
1651-
atom *a = lookup_atom(board, board->marked.positions[j]);
1652-
*a &= ~VISITED;
1653-
}
1654-
if (match && (io->type & REPEATING_OUTPUT) && board->chain_mode == EXTEND_CHAIN)
1655-
match_repeating_output_with_chain_atoms(board, io);
1656-
// if the output is a match remove the output and increment the output counter.
1657-
if (match) {
1658-
if (io->type & REPEATING_OUTPUT)
1659-
io->number_of_outputs = io->number_of_repetitions * io->outputs_per_repetition;
1660-
else {
1661-
for (uint32_t j = 0; j < io->number_of_atoms; ++j)
1662-
remove_atom(board, (struct atom_ref_at_position){ lookup_atom(board, io->atoms[j].position), io->atoms[j].position });
1663-
io->number_of_outputs++;
1664-
}
1665-
} else if (wrong_output) {
1666-
report_collision(board, io->atoms[0].position, "output didn't match");
1667-
board->wrong_output_index = i;
1668-
} else if (wrong_output_bonds) {
1669-
report_collision(board, io->atoms[0].position, "output bonds didn't match");
1670-
board->wrong_output_index = i;
1671-
}
1549+
if (io->type & OUTPUT)
1550+
consume_output(solution, board, io, i);
16721551
}
16731552
}
16741553

@@ -2061,7 +1940,6 @@ void destroy(struct solution *solution, struct board *board)
20611940
free(board->flag_reset);
20621941
free(board->movements.movements);
20631942
free(board->moving_atoms.atoms_at_positions);
2064-
free(board->marked.positions);
20651943
free(board->overlapped_atoms);
20661944
free(board->chain_atoms);
20671945
free(board->chain_atom_table);

sim.h

Lines changed: 1 addition & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,7 @@ typedef uint64_t atom;
100100
#define TRIPLEX_K_BONDS (0x3FULL << TRIPLEX_BOND_K)
101101
#define TRIPLEX_BONDS (TRIPLEX_R_BONDS | TRIPLEX_Y_BONDS | TRIPLEX_K_BONDS)
102102
#define ALL_BONDS (0x3FULL * BOND_LOW_BITS)
103+
#define REAL_BONDS (ALL_BONDS & ~RECENT_BONDS)
103104
#define RIGHTWARD_BONDS (0x23ULL * BOND_LOW_BITS)
104105

105106
#define MAX_ATOMS_PER_HEX 6
@@ -394,11 +395,6 @@ struct moving_atoms {
394395
size_t length;
395396
size_t cursor;
396397
};
397-
struct marked_positions {
398-
struct vector *positions;
399-
size_t capacity;
400-
size_t length;
401-
};
402398

403399
// chain atoms participate in waste chain / polymer throughput detection.
404400
#define CHAIN_ATOM_ROTATION 7u
@@ -465,9 +461,6 @@ struct board {
465461
uint32_t number_of_atoms_being_produced;
466462
uint32_t atoms_being_produced_capacity;
467463

468-
// used for checking infinite products.
469-
struct marked_positions marked;
470-
471464
bool collision;
472465
struct vector collision_location;
473466
const char *collision_reason;

0 commit comments

Comments
 (0)