A modern Music Player Daemon based on Rockbox open source high quality audio player
libadwaita audio rust zig deno mpris rockbox mpd
at master 667 lines 20 kB view raw
1/* 2 * Library code to divide up a rectangle into a number of equally 3 * sized ominoes, in a random fashion. 4 * 5 * Could use this for generating solved grids of 6 * http://www.nikoli.co.jp/ja/puzzles/block_puzzle/ 7 * or for generating the playfield for Jigsaw Sudoku. 8 */ 9 10/* 11 * This code is restricted to simply connected solutions: that is, 12 * no single polyomino may completely surround another (not even 13 * with a corner visible to the outside world, in the sense that a 14 * 7-omino can `surround' a single square). 15 * 16 * It's tempting to think that this is a natural consequence of 17 * all the ominoes being the same size - after all, a division of 18 * anything into 7-ominoes must necessarily have all of them 19 * simply connected, because if one was not then the 1-square 20 * space in the middle could not be part of any 7-omino - but in 21 * fact, for sufficiently large k, it is perfectly possible for a 22 * k-omino to completely surround another k-omino. A simple 23 * example is this one with two 25-ominoes: 24 * 25 * +--+--+--+--+--+--+--+ 26 * | | 27 * + +--+--+--+--+--+ + 28 * | | | | 29 * + + + + 30 * | | | | 31 * + + + +--+ 32 * | | | | 33 * + + + +--+ 34 * | | | | 35 * + + + + 36 * | | | | 37 * + +--+--+--+--+--+ + 38 * | | 39 * +--+--+--+--+--+--+--+ 40 * 41 * I claim the smallest k which can manage this is 23. More 42 * formally: 43 * 44 * If a k-omino P is completely surrounded by another k-omino Q, 45 * such that every edge of P borders on Q, then k >= 23. 46 * 47 * Proof: 48 * 49 * It's relatively simple to find the largest _rectangle_ a 50 * k-omino can enclose. So I'll construct my proof in two parts: 51 * firstly, show that no 22-omino or smaller can enclose a 52 * rectangle as large as itself, and secondly, show that no 53 * polyomino can enclose a larger non-rectangle than a rectangle. 54 * 55 * The first of those claims: 56 * 57 * To surround an m x n rectangle, a polyomino must have 2m 58 * squares along the two m-sides of the rectangle, 2n squares 59 * along the two n-sides, and must fill in at least three of the 60 * corners in order to be connected. Thus, 2(m+n)+3 <= k. We wish 61 * to find the largest value of mn subject to that constraint, and 62 * it's clear that this is achieved when m and n are as close to 63 * equal as possible. (If they aren't, WLOG suppose m < n; then 64 * (m+1)(n-1) = mn + n - m - 1 >= mn, with equality only when 65 * m=n-1.) 66 * 67 * So the area of the largest rectangle which can be enclosed by a 68 * k-omino is given by floor(k'/2) * ceil(k'/2), where k' = 69 * (k-3)/2. This is a monotonic function in k, so there will be a 70 * unique point at which it goes from being smaller than k to 71 * being larger than k. That point is between 22 (maximum area 20) 72 * and 23 (maximum area 25). 73 * 74 * The second claim: 75 * 76 * Suppose we have an inner polyomino P surrounded by an outer 77 * polyomino Q. I seek to show that if P is non-rectangular, then 78 * P is also non-maximal, in the sense that we can transform P and 79 * Q into a new pair of polyominoes in which P is larger and Q is 80 * at most the same size. 81 * 82 * Consider walking along the boundary of P in a clockwise 83 * direction. (We may assume, of course, that there is only _one_ 84 * boundary of P, i.e. P has no hole in the middle. If it does 85 * have a hole in the middle, it's _trivially_ non-maximal because 86 * we can just fill the hole in!) Our walk will take us along many 87 * edges between squares; sometimes we might turn left, and 88 * certainly sometimes we will turn right. Always there will be a 89 * square of P on our right, and a square of Q on our left. 90 * 91 * The net angle through which we turn during the entire walk must 92 * add up to 360 degrees rightwards. So if there are no left 93 * turns, then we must turn right exactly four times, meaning we 94 * have described a rectangle. Hence, if P is _not_ rectangular, 95 * then there must have been a left turn at some point. A left 96 * turn must mean we walk along two edges of the same square of Q. 97 * 98 * Thus, there is some square X in Q which is adjacent to two 99 * diagonally separated squares in P. Let us call those two 100 * squares N and E; let us refer to the other two neighbours of X 101 * as S and W; let us refer to the other mutual neighbour of S and 102 * W as D; and let us refer to the other mutual neighbour of S and 103 * E as Y. In other words, we have named seven squares, arranged 104 * thus: 105 * 106 * N 107 * W X E 108 * D S Y 109 * 110 * where N and E are in P, and X is in Q. 111 * 112 * Clearly at least one of W and S must be in Q (because otherwise 113 * X would not be connected to any other square in Q, and would 114 * hence have to be the whole of Q; and evidently if Q were a 115 * 1-omino it could not enclose _anything_). So we divide into 116 * cases: 117 * 118 * If both W and S are in Q, then we take X out of Q and put it in 119 * P, which does not expose any edge of P. If this disconnects Q, 120 * then we can reconnect it by adding D to Q. 121 * 122 * If only one of W and S is in Q, then wlog let it be W. If S is 123 * in _P_, then we have a particularly easy case: we can simply 124 * take X out of Q and add it to P, and this cannot disconnect X 125 * since X was a leaf square of Q. 126 * 127 * Our remaining case is that W is in Q and S is in neither P nor 128 * Q. Again we take X out of Q and put it in P; we also add S to 129 * Q. This ensures we do not expose an edge of P, but we must now 130 * prove that S is adjacent to some other existing square of Q so 131 * that we haven't disconnected Q by adding it. 132 * 133 * To do this, we recall that we walked along the edge XE, and 134 * then turned left to walk along XN. So just before doing all 135 * that, we must have reached the corner XSE, and we must have 136 * done it by walking along one of the three edges meeting at that 137 * corner which are _not_ XE. It can't have been SY, since S would 138 * then have been on our left and it isn't in Q; and it can't have 139 * been XS, since S would then have been on our right and it isn't 140 * in P. So it must have been YE, in which case Y was on our left, 141 * and hence is in Q. 142 * 143 * So in all cases we have shown that we can take X out of Q and 144 * add it to P, and add at most one square to Q to restore the 145 * containment and connectedness properties. Hence, we can keep 146 * doing this until we run out of left turns and P becomes 147 * rectangular. [] 148 * 149 * ------------ 150 * 151 * Anyway, that entire proof was a bit of a sidetrack. The point 152 * is, although constructions of this type are possible for 153 * sufficiently large k, divvy_rectangle() will never generate 154 * them. This could be considered a weakness for some purposes, in 155 * the sense that we can't generate all possible divisions. 156 * However, there are many divisions which we are highly unlikely 157 * to generate anyway, so in practice it probably isn't _too_ bad. 158 * 159 * If I wanted to fix this issue, I would have to make the rules 160 * more complicated for determining when a square can safely be 161 * _removed_ from a polyomino. Adding one becomes easier (a square 162 * may be added to a polyomino iff it is 4-adjacent to any square 163 * currently part of the polyomino, and the current test for loop 164 * formation may be dispensed with), but to determine which 165 * squares may be removed we must now resort to analysis of the 166 * overall structure of the polyomino rather than the simple local 167 * properties we can currently get away with measuring. 168 */ 169 170/* 171 * Possible improvements which might cut the fail rate: 172 * 173 * - instead of picking one omino to extend in an iteration, try 174 * them all in succession (in a randomised order) 175 * 176 * - (for real rigour) instead of bfsing over ominoes, bfs over 177 * the space of possible _removed squares_. That way we aren't 178 * limited to randomly choosing a single square to remove from 179 * an omino and failing if that particular square doesn't 180 * happen to work. 181 * 182 * However, I don't currently think it's necessary to do either of 183 * these, because the failure rate is already low enough to be 184 * easily tolerable, under all circumstances I've been able to 185 * think of. 186 */ 187 188#include <assert.h> 189#include <stdio.h> 190#include <stdlib.h> 191#include <stddef.h> 192 193#include "puzzles.h" 194 195/* 196 * Subroutine which implements a function used in computing both 197 * whether a square can safely be added to an omino, and whether 198 * it can safely be removed. 199 * 200 * We enumerate the eight squares 8-adjacent to this one, in 201 * cyclic order. We go round that loop and count the number of 202 * times we find a square owned by the target omino next to one 203 * not owned by it. We then return success iff that count is 2. 204 * 205 * When adding a square to an omino, this is precisely the 206 * criterion which tells us that adding the square won't leave a 207 * hole in the middle of the omino. (If it did, then things get 208 * more complicated; see above.) 209 * 210 * When removing a square from an omino, the _same_ criterion 211 * tells us that removing the square won't disconnect the omino. 212 * (This only works _because_ we've ensured the omino is simply 213 * connected.) 214 */ 215static bool addremcommon(int w, int h, int x, int y, int *own, int val) 216{ 217 int neighbours[8]; 218 int dir, count; 219 220 for (dir = 0; dir < 8; dir++) { 221 int dx = ((dir & 3) == 2 ? 0 : dir > 2 && dir < 6 ? +1 : -1); 222 int dy = ((dir & 3) == 0 ? 0 : dir < 4 ? -1 : +1); 223 int sx = x+dx, sy = y+dy; 224 225 if (sx < 0 || sx >= w || sy < 0 || sy >= h) 226 neighbours[dir] = -1; /* outside the grid */ 227 else 228 neighbours[dir] = own[sy*w+sx]; 229 } 230 231 /* 232 * To begin with, check 4-adjacency. 233 */ 234 if (neighbours[0] != val && neighbours[2] != val && 235 neighbours[4] != val && neighbours[6] != val) 236 return false; 237 238 count = 0; 239 240 for (dir = 0; dir < 8; dir++) { 241 int next = (dir + 1) & 7; 242 bool gotthis = (neighbours[dir] == val); 243 bool gotnext = (neighbours[next] == val); 244 245 if (gotthis != gotnext) 246 count++; 247 } 248 249 return (count == 2); 250} 251 252/* 253 * w and h are the dimensions of the rectangle. 254 * 255 * k is the size of the required ominoes. (So k must divide w*h, 256 * of course.) 257 * 258 * The returned result is a w*h-sized dsf. 259 * 260 * In both of the above suggested use cases, the user would 261 * probably want w==h==k, but that isn't a requirement. 262 */ 263DSF *divvy_rectangle_attempt(int w, int h, int k, random_state *rs) 264{ 265 int *order, *queue, *tmp, *own, *sizes, *addable; 266 DSF *retdsf, *tmpdsf; 267 bool *removable; 268 int wh = w*h; 269 int i, j, n, x, y, qhead, qtail; 270 271 n = wh / k; 272 assert(wh == k*n); 273 274 order = snewn(wh, int); 275 tmp = snewn(wh, int); 276 own = snewn(wh, int); 277 sizes = snewn(n, int); 278 queue = snewn(n, int); 279 addable = snewn(wh*4, int); 280 removable = snewn(wh, bool); 281 retdsf = tmpdsf = NULL; 282 283 /* 284 * Permute the grid squares into a random order, which will be 285 * used for iterating over the grid whenever we need to search 286 * for something. This prevents directional bias and arranges 287 * for the answer to be non-deterministic. 288 */ 289 for (i = 0; i < wh; i++) 290 order[i] = i; 291 shuffle(order, wh, sizeof(*order), rs); 292 293 /* 294 * Begin by choosing a starting square at random for each 295 * omino. 296 */ 297 for (i = 0; i < wh; i++) { 298 own[i] = -1; 299 } 300 for (i = 0; i < n; i++) { 301 own[order[i]] = i; 302 sizes[i] = 1; 303 } 304 305 /* 306 * Now repeatedly pick a random omino which isn't already at 307 * the target size, and find a way to expand it by one. This 308 * may involve stealing a square from another omino, in which 309 * case we then re-expand that omino, forming a chain of 310 * square-stealing which terminates in an as yet unclaimed 311 * square. Hence every successful iteration around this loop 312 * causes the number of unclaimed squares to drop by one, and 313 * so the process is bounded in duration. 314 */ 315 while (1) { 316 317#ifdef DIVVY_DIAGNOSTICS 318 { 319 int x, y; 320 printf("Top of loop. Current grid:\n"); 321 for (y = 0; y < h; y++) { 322 for (x = 0; x < w; x++) 323 printf("%3d", own[y*w+x]); 324 printf("\n"); 325 } 326 } 327#endif 328 329 /* 330 * Go over the grid and figure out which squares can 331 * safely be added to, or removed from, each omino. We 332 * don't take account of other ominoes in this process, so 333 * we will often end up knowing that a square can be 334 * poached from one omino by another. 335 * 336 * For each square, there may be up to four ominoes to 337 * which it can be added (those to which it is 338 * 4-adjacent). 339 */ 340 for (y = 0; y < h; y++) { 341 for (x = 0; x < w; x++) { 342 int yx = y*w+x; 343 int curr = own[yx]; 344 int dir; 345 346 if (curr < 0) { 347 removable[yx] = false; /* can't remove if not owned! */ 348 } else if (sizes[curr] == 1) { 349 removable[yx] = true; /* can always remove a singleton */ 350 } else { 351 /* 352 * See if this square can be removed from its 353 * omino without disconnecting it. 354 */ 355 removable[yx] = addremcommon(w, h, x, y, own, curr); 356 } 357 358 for (dir = 0; dir < 4; dir++) { 359 int dx = (dir == 0 ? -1 : dir == 1 ? +1 : 0); 360 int dy = (dir == 2 ? -1 : dir == 3 ? +1 : 0); 361 int sx = x + dx, sy = y + dy; 362 int syx = sy*w+sx; 363 364 addable[yx*4+dir] = -1; 365 366 if (sx < 0 || sx >= w || sy < 0 || sy >= h) 367 continue; /* no omino here! */ 368 if (own[syx] < 0) 369 continue; /* also no omino here */ 370 if (own[syx] == own[yx]) 371 continue; /* we already got one */ 372 if (!addremcommon(w, h, x, y, own, own[syx])) 373 continue; /* would non-simply connect the omino */ 374 375 addable[yx*4+dir] = own[syx]; 376 } 377 } 378 } 379 380 for (i = j = 0; i < n; i++) 381 if (sizes[i] < k) 382 tmp[j++] = i; 383 if (j == 0) 384 break; /* all ominoes are complete! */ 385 j = tmp[random_upto(rs, j)]; 386#ifdef DIVVY_DIAGNOSTICS 387 printf("Trying to extend %d\n", j); 388#endif 389 390 /* 391 * So we're trying to expand omino j. We breadth-first 392 * search out from j across the space of ominoes. 393 * 394 * For bfs purposes, we use two elements of tmp per omino: 395 * tmp[2*i+0] tells us which omino we got to i from, and 396 * tmp[2*i+1] numbers the grid square that omino stole 397 * from us. 398 * 399 * This requires that wh (the size of tmp) is at least 2n, 400 * i.e. k is at least 2. There would have been nothing to 401 * stop a user calling this function with k=1, but if they 402 * did then we wouldn't have got to _here_ in the code - 403 * we would have noticed above that all ominoes were 404 * already at their target sizes, and terminated :-) 405 */ 406 assert(wh >= 2*n); 407 for (i = 0; i < n; i++) 408 tmp[2*i] = tmp[2*i+1] = -1; 409 qhead = qtail = 0; 410 queue[qtail++] = j; 411 tmp[2*j] = tmp[2*j+1] = -2; /* special value: `starting point' */ 412 413 while (qhead < qtail) { 414 int tmpsq; 415 416 j = queue[qhead]; 417 418 /* 419 * We wish to expand omino j. However, we might have 420 * got here by omino j having a square stolen from it, 421 * so first of all we must temporarily mark that 422 * square as not belonging to j, so that our adjacency 423 * calculations don't assume j _does_ belong to us. 424 */ 425 tmpsq = tmp[2*j+1]; 426 if (tmpsq >= 0) { 427 assert(own[tmpsq] == j); 428 own[tmpsq] = -3; 429 } 430 431 /* 432 * OK. Now begin by seeing if we can find any 433 * unclaimed square into which we can expand omino j. 434 * If we find one, the entire bfs terminates. 435 */ 436 for (i = 0; i < wh; i++) { 437 int dir; 438 439 if (own[order[i]] != -1) 440 continue; /* this square is claimed */ 441 442 /* 443 * Special case: if our current omino was size 1 444 * and then had a square stolen from it, it's now 445 * size zero, which means it's valid to `expand' 446 * it into _any_ unclaimed square. 447 */ 448 if (sizes[j] == 1 && tmpsq >= 0) 449 break; /* got one */ 450 451 /* 452 * Failing that, we must do the full test for 453 * addability. 454 */ 455 for (dir = 0; dir < 4; dir++) 456 if (addable[order[i]*4+dir] == j) { 457 /* 458 * We know this square is addable to this 459 * omino with the grid in the state it had 460 * at the top of the loop. However, we 461 * must now check that it's _still_ 462 * addable to this omino when the omino is 463 * missing a square. To do this it's only 464 * necessary to re-check addremcommon. 465 */ 466 if (!addremcommon(w, h, order[i]%w, order[i]/w, 467 own, j)) 468 continue; 469 break; 470 } 471 if (dir == 4) 472 continue; /* we can't add this square to j */ 473 474 break; /* got one! */ 475 } 476 if (i < wh) { 477 i = order[i]; 478 479 /* 480 * Restore the temporarily removed square _before_ 481 * we start shifting ownerships about. 482 */ 483 if (tmpsq >= 0) 484 own[tmpsq] = j; 485 486 /* 487 * We are done. We can add square i to omino j, 488 * and then backtrack along the trail in tmp 489 * moving squares between ominoes, ending up 490 * expanding our starting omino by one. 491 */ 492#ifdef DIVVY_DIAGNOSTICS 493 printf("(%d,%d)", i%w, i/w); 494#endif 495 while (1) { 496 own[i] = j; 497#ifdef DIVVY_DIAGNOSTICS 498 printf(" -> %d", j); 499#endif 500 if (tmp[2*j] == -2) 501 break; 502 i = tmp[2*j+1]; 503 j = tmp[2*j]; 504#ifdef DIVVY_DIAGNOSTICS 505 printf("; (%d,%d)", i%w, i/w); 506#endif 507 } 508#ifdef DIVVY_DIAGNOSTICS 509 printf("\n"); 510#endif 511 512 /* 513 * Increment the size of the starting omino. 514 */ 515 sizes[j]++; 516 517 /* 518 * Terminate the bfs loop. 519 */ 520 break; 521 } 522 523 /* 524 * If we get here, we haven't been able to expand 525 * omino j into an unclaimed square. So now we begin 526 * to investigate expanding it into squares which are 527 * claimed by ominoes the bfs has not yet visited. 528 */ 529 for (i = 0; i < wh; i++) { 530 int dir, nj; 531 532 nj = own[order[i]]; 533 if (nj < 0 || tmp[2*nj] != -1) 534 continue; /* unclaimed, or owned by wrong omino */ 535 if (!removable[order[i]]) 536 continue; /* its omino won't let it go */ 537 538 for (dir = 0; dir < 4; dir++) 539 if (addable[order[i]*4+dir] == j) { 540 /* 541 * As above, re-check addremcommon. 542 */ 543 if (!addremcommon(w, h, order[i]%w, order[i]/w, 544 own, j)) 545 continue; 546 547 /* 548 * We have found a square we can use to 549 * expand omino j, at the expense of the 550 * as-yet unvisited omino nj. So add this 551 * to the bfs queue. 552 */ 553 assert(qtail < n); 554 queue[qtail++] = nj; 555 tmp[2*nj] = j; 556 tmp[2*nj+1] = order[i]; 557 558 /* 559 * Now terminate the loop over dir, to 560 * ensure we don't accidentally add the 561 * same omino twice to the queue. 562 */ 563 break; 564 } 565 } 566 567 /* 568 * Restore the temporarily removed square. 569 */ 570 if (tmpsq >= 0) 571 own[tmpsq] = j; 572 573 /* 574 * Advance the queue head. 575 */ 576 qhead++; 577 } 578 579 if (qhead == qtail) { 580 /* 581 * We have finished the bfs and not found any way to 582 * expand omino j. Panic, and return failure. 583 * 584 * FIXME: or should we loop over all ominoes before we 585 * give up? 586 */ 587#ifdef DIVVY_DIAGNOSTICS 588 printf("FAIL!\n"); 589#endif 590 retdsf = NULL; 591 goto cleanup; 592 } 593 } 594 595#ifdef DIVVY_DIAGNOSTICS 596 { 597 int x, y; 598 printf("SUCCESS! Final grid:\n"); 599 for (y = 0; y < h; y++) { 600 for (x = 0; x < w; x++) 601 printf("%3d", own[y*w+x]); 602 printf("\n"); 603 } 604 } 605#endif 606 607 /* 608 * Construct the output dsf. 609 */ 610 for (i = 0; i < wh; i++) { 611 assert(own[i] >= 0 && own[i] < n); 612 tmp[own[i]] = i; 613 } 614 retdsf = dsf_new(wh); 615 for (i = 0; i < wh; i++) { 616 dsf_merge(retdsf, i, tmp[own[i]]); 617 } 618 619 /* 620 * Construct the output dsf a different way, to verify that 621 * the ominoes really are k-ominoes and we haven't 622 * accidentally split one into two disconnected pieces. 623 */ 624 tmpdsf = dsf_new(wh); 625 for (y = 0; y < h; y++) 626 for (x = 0; x+1 < w; x++) 627 if (own[y*w+x] == own[y*w+(x+1)]) 628 dsf_merge(tmpdsf, y*w+x, y*w+(x+1)); 629 for (x = 0; x < w; x++) 630 for (y = 0; y+1 < h; y++) 631 if (own[y*w+x] == own[(y+1)*w+x]) 632 dsf_merge(tmpdsf, y*w+x, (y+1)*w+x); 633 for (i = 0; i < wh; i++) { 634 j = dsf_canonify(retdsf, i); 635 assert(dsf_equivalent(tmpdsf, j, i)); 636 } 637 638 cleanup: 639 640 /* 641 * Free our temporary working space. 642 */ 643 sfree(order); 644 sfree(tmp); 645 dsf_free(tmpdsf); 646 sfree(own); 647 sfree(sizes); 648 sfree(queue); 649 sfree(addable); 650 sfree(removable); 651 652 /* 653 * And we're done. 654 */ 655 return retdsf; 656} 657 658DSF *divvy_rectangle(int w, int h, int k, random_state *rs) 659{ 660 DSF *ret; 661 662 do { 663 ret = divvy_rectangle_attempt(w, h, k, rs); 664 } while (!ret); 665 666 return ret; 667}