How next_c.tc works

On Friday Jan 13, 2017 I became intrigued by the question "When's the next Friday the 13th?" After about four iterations I finally arrived at a solution (which worked for any day, not just Friday the 13th).

A friend solved the problem in perl (http://primepuzzle.com/tc/nextperl.sh.txt).

Mine is in tiny-C (perl has date smarts that tiny-C lacks). The source code is at http://primepuzzle.com/tc/next_c.tc.

The basic idea is to hop from month to month, driven by the length of each month. In a simple case, to go from Sun March 12 2017 to Wed April 12 2017 we hop 31 days (the number of days in March). The day of week advances by 3 (because 31%7=3). We keep hopping till the sum of the numbers equals 0 (modulo 7).

31  30  31  30  31  31  30  31
Mar Apr May Jun Jul Aug Sep Oct Nov
 3 + 2 + 3 + 2 + 3 + 3 + 2 + 3      = 21 = 0 (modulo 7)
Sun Wed Fri Mon Wed Sat Tue Thu Sun

If you start on a day number that doesn't occur in every month (e.g. 30) hops may cross over month boundaries so we can't stop our hopping because we'll be sitting on a day number that's not our required day number. Also, if we start in a late month (e.g. Nov or Dec) it's likely we'll cross a year boundary and we may be running into a leap year (or we may have been in a leap year and will be entering a non-leap year). For these reasons, after a while it occurred to me that I should "compile" a 3-year list of month lengths, and make sure the 29th of Feb (if any) was where it belonged. For example:

              2018                                   2019                                    2020
31 28 31 30 31 30 31 31 30 31 30 31    31 28 31 30 31 30 31 31 30 31 30 31    31 29 31 30 31 30 31 31 30 31 30 31
Key variables in the logic were the four input variables (dow, month, day, year), two arrays that hold month lengths, index (a month "pointer"), and work_day (a day of week recorder). How to initialize them and how to update them was finally worked out. The main loop fell into place.
 index=month+1;work_day=dow;verbose=1
 if verbose printf "%c%d %d",10,month,work_day
 while 1 [
  work_day=(work_day+da(index-1))%7
  if verbose printf "%c%d %d",10,index,work_day
  if work_day==dow // needs to be right day of week
   if (da(index)>=day) break // needs to be a legal month
  index=index+1
  ]
 printf "%c%s %d%c",10,month_n(index%12),(year+index/12),10

Here's a sample run:

D:\Tom Gibson\tiny-c-master>tc SamplePrograms\next_c_try.tc
***  TINY-C VERSION 1.0,  COPYRIGHT 1977, T A GIBSON  ***
        This C version copyright 2017, T A Gibson

next_c.tc - 6/6/19 - lrb

dow (0=Sunday, 1=Monday, etc.) : 4
month (0=January, 1=February, etc.) : 5
day (1..31) : 6
year (e.g. 2019) : 2019

Thu Jun 6
5 4
6 6
7 2
8 5
9 0
10 3
11 5
12 1
13 4
Feb 2020

done

D:\Tom Gibson\tiny-c-master>