~ubuntu-branches/ubuntu/wily/sgt-puzzles/wily

« back to all changes in this revision

Viewing changes to pattern.c

  • Committer: Package Import Robot
  • Author(s): Ben Hutchings
  • Date: 2013-06-30 03:20:16 UTC
  • mfrom: (1.2.13)
  • Revision ID: package-import@ubuntu.com-20130630032016-v8xqt6vtg6tgs420
Tags: 9872-1
* New upstream version
  - Add an explicit -lm to the link lines in Makefile.gtk (Closes: #713476)
  - Add Undead by Steffen Bauer, an implementation of 'Haunted Mirror Maze'
  - Add Unruly by Lennard Sprong, an implementation of a puzzle usually
    called 'Tohu wa Vohu'
* Add DEP-3 headers to patches
* pearl: Require width or height to be at least 6 for Tricky
  (Closes: #667963)
* debian/watch: Update ViewVC URL regex
* Add 'sgt-' prefix to all command names and remove 'game' suffix, but
  retain symlinks under the old names (see #684193)
* Use upstream short descriptions in English manual pages and package
  description
* Update German translation, thanks to Helge Kreutzmann

Show diffs side-by-side

added added

removed removed

Lines of Context:
19
19
    COL_UNKNOWN,
20
20
    COL_GRID,
21
21
    COL_CURSOR,
 
22
    COL_ERROR,
22
23
    NCOLOURS
23
24
};
24
25
 
96
97
    sfree(params);
97
98
}
98
99
 
99
 
static game_params *dup_params(game_params *params)
 
100
static game_params *dup_params(const game_params *params)
100
101
{
101
102
    game_params *ret = snew(game_params);
102
103
    *ret = *params;                    /* structure copy */
118
119
    }
119
120
}
120
121
 
121
 
static char *encode_params(game_params *params, int full)
 
122
static char *encode_params(const game_params *params, int full)
122
123
{
123
124
    char ret[400];
124
125
    int len;
130
131
    return dupstr(ret);
131
132
}
132
133
 
133
 
static config_item *game_configure(game_params *params)
 
134
static config_item *game_configure(const game_params *params)
134
135
{
135
136
    config_item *ret;
136
137
    char buf[80];
157
158
    return ret;
158
159
}
159
160
 
160
 
static game_params *custom_params(config_item *cfg)
 
161
static game_params *custom_params(const config_item *cfg)
161
162
{
162
163
    game_params *ret = snew(game_params);
163
164
 
167
168
    return ret;
168
169
}
169
170
 
170
 
static char *validate_params(game_params *params, int full)
 
171
static char *validate_params(const game_params *params, int full)
171
172
{
172
173
    if (params->w <= 0 || params->h <= 0)
173
174
        return "Width and height must both be greater than zero";
343
344
int verbose = FALSE;
344
345
#endif
345
346
 
346
 
static void do_recurse(unsigned char *known, unsigned char *deduced,
347
 
                       unsigned char *row, int *data, int len,
 
347
static int do_recurse(unsigned char *known, unsigned char *deduced,
 
348
                       unsigned char *row,
 
349
                       unsigned char *minpos_done, unsigned char *maxpos_done,
 
350
                       unsigned char *minpos_ok, unsigned char *maxpos_ok,
 
351
                       int *data, int len,
348
352
                       int freespace, int ndone, int lowest)
349
353
{
350
354
    int i, j, k;
351
355
 
 
356
 
 
357
    /* This algorithm basically tries all possible ways the given rows of
 
358
     * black blocks can be laid out in the row/column being examined.
 
359
     * Special care is taken to avoid checking the tail of a row/column
 
360
     * if the same conditions have already been checked during this recursion
 
361
     * The algorithm also takes care to cut its losses as soon as an
 
362
     * invalid (partial) solution is detected.
 
363
     */
352
364
    if (data[ndone]) {
 
365
        if (lowest >= minpos_done[ndone] && lowest <= maxpos_done[ndone]) {
 
366
            if (lowest >= minpos_ok[ndone] && lowest <= maxpos_ok[ndone]) {
 
367
                for (i=0; i<lowest; i++)
 
368
                    deduced[i] |= row[i];
 
369
            }
 
370
            return lowest >= minpos_ok[ndone] && lowest <= maxpos_ok[ndone];
 
371
        } else {
 
372
            if (lowest < minpos_done[ndone]) minpos_done[ndone] = lowest;
 
373
            if (lowest > maxpos_done[ndone]) maxpos_done[ndone] = lowest;
 
374
        }
353
375
        for (i=0; i<=freespace; i++) {
354
376
            j = lowest;
355
 
            for (k=0; k<i; k++) row[j++] = DOT;
356
 
            for (k=0; k<data[ndone]; k++) row[j++] = BLOCK;
357
 
            if (j < len) row[j++] = DOT;
358
 
            do_recurse(known, deduced, row, data, len,
359
 
                       freespace-i, ndone+1, j);
 
377
            for (k=0; k<i; k++) {
 
378
                if (known[j] == BLOCK) goto next_iter;
 
379
                row[j++] = DOT;
 
380
            }
 
381
            for (k=0; k<data[ndone]; k++) {
 
382
                if (known[j] == DOT) goto next_iter;
 
383
                row[j++] = BLOCK;
 
384
            }
 
385
            if (j < len) {
 
386
                if (known[j] == BLOCK) goto next_iter;
 
387
                row[j++] = DOT;
 
388
            }
 
389
            if (do_recurse(known, deduced, row, minpos_done, maxpos_done,
 
390
                           minpos_ok, maxpos_ok, data, len, freespace-i, ndone+1, j)) {
 
391
                if (lowest < minpos_ok[ndone]) minpos_ok[ndone] = lowest;
 
392
                if (lowest + i > maxpos_ok[ndone]) maxpos_ok[ndone] = lowest + i;
 
393
                if (lowest + i > maxpos_done[ndone]) maxpos_done[ndone] = lowest + i;
 
394
            }
 
395
            next_iter:
 
396
            j++;
360
397
        }
 
398
        return lowest >= minpos_ok[ndone] && lowest <= maxpos_ok[ndone];
361
399
    } else {
362
 
        for (i=lowest; i<len; i++)
 
400
        for (i=lowest; i<len; i++) {
 
401
            if (known[i] == BLOCK) return FALSE;
363
402
            row[i] = DOT;
364
 
        for (i=0; i<len; i++)
365
 
            if (known[i] && known[i] != row[i])
366
 
                return;
 
403
            }
367
404
        for (i=0; i<len; i++)
368
405
            deduced[i] |= row[i];
 
406
        return TRUE;
369
407
    }
370
408
}
371
409
 
 
410
 
372
411
static int do_row(unsigned char *known, unsigned char *deduced,
373
412
                  unsigned char *row,
374
 
                  unsigned char *start, int len, int step, int *data
 
413
                  unsigned char *minpos_done, unsigned char *maxpos_done,
 
414
                  unsigned char *minpos_ok, unsigned char *maxpos_ok,
 
415
                  unsigned char *start, int len, int step, int *data,
 
416
                  unsigned int *changed
375
417
#ifdef STANDALONE_SOLVER
376
418
                  , const char *rowcol, int index, int cluewid
377
419
#endif
380
422
    int rowlen, i, freespace, done_any;
381
423
 
382
424
    freespace = len+1;
383
 
    for (rowlen = 0; data[rowlen]; rowlen++)
 
425
    for (rowlen = 0; data[rowlen]; rowlen++) {
 
426
        minpos_done[rowlen] = minpos_ok[rowlen] = len - 1;
 
427
        maxpos_done[rowlen] = maxpos_ok[rowlen] = 0;
384
428
        freespace -= data[rowlen]+1;
 
429
    }
385
430
 
386
431
    for (i = 0; i < len; i++) {
387
432
        known[i] = start[i*step];
388
433
        deduced[i] = 0;
389
434
    }
390
 
 
391
 
    do_recurse(known, deduced, row, data, len, freespace, 0, 0);
 
435
    for (i = len - 1; i >= 0 && known[i] == DOT; i--)
 
436
        freespace--;
 
437
 
 
438
    do_recurse(known, deduced, row, minpos_done, maxpos_done, minpos_ok, maxpos_ok, data, len, freespace, 0, 0);
 
439
 
392
440
    done_any = FALSE;
393
441
    for (i=0; i<len; i++)
394
442
        if (deduced[i] && deduced[i] != STILL_UNKNOWN && !known[i]) {
395
443
            start[i*step] = deduced[i];
 
444
            if (changed) changed[i]++;
396
445
            done_any = TRUE;
397
446
        }
398
447
#ifdef STANDALONE_SOLVER
419
468
    return done_any;
420
469
}
421
470
 
 
471
static int solve_puzzle(const game_state *state, unsigned char *grid,
 
472
                        int w, int h,
 
473
                        unsigned char *matrix, unsigned char *workspace,
 
474
                        unsigned int *changed_h, unsigned int *changed_w,
 
475
                        int *rowdata
 
476
#ifdef STANDALONE_SOLVER
 
477
                        , int cluewid
 
478
#else
 
479
                        , int dummy
 
480
#endif
 
481
                        )
 
482
{
 
483
    int i, j, ok, max;
 
484
    int max_h, max_w;
 
485
 
 
486
    assert((state!=NULL) ^ (grid!=NULL));
 
487
 
 
488
    max = max(w, h);
 
489
 
 
490
    memset(matrix, 0, w*h);
 
491
 
 
492
    /* For each column, compute how many squares can be deduced
 
493
     * from just the row-data.
 
494
     * Later, changed_* will hold how many squares were changed
 
495
     * in every row/column in the previous iteration
 
496
     * Changed_* is used to choose the next rows / cols to re-examine
 
497
     */
 
498
    for (i=0; i<h; i++) {
 
499
        int freespace;
 
500
        if (state) {
 
501
            memcpy(rowdata, state->rowdata + state->rowsize*(w+i), max*sizeof(int));
 
502
            rowdata[state->rowlen[w+i]] = 0;
 
503
        } else {
 
504
            rowdata[compute_rowdata(rowdata, grid+i*w, w, 1)] = 0;
 
505
        }
 
506
        for (j=0, freespace=w+1; rowdata[j]; j++) freespace -= rowdata[j] + 1;
 
507
        for (j=0, changed_h[i]=0; rowdata[j]; j++)
 
508
            if (rowdata[j] > freespace)
 
509
                changed_h[i] += rowdata[j] - freespace;
 
510
    }
 
511
    for (i=0,max_h=0; i<h; i++)
 
512
        if (changed_h[i] > max_h)
 
513
            max_h = changed_h[i];
 
514
    for (i=0; i<w; i++) {
 
515
        int freespace;
 
516
        if (state) {
 
517
            memcpy(rowdata, state->rowdata + state->rowsize*i, max*sizeof(int));
 
518
            rowdata[state->rowlen[i]] = 0;
 
519
        } else {
 
520
            rowdata[compute_rowdata(rowdata, grid+i, h, w)] = 0;
 
521
        }
 
522
        for (j=0, freespace=h+1; rowdata[j]; j++) freespace -= rowdata[j] + 1;
 
523
        for (j=0, changed_w[i]=0; rowdata[j]; j++)
 
524
            if (rowdata[j] > freespace)
 
525
                changed_w[i] += rowdata[j] - freespace;
 
526
    }
 
527
    for (i=0,max_w=0; i<w; i++)
 
528
        if (changed_w[i] > max_w)
 
529
            max_w = changed_w[i];
 
530
 
 
531
    /* Solve the puzzle.
 
532
     * Process rows/columns individually. Deductions involving more than one
 
533
     * row and/or column at a time are not supported.
 
534
     * Take care to only process rows/columns which have been changed since they
 
535
     * were previously processed.
 
536
     * Also, prioritize rows/columns which have had the most changes since their
 
537
     * previous processing, as they promise the greatest benefit.
 
538
     * Extremely rectangular grids (e.g. 10x20, 15x40, etc.) are not treated specially.
 
539
     */
 
540
    do {
 
541
        for (; max_h && max_h >= max_w; max_h--) {
 
542
            for (i=0; i<h; i++) {
 
543
                if (changed_h[i] >= max_h) {
 
544
                    if (state) {
 
545
                        memcpy(rowdata, state->rowdata + state->rowsize*(w+i), max*sizeof(int));
 
546
                        rowdata[state->rowlen[w+i]] = 0;
 
547
                    } else {
 
548
                        rowdata[compute_rowdata(rowdata, grid+i*w, w, 1)] = 0;
 
549
                    }
 
550
                    do_row(workspace, workspace+max, workspace+2*max,
 
551
                           workspace+3*max, workspace+4*max,
 
552
                           workspace+5*max, workspace+6*max,
 
553
                           matrix+i*w, w, 1, rowdata, changed_w
 
554
#ifdef STANDALONE_SOLVER
 
555
                           , "row", i+1, cluewid
 
556
#endif
 
557
                           );
 
558
                    changed_h[i] = 0;
 
559
                }
 
560
            }
 
561
            for (i=0,max_w=0; i<w; i++)
 
562
                if (changed_w[i] > max_w)
 
563
                    max_w = changed_w[i];
 
564
        }
 
565
        for (; max_w && max_w >= max_h; max_w--) {
 
566
            for (i=0; i<w; i++) {
 
567
                if (changed_w[i] >= max_w) {
 
568
                    if (state) {
 
569
                        memcpy(rowdata, state->rowdata + state->rowsize*i, max*sizeof(int));
 
570
                        rowdata[state->rowlen[i]] = 0;
 
571
                    } else {
 
572
                        rowdata[compute_rowdata(rowdata, grid+i, h, w)] = 0;
 
573
                    }
 
574
                    do_row(workspace, workspace+max, workspace+2*max,
 
575
                           workspace+3*max, workspace+4*max,
 
576
                           workspace+5*max, workspace+6*max,
 
577
                           matrix+i, h, w, rowdata, changed_h
 
578
#ifdef STANDALONE_SOLVER
 
579
                           , "col", i+1, cluewid
 
580
#endif
 
581
                           );
 
582
                    changed_w[i] = 0;
 
583
                }
 
584
            }
 
585
            for (i=0,max_h=0; i<h; i++)
 
586
                if (changed_h[i] > max_h)
 
587
                    max_h = changed_h[i];
 
588
        }
 
589
    } while (max_h>0 || max_w>0);
 
590
 
 
591
    ok = TRUE;
 
592
    for (i=0; i<h; i++) {
 
593
        for (j=0; j<w; j++) {
 
594
            if (matrix[i*w+j] == UNKNOWN)
 
595
                ok = FALSE;
 
596
        }
 
597
    }
 
598
 
 
599
    return ok;
 
600
}
 
601
 
422
602
static unsigned char *generate_soluble(random_state *rs, int w, int h)
423
603
{
424
 
    int i, j, done_any, ok, ntries, max;
 
604
    int i, j, ok, ntries, max;
425
605
    unsigned char *grid, *matrix, *workspace;
 
606
    unsigned int *changed_h, *changed_w;
426
607
    int *rowdata;
427
608
 
 
609
    max = max(w, h);
 
610
 
428
611
    grid = snewn(w*h, unsigned char);
 
612
    /* Allocate this here, to avoid having to reallocate it again for every geneerated grid */
429
613
    matrix = snewn(w*h, unsigned char);
430
 
    max = max(w, h);
431
 
    workspace = snewn(max*3, unsigned char);
 
614
    workspace = snewn(max*7, unsigned char);
 
615
    changed_h = snewn(max+1, unsigned int);
 
616
    changed_w = snewn(max+1, unsigned int);
432
617
    rowdata = snewn(max+1, int);
433
618
 
434
619
    ntries = 0;
466
651
        if (!ok)
467
652
            continue;
468
653
 
469
 
        memset(matrix, 0, w*h);
470
 
 
471
 
        do {
472
 
            done_any = 0;
473
 
            for (i=0; i<h; i++) {
474
 
                rowdata[compute_rowdata(rowdata, grid+i*w, w, 1)] = 0;
475
 
                done_any |= do_row(workspace, workspace+max, workspace+2*max,
476
 
                                   matrix+i*w, w, 1, rowdata
477
 
#ifdef STANDALONE_SOLVER
478
 
                                   , NULL, 0, 0 /* never do diagnostics here */
479
 
#endif
480
 
                                   );
481
 
            }
482
 
            for (i=0; i<w; i++) {
483
 
                rowdata[compute_rowdata(rowdata, grid+i, h, w)] = 0;
484
 
                done_any |= do_row(workspace, workspace+max, workspace+2*max,
485
 
                                   matrix+i, h, w, rowdata
486
 
#ifdef STANDALONE_SOLVER
487
 
                                   , NULL, 0, 0 /* never do diagnostics here */
488
 
#endif
489
 
                                   );
490
 
            }
491
 
        } while (done_any);
492
 
 
493
 
        ok = TRUE;
494
 
        for (i=0; i<h; i++) {
495
 
            for (j=0; j<w; j++) {
496
 
                if (matrix[i*w+j] == UNKNOWN)
497
 
                    ok = FALSE;
498
 
            }
499
 
        }
 
654
        ok = solve_puzzle(NULL, grid, w, h, matrix, workspace,
 
655
                          changed_h, changed_w, rowdata, 0);
500
656
    } while (!ok);
501
657
 
502
658
    sfree(matrix);
503
659
    sfree(workspace);
 
660
    sfree(changed_h);
 
661
    sfree(changed_w);
504
662
    sfree(rowdata);
505
663
    return grid;
506
664
}
507
665
 
508
 
static char *new_game_desc(game_params *params, random_state *rs,
 
666
static char *new_game_desc(const game_params *params, random_state *rs,
509
667
                           char **aux, int interactive)
510
668
{
511
669
    unsigned char *grid;
592
750
    return desc;
593
751
}
594
752
 
595
 
static char *validate_desc(game_params *params, char *desc)
 
753
static char *validate_desc(const game_params *params, const char *desc)
596
754
{
597
755
    int i, n, rowspace;
598
 
    char *p;
 
756
    const char *p;
599
757
 
600
758
    for (i = 0; i < params->w + params->h; i++) {
601
759
        if (i < params->w)
634
792
    return NULL;
635
793
}
636
794
 
637
 
static game_state *new_game(midend *me, game_params *params, char *desc)
 
795
static game_state *new_game(midend *me, const game_params *params,
 
796
                            const char *desc)
638
797
{
639
798
    int i;
640
 
    char *p;
 
799
    const char *p;
641
800
    game_state *state = snew(game_state);
642
801
 
643
802
    state->w = params->w;
669
828
    return state;
670
829
}
671
830
 
672
 
static game_state *dup_game(game_state *state)
 
831
static game_state *dup_game(const game_state *state)
673
832
{
674
833
    game_state *ret = snew(game_state);
675
834
 
701
860
    sfree(state);
702
861
}
703
862
 
704
 
static char *solve_game(game_state *state, game_state *currstate,
705
 
                        char *ai, char **error)
 
863
static char *solve_game(const game_state *state, const game_state *currstate,
 
864
                        const char *ai, char **error)
706
865
{
707
866
    unsigned char *matrix;
708
867
    int w = state->w, h = state->h;
709
868
    int i;
710
869
    char *ret;
711
 
    int done_any, max;
 
870
    int max, ok;
712
871
    unsigned char *workspace;
 
872
    unsigned int *changed_h, *changed_w;
713
873
    int *rowdata;
714
874
 
715
875
    /*
718
878
    if (ai)
719
879
        return dupstr(ai);
720
880
 
 
881
    max = max(w, h);
721
882
    matrix = snewn(w*h, unsigned char);
722
 
    max = max(w, h);
723
 
    workspace = snewn(max*3, unsigned char);
 
883
    workspace = snewn(max*7, unsigned char);
 
884
    changed_h = snewn(max+1, unsigned int);
 
885
    changed_w = snewn(max+1, unsigned int);
724
886
    rowdata = snewn(max+1, int);
725
887
 
726
 
    memset(matrix, 0, w*h);
727
 
 
728
 
    do {
729
 
        done_any = 0;
730
 
        for (i=0; i<h; i++) {
731
 
            memcpy(rowdata, state->rowdata + state->rowsize*(w+i),
732
 
                   max*sizeof(int));
733
 
            rowdata[state->rowlen[w+i]] = 0;
734
 
            done_any |= do_row(workspace, workspace+max, workspace+2*max,
735
 
                               matrix+i*w, w, 1, rowdata
736
 
#ifdef STANDALONE_SOLVER
737
 
                               , NULL, 0, 0 /* never do diagnostics here */
738
 
#endif
739
 
                               );
740
 
        }
741
 
        for (i=0; i<w; i++) {
742
 
            memcpy(rowdata, state->rowdata + state->rowsize*i, max*sizeof(int));
743
 
            rowdata[state->rowlen[i]] = 0;
744
 
            done_any |= do_row(workspace, workspace+max, workspace+2*max,
745
 
                               matrix+i, h, w, rowdata
746
 
#ifdef STANDALONE_SOLVER
747
 
                               , NULL, 0, 0 /* never do diagnostics here */
748
 
#endif
749
 
                               );
750
 
        }
751
 
    } while (done_any);
 
888
    ok = solve_puzzle(state, NULL, w, h, matrix, workspace,
 
889
                      changed_h, changed_w, rowdata, 0);
752
890
 
753
891
    sfree(workspace);
 
892
    sfree(changed_h);
 
893
    sfree(changed_w);
754
894
    sfree(rowdata);
755
895
 
756
 
    for (i = 0; i < w*h; i++) {
757
 
        if (matrix[i] != BLOCK && matrix[i] != DOT) {
758
 
            sfree(matrix);
759
 
            *error = "Solving algorithm cannot complete this puzzle";
760
 
            return NULL;
761
 
        }
 
896
    if (!ok) {
 
897
        sfree(matrix);
 
898
        *error = "Solving algorithm cannot complete this puzzle";
 
899
        return NULL;
762
900
    }
763
901
 
764
902
    ret = snewn(w*h+2, char);
774
912
    return ret;
775
913
}
776
914
 
777
 
static int game_can_format_as_text_now(game_params *params)
 
915
static int game_can_format_as_text_now(const game_params *params)
778
916
{
779
917
    return TRUE;
780
918
}
781
919
 
782
 
static char *game_text_format(game_state *state)
 
920
static char *game_text_format(const game_state *state)
783
921
{
784
922
    return NULL;
785
923
}
794
932
    int cur_x, cur_y, cur_visible;
795
933
};
796
934
 
797
 
static game_ui *new_ui(game_state *state)
 
935
static game_ui *new_ui(const game_state *state)
798
936
{
799
937
    game_ui *ret;
800
938
 
810
948
    sfree(ui);
811
949
}
812
950
 
813
 
static char *encode_ui(game_ui *ui)
 
951
static char *encode_ui(const game_ui *ui)
814
952
{
815
953
    return NULL;
816
954
}
817
955
 
818
 
static void decode_ui(game_ui *ui, char *encoding)
 
956
static void decode_ui(game_ui *ui, const char *encoding)
819
957
{
820
958
}
821
959
 
822
 
static void game_changed_state(game_ui *ui, game_state *oldstate,
823
 
                               game_state *newstate)
 
960
static void game_changed_state(game_ui *ui, const game_state *oldstate,
 
961
                               const game_state *newstate)
824
962
{
825
963
}
826
964
 
828
966
    int started;
829
967
    int w, h;
830
968
    int tilesize;
831
 
    unsigned char *visible;
 
969
    unsigned char *visible, *numcolours;
832
970
    int cur_x, cur_y;
833
971
};
834
972
 
835
 
static char *interpret_move(game_state *state, game_ui *ui, game_drawstate *ds,
836
 
                            int x, int y, int button)
 
973
static char *interpret_move(const game_state *state, game_ui *ui,
 
974
                            const game_drawstate *ds,
 
975
                            int x, int y, int button)
837
976
{
838
977
    button &= ~MOD_MASK;
839
978
 
966
1105
    return NULL;
967
1106
}
968
1107
 
969
 
static game_state *execute_move(game_state *from, char *move)
 
1108
static game_state *execute_move(const game_state *from, const char *move)
970
1109
{
971
1110
    game_state *ret;
972
1111
    int x1, x2, y1, y2, xx, yy;
1038
1177
}
1039
1178
 
1040
1179
/* ----------------------------------------------------------------------
 
1180
 * Error-checking during gameplay.
 
1181
 */
 
1182
 
 
1183
/*
 
1184
 * The difficulty in error-checking Pattern is to make the error check
 
1185
 * _weak_ enough. The most obvious way would be to check each row and
 
1186
 * column by calling (a modified form of) do_row() to recursively
 
1187
 * analyse the row contents against the clue set and see if the
 
1188
 * GRID_UNKNOWNs could be filled in in any way that would end up
 
1189
 * correct. However, this turns out to be such a strong error check as
 
1190
 * to constitute a spoiler in many situations: you make a typo while
 
1191
 * trying to fill in one row, and not only does the row light up to
 
1192
 * indicate an error, but several columns crossed by the move also
 
1193
 * light up and draw your attention to deductions you hadn't even
 
1194
 * noticed you could make.
 
1195
 *
 
1196
 * So instead I restrict error-checking to 'complete runs' within a
 
1197
 * row, by which I mean contiguous sequences of GRID_FULL bounded at
 
1198
 * both ends by either GRID_EMPTY or the ends of the row. We identify
 
1199
 * all the complete runs in a row, and verify that _those_ are
 
1200
 * consistent with the row's clue list. Sequences of complete runs
 
1201
 * separated by solid GRID_EMPTY are required to match contiguous
 
1202
 * sequences in the clue list, whereas if there's at least one
 
1203
 * GRID_UNKNOWN between any two complete runs then those two need not
 
1204
 * be contiguous in the clue list.
 
1205
 *
 
1206
 * To simplify the edge cases, I pretend that the clue list for the
 
1207
 * row is extended with a 0 at each end, and I also pretend that the
 
1208
 * grid data for the row is extended with a GRID_EMPTY and a
 
1209
 * zero-length run at each end. This permits the contiguity checker to
 
1210
 * handle the fiddly end effects (e.g. if the first contiguous
 
1211
 * sequence of complete runs in the grid matches _something_ in the
 
1212
 * clue list but not at the beginning, this is allowable iff there's a
 
1213
 * GRID_UNKNOWN before the first one) with minimal faff, since the end
 
1214
 * effects just drop out as special cases of the normal inter-run
 
1215
 * handling (in this code the above case is not 'at the end of the
 
1216
 * clue list' at all, but between the implicit initial zero run and
 
1217
 * the first nonzero one).
 
1218
 *
 
1219
 * We must also be a little careful about how we search for a
 
1220
 * contiguous sequence of runs. In the clue list (1 1 2 1 2 3),
 
1221
 * suppose we see a GRID_UNKNOWN and then a length-1 run. We search
 
1222
 * for 1 in the clue list and find it at the very beginning. But now
 
1223
 * suppose we find a length-2 run with no GRID_UNKNOWN before it. We
 
1224
 * can't naively look at the next clue from the 1 we found, because
 
1225
 * that'll be the second 1 and won't match. Instead, we must backtrack
 
1226
 * by observing that the 2 we've just found must be contiguous with
 
1227
 * the 1 we've already seen, so we search for the sequence (1 2) and
 
1228
 * find it starting at the second 1. Now if we see a 3, we must
 
1229
 * rethink again and search for (1 2 3).
 
1230
 */
 
1231
 
 
1232
struct errcheck_state {
 
1233
    /*
 
1234
     * rowdata and rowlen point at the clue data for this row in the
 
1235
     * game state.
 
1236
     */
 
1237
    int *rowdata;
 
1238
    int rowlen;
 
1239
    /*
 
1240
     * rowpos indicates the lowest position where it would be valid to
 
1241
     * see our next run length. It might be equal to rowlen,
 
1242
     * indicating that the next run would have to be the terminating 0.
 
1243
     */
 
1244
    int rowpos;
 
1245
    /*
 
1246
     * ncontig indicates how many runs we've seen in a contiguous
 
1247
     * block. This is taken into account when searching for the next
 
1248
     * run we find, unless ncontig is zeroed out first by encountering
 
1249
     * a GRID_UNKNOWN.
 
1250
     */
 
1251
    int ncontig;
 
1252
};
 
1253
 
 
1254
static int errcheck_found_run(struct errcheck_state *es, int r)
 
1255
{
 
1256
/* Macro to handle the pretence that rowdata has a 0 at each end */
 
1257
#define ROWDATA(k) ((k)<0 || (k)>=es->rowlen ? 0 : es->rowdata[(k)])
 
1258
 
 
1259
    /*
 
1260
     * See if we can find this new run length at a position where it
 
1261
     * also matches the last 'ncontig' runs we've seen.
 
1262
     */
 
1263
    int i, newpos;
 
1264
    for (newpos = es->rowpos; newpos <= es->rowlen; newpos++) {
 
1265
 
 
1266
        if (ROWDATA(newpos) != r)
 
1267
            goto notfound;
 
1268
 
 
1269
        for (i = 1; i <= es->ncontig; i++)
 
1270
            if (ROWDATA(newpos - i) != ROWDATA(es->rowpos - i))
 
1271
                goto notfound;
 
1272
 
 
1273
        es->rowpos = newpos+1;
 
1274
        es->ncontig++;
 
1275
        return TRUE;
 
1276
 
 
1277
      notfound:;
 
1278
    }
 
1279
 
 
1280
    return FALSE;
 
1281
 
 
1282
#undef ROWDATA
 
1283
}
 
1284
 
 
1285
static int check_errors(const game_state *state, int i)
 
1286
{
 
1287
    int start, step, end, j;
 
1288
    int val, runlen;
 
1289
    struct errcheck_state aes, *es = &aes;
 
1290
 
 
1291
    es->rowlen = state->rowlen[i];
 
1292
    es->rowdata = state->rowdata + state->rowsize * i;
 
1293
    /* Pretend that we've already encountered the initial zero run */
 
1294
    es->ncontig = 1;
 
1295
    es->rowpos = 0;
 
1296
 
 
1297
    if (i < state->w) {
 
1298
        start = i;
 
1299
        step = state->w;
 
1300
        end = start + step * state->h;
 
1301
    } else {
 
1302
        start = (i - state->w) * state->w;
 
1303
        step = 1;
 
1304
        end = start + step * state->w;
 
1305
    }
 
1306
 
 
1307
    runlen = -1;
 
1308
    for (j = start - step; j <= end; j += step) {
 
1309
        if (j < start || j == end)
 
1310
            val = GRID_EMPTY;
 
1311
        else
 
1312
            val = state->grid[j];
 
1313
 
 
1314
        if (val == GRID_UNKNOWN) {
 
1315
            runlen = -1;
 
1316
            es->ncontig = 0;
 
1317
        } else if (val == GRID_FULL) {
 
1318
            if (runlen >= 0)
 
1319
                runlen++;
 
1320
        } else if (val == GRID_EMPTY) {
 
1321
            if (runlen > 0) {
 
1322
                if (!errcheck_found_run(es, runlen))
 
1323
                    return TRUE;       /* error! */
 
1324
            }
 
1325
            runlen = 0;
 
1326
        }
 
1327
    }
 
1328
 
 
1329
    /* Signal end-of-row by sending errcheck_found_run the terminating
 
1330
     * zero run, which will be marked as contiguous with the previous
 
1331
     * run if and only if there hasn't been a GRID_UNKNOWN before. */
 
1332
    if (!errcheck_found_run(es, 0))
 
1333
        return TRUE;                   /* error at the last minute! */
 
1334
 
 
1335
    return FALSE;                      /* no error */
 
1336
}
 
1337
 
 
1338
/* ----------------------------------------------------------------------
1041
1339
 * Drawing routines.
1042
1340
 */
1043
1341
 
1044
 
static void game_compute_size(game_params *params, int tilesize,
1045
 
                              int *x, int *y)
 
1342
static void game_compute_size(const game_params *params, int tilesize,
 
1343
                              int *x, int *y)
1046
1344
{
1047
1345
    /* Ick: fake up `ds->tilesize' for macro expansion purposes */
1048
1346
    struct { int tilesize; } ads, *ds = &ads;
1053
1351
}
1054
1352
 
1055
1353
static void game_set_size(drawing *dr, game_drawstate *ds,
1056
 
                          game_params *params, int tilesize)
 
1354
                          const game_params *params, int tilesize)
1057
1355
{
1058
1356
    ds->tilesize = tilesize;
1059
1357
}
1075
1373
    ret[COL_CURSOR * 3 + 0] = 1.0F;
1076
1374
    ret[COL_CURSOR * 3 + 1] = 0.25F;
1077
1375
    ret[COL_CURSOR * 3 + 2] = 0.25F;
 
1376
    ret[COL_ERROR * 3 + 0] = 1.0F;
 
1377
    ret[COL_ERROR * 3 + 1] = 0.0F;
 
1378
    ret[COL_ERROR * 3 + 2] = 0.0F;
1078
1379
 
1079
1380
    *ncolours = NCOLOURS;
1080
1381
    return ret;
1081
1382
}
1082
1383
 
1083
 
static game_drawstate *game_new_drawstate(drawing *dr, game_state *state)
 
1384
static game_drawstate *game_new_drawstate(drawing *dr, const game_state *state)
1084
1385
{
1085
1386
    struct game_drawstate *ds = snew(struct game_drawstate);
1086
1387
 
1090
1391
    ds->visible = snewn(ds->w * ds->h, unsigned char);
1091
1392
    ds->tilesize = 0;                  /* not decided yet */
1092
1393
    memset(ds->visible, 255, ds->w * ds->h);
 
1394
    ds->numcolours = snewn(ds->w + ds->h, unsigned char);
 
1395
    memset(ds->numcolours, 255, ds->w + ds->h);
1093
1396
    ds->cur_x = ds->cur_y = 0;
1094
1397
 
1095
1398
    return ds;
1131
1434
                TILE_SIZE, TILE_SIZE);
1132
1435
}
1133
1436
 
1134
 
static void draw_numbers(drawing *dr, game_drawstate *ds, game_state *state,
1135
 
                         int colour)
 
1437
/*
 
1438
 * Draw the numbers for a single row or column.
 
1439
 */
 
1440
static void draw_numbers(drawing *dr, game_drawstate *ds,
 
1441
                         const game_state *state, int i, int erase, int colour)
1136
1442
{
1137
 
    int i, j;
 
1443
    int rowlen = state->rowlen[i];
 
1444
    int *rowdata = state->rowdata + state->rowsize * i;
 
1445
    int nfit;
 
1446
    int j;
 
1447
 
 
1448
    if (erase) {
 
1449
        if (i < state->w) {
 
1450
            draw_rect(dr, TOCOORD(state->w, i), 0,
 
1451
                      TILE_SIZE, BORDER + TLBORDER(state->h) * TILE_SIZE,
 
1452
                      COL_BACKGROUND);
 
1453
        } else {
 
1454
            draw_rect(dr, 0, TOCOORD(state->h, i - state->w),
 
1455
                      BORDER + TLBORDER(state->w) * TILE_SIZE, TILE_SIZE,
 
1456
                      COL_BACKGROUND);
 
1457
        }
 
1458
    }
1138
1459
 
1139
1460
    /*
1140
 
     * Draw the numbers.
 
1461
     * Normally I space the numbers out by the same distance as the
 
1462
     * tile size. However, if there are more numbers than available
 
1463
     * spaces, I have to squash them up a bit.
1141
1464
     */
1142
 
    for (i = 0; i < state->w + state->h; i++) {
1143
 
        int rowlen = state->rowlen[i];
1144
 
        int *rowdata = state->rowdata + state->rowsize * i;
1145
 
        int nfit;
1146
 
 
1147
 
        /*
1148
 
         * Normally I space the numbers out by the same
1149
 
         * distance as the tile size. However, if there are
1150
 
         * more numbers than available spaces, I have to squash
1151
 
         * them up a bit.
1152
 
         */
1153
 
        nfit = max(rowlen, TLBORDER(state->h))-1;
1154
 
        assert(nfit > 0);
1155
 
 
1156
 
        for (j = 0; j < rowlen; j++) {
1157
 
            int x, y;
1158
 
            char str[80];
1159
 
 
1160
 
            if (i < state->w) {
1161
 
                x = TOCOORD(state->w, i);
1162
 
                y = BORDER + TILE_SIZE * (TLBORDER(state->h)-1);
1163
 
                y -= ((rowlen-j-1)*TILE_SIZE) * (TLBORDER(state->h)-1) / nfit;
1164
 
            } else {
1165
 
                y = TOCOORD(state->h, i - state->w);
1166
 
                x = BORDER + TILE_SIZE * (TLBORDER(state->w)-1);
1167
 
                x -= ((rowlen-j-1)*TILE_SIZE) * (TLBORDER(state->h)-1) / nfit;
1168
 
            }
1169
 
 
1170
 
            sprintf(str, "%d", rowdata[j]);
1171
 
            draw_text(dr, x+TILE_SIZE/2, y+TILE_SIZE/2, FONT_VARIABLE,
1172
 
                      TILE_SIZE/2, ALIGN_HCENTRE | ALIGN_VCENTRE, colour, str);
1173
 
        }
 
1465
    if (i < state->w)
 
1466
        nfit = TLBORDER(state->h);
 
1467
    else
 
1468
        nfit = TLBORDER(state->w);
 
1469
    nfit = max(rowlen, nfit) - 1;
 
1470
    assert(nfit > 0);
 
1471
 
 
1472
    for (j = 0; j < rowlen; j++) {
 
1473
        int x, y;
 
1474
        char str[80];
 
1475
 
 
1476
        if (i < state->w) {
 
1477
            x = TOCOORD(state->w, i);
 
1478
            y = BORDER + TILE_SIZE * (TLBORDER(state->h)-1);
 
1479
            y -= ((rowlen-j-1)*TILE_SIZE) * (TLBORDER(state->h)-1) / nfit;
 
1480
        } else {
 
1481
            y = TOCOORD(state->h, i - state->w);
 
1482
            x = BORDER + TILE_SIZE * (TLBORDER(state->w)-1);
 
1483
            x -= ((rowlen-j-1)*TILE_SIZE) * (TLBORDER(state->w)-1) / nfit;
 
1484
        }
 
1485
 
 
1486
        sprintf(str, "%d", rowdata[j]);
 
1487
        draw_text(dr, x+TILE_SIZE/2, y+TILE_SIZE/2, FONT_VARIABLE,
 
1488
                  TILE_SIZE/2, ALIGN_HCENTRE | ALIGN_VCENTRE, colour, str);
 
1489
    }
 
1490
 
 
1491
    if (i < state->w) {
 
1492
        draw_update(dr, TOCOORD(state->w, i), 0,
 
1493
                    TILE_SIZE, BORDER + TLBORDER(state->h) * TILE_SIZE);
 
1494
    } else {
 
1495
        draw_update(dr, 0, TOCOORD(state->h, i - state->w),
 
1496
                    BORDER + TLBORDER(state->w) * TILE_SIZE, TILE_SIZE);
1174
1497
    }
1175
1498
}
1176
1499
 
1177
 
static void game_redraw(drawing *dr, game_drawstate *ds, game_state *oldstate,
1178
 
                        game_state *state, int dir, game_ui *ui,
 
1500
static void game_redraw(drawing *dr, game_drawstate *ds,
 
1501
                        const game_state *oldstate, const game_state *state,
 
1502
                        int dir, const game_ui *ui,
1179
1503
                        float animtime, float flashtime)
1180
1504
{
1181
1505
    int i, j;
1191
1515
         */
1192
1516
        draw_rect(dr, 0, 0, SIZE(ds->w), SIZE(ds->h), COL_BACKGROUND);
1193
1517
 
1194
 
        /*
1195
 
         * Draw the numbers.
1196
 
         */
1197
 
        draw_numbers(dr, ds, state, COL_TEXT);
1198
 
 
1199
1518
        /*
1200
1519
         * Draw the grid outline.
1201
1520
         */
1265
1584
        }
1266
1585
    }
1267
1586
    ds->cur_x = cx; ds->cur_y = cy;
 
1587
 
 
1588
    /*
 
1589
     * Redraw any numbers which have changed their colour due to error
 
1590
     * indication.
 
1591
     */
 
1592
    for (i = 0; i < state->w + state->h; i++) {
 
1593
        int colour = check_errors(state, i) ? COL_ERROR : COL_TEXT;
 
1594
        if (ds->numcolours[i] != colour) {
 
1595
            draw_numbers(dr, ds, state, i, TRUE, colour);
 
1596
            ds->numcolours[i] = colour;
 
1597
        }
 
1598
    }
1268
1599
}
1269
1600
 
1270
 
static float game_anim_length(game_state *oldstate,
1271
 
                              game_state *newstate, int dir, game_ui *ui)
 
1601
static float game_anim_length(const game_state *oldstate,
 
1602
                              const game_state *newstate, int dir, game_ui *ui)
1272
1603
{
1273
1604
    return 0.0F;
1274
1605
}
1275
1606
 
1276
 
static float game_flash_length(game_state *oldstate,
1277
 
                               game_state *newstate, int dir, game_ui *ui)
 
1607
static float game_flash_length(const game_state *oldstate,
 
1608
                               const game_state *newstate, int dir, game_ui *ui)
1278
1609
{
1279
1610
    if (!oldstate->completed && newstate->completed &&
1280
1611
        !oldstate->cheated && !newstate->cheated)
1282
1613
    return 0.0F;
1283
1614
}
1284
1615
 
1285
 
static int game_status(game_state *state)
 
1616
static int game_status(const game_state *state)
1286
1617
{
1287
1618
    return state->completed ? +1 : 0;
1288
1619
}
1289
1620
 
1290
 
static int game_timing_state(game_state *state, game_ui *ui)
 
1621
static int game_timing_state(const game_state *state, game_ui *ui)
1291
1622
{
1292
1623
    return TRUE;
1293
1624
}
1294
1625
 
1295
 
static void game_print_size(game_params *params, float *x, float *y)
 
1626
static void game_print_size(const game_params *params, float *x, float *y)
1296
1627
{
1297
1628
    int pw, ph;
1298
1629
 
1304
1635
    *y = ph / 100.0F;
1305
1636
}
1306
1637
 
1307
 
static void game_print(drawing *dr, game_state *state, int tilesize)
 
1638
static void game_print(drawing *dr, const game_state *state, int tilesize)
1308
1639
{
1309
1640
    int w = state->w, h = state->h;
1310
1641
    int ink = print_mono_colour(dr, 0);
1311
 
    int x, y;
 
1642
    int x, y, i;
1312
1643
 
1313
1644
    /* Ick: fake up `ds->tilesize' for macro expansion purposes */
1314
1645
    game_drawstate ads, *ds = &ads;
1338
1669
    /*
1339
1670
     * Clues.
1340
1671
     */
1341
 
    draw_numbers(dr, ds, state, ink);
 
1672
    for (i = 0; i < state->w + state->h; i++)
 
1673
        draw_numbers(dr, ds, state, i, FALSE, ink);
1342
1674
 
1343
1675
    /*
1344
1676
     * Solution.
1442
1774
    s = new_game(NULL, p, desc);
1443
1775
 
1444
1776
    {
1445
 
        int w = p->w, h = p->h, i, j, done_any, max, cluewid = 0;
 
1777
        int w = p->w, h = p->h, i, j, max, cluewid = 0;
1446
1778
        unsigned char *matrix, *workspace;
 
1779
        unsigned int *changed_h, *changed_w;
1447
1780
        int *rowdata;
1448
1781
 
1449
1782
        matrix = snewn(w*h, unsigned char);
1450
1783
        max = max(w, h);
1451
 
        workspace = snewn(max*3, unsigned char);
 
1784
        workspace = snewn(max*7, unsigned char);
 
1785
        changed_h = snewn(max+1, unsigned int);
 
1786
        changed_w = snewn(max+1, unsigned int);
1452
1787
        rowdata = snewn(max+1, int);
1453
1788
 
1454
 
        memset(matrix, 0, w*h);
1455
 
 
1456
1789
        if (verbose) {
1457
1790
            int thiswid;
1458
1791
            /*
1469
1802
            }
1470
1803
        }
1471
1804
 
1472
 
        do {
1473
 
            done_any = 0;
1474
 
            for (i=0; i<h; i++) {
1475
 
                memcpy(rowdata, s->rowdata + s->rowsize*(w+i),
1476
 
                       max*sizeof(int));
1477
 
                rowdata[s->rowlen[w+i]] = 0;
1478
 
                done_any |= do_row(workspace, workspace+max, workspace+2*max,
1479
 
                                   matrix+i*w, w, 1, rowdata
1480
 
#ifdef STANDALONE_SOLVER
1481
 
                                   , "row", i+1, cluewid
1482
 
#endif
1483
 
                                   );
1484
 
            }
1485
 
            for (i=0; i<w; i++) {
1486
 
                memcpy(rowdata, s->rowdata + s->rowsize*i, max*sizeof(int));
1487
 
                rowdata[s->rowlen[i]] = 0;
1488
 
                done_any |= do_row(workspace, workspace+max, workspace+2*max,
1489
 
                                   matrix+i, h, w, rowdata
1490
 
#ifdef STANDALONE_SOLVER
1491
 
                                   , "col", i+1, cluewid
1492
 
#endif
1493
 
                                   );
1494
 
            }
1495
 
        } while (done_any);
 
1805
        solve_puzzle(s, NULL, w, h, matrix, workspace,
 
1806
                     changed_h, changed_w, rowdata, cluewid);
1496
1807
 
1497
1808
        for (i = 0; i < h; i++) {
1498
1809
            for (j = 0; j < w; j++) {