【PHP/演習問題】関数と戻り値[6]

【PHP/演習問題】関数と戻り値[6]

問題

年間カレンダーを出力するプログラムを作成してください。
なお、下記条件を満たすものとします。

  • 年はコマンドライン引数で与える
    ※ 年は1873以上で与えられるものとします(暦の関係上)
    ※ 1873年1月1日は水曜日(We)です
  • 閏年判定のアルゴリズムはグレゴリオ暦に従う
  • 曜日は英語で出力する
    日 → Su
    月 → Mo
    火 → Tu
    水 → We
    木 → Th
    金 → Fr
    土 → Sa
  • カレンダーを出力するcalendar関数を作成する
    引数:年
    戻り値:なし
$ php practice.php 1873
====================
======= 1873 =======
====================

-------- 01 --------
Su Mo Tu We Th Fr Sa 
         01 02 03 04 
05 06 07 08 09 10 11 
12 13 14 15 16 17 18 
19 20 21 22 23 24 25 
26 27 28 29 30 31 

-------- 02 --------
Su Mo Tu We Th Fr Sa 
                  01 
02 03 04 05 06 07 08 
09 10 11 12 13 14 15 
16 17 18 19 20 21 22 
23 24 25 26 27 28 

-------- 03 --------
Su Mo Tu We Th Fr Sa 
                  01 
02 03 04 05 06 07 08 
09 10 11 12 13 14 15 
16 17 18 19 20 21 22 
23 24 25 26 27 28 29 
30 31 

-------- 04 --------
Su Mo Tu We Th Fr Sa 
      01 02 03 04 05 
06 07 08 09 10 11 12 
13 14 15 16 17 18 19 
20 21 22 23 24 25 26 
27 28 29 30 

-------- 05 --------
Su Mo Tu We Th Fr Sa 
            01 02 03 
04 05 06 07 08 09 10 
11 12 13 14 15 16 17 
18 19 20 21 22 23 24 
25 26 27 28 29 30 31 

-------- 06 --------
Su Mo Tu We Th Fr Sa 
01 02 03 04 05 06 07 
08 09 10 11 12 13 14 
15 16 17 18 19 20 21 
22 23 24 25 26 27 28 
29 30 

-------- 07 --------
Su Mo Tu We Th Fr Sa 
      01 02 03 04 05 
06 07 08 09 10 11 12 
13 14 15 16 17 18 19 
20 21 22 23 24 25 26 
27 28 29 30 31 

-------- 08 --------
Su Mo Tu We Th Fr Sa 
               01 02 
03 04 05 06 07 08 09 
10 11 12 13 14 15 16 
17 18 19 20 21 22 23 
24 25 26 27 28 29 30 
31 

-------- 09 --------
Su Mo Tu We Th Fr Sa 
   01 02 03 04 05 06 
07 08 09 10 11 12 13 
14 15 16 17 18 19 20 
21 22 23 24 25 26 27 
28 29 30 

-------- 10 --------
Su Mo Tu We Th Fr Sa 
         01 02 03 04 
05 06 07 08 09 10 11 
12 13 14 15 16 17 18 
19 20 21 22 23 24 25 
26 27 28 29 30 31 

-------- 11 --------
Su Mo Tu We Th Fr Sa 
                  01 
02 03 04 05 06 07 08 
09 10 11 12 13 14 15 
16 17 18 19 20 21 22 
23 24 25 26 27 28 29 
30 

-------- 12 --------
Su Mo Tu We Th Fr Sa 
   01 02 03 04 05 06 
07 08 09 10 11 12 13 
14 15 16 17 18 19 20 
21 22 23 24 25 26 27 
28 29 30 31
$ php practice.php 2000
====================
======= 2000 =======
====================

-------- 01 --------
Su Mo Tu We Th Fr Sa 
                  01 
02 03 04 05 06 07 08 
09 10 11 12 13 14 15 
16 17 18 19 20 21 22 
23 24 25 26 27 28 29 
30 31 

-------- 02 --------
Su Mo Tu We Th Fr Sa 
      01 02 03 04 05 
06 07 08 09 10 11 12 
13 14 15 16 17 18 19 
20 21 22 23 24 25 26 
27 28 29 

-------- 03 --------
Su Mo Tu We Th Fr Sa 
         01 02 03 04 
05 06 07 08 09 10 11 
12 13 14 15 16 17 18 
19 20 21 22 23 24 25 
26 27 28 29 30 31 

-------- 04 --------
Su Mo Tu We Th Fr Sa 
                  01 
02 03 04 05 06 07 08 
09 10 11 12 13 14 15 
16 17 18 19 20 21 22 
23 24 25 26 27 28 29 
30 

-------- 05 --------
Su Mo Tu We Th Fr Sa 
   01 02 03 04 05 06 
07 08 09 10 11 12 13 
14 15 16 17 18 19 20 
21 22 23 24 25 26 27 
28 29 30 31 

-------- 06 --------
Su Mo Tu We Th Fr Sa 
            01 02 03 
04 05 06 07 08 09 10 
11 12 13 14 15 16 17 
18 19 20 21 22 23 24 
25 26 27 28 29 30 

-------- 07 --------
Su Mo Tu We Th Fr Sa 
                  01 
02 03 04 05 06 07 08 
09 10 11 12 13 14 15 
16 17 18 19 20 21 22 
23 24 25 26 27 28 29 
30 31 

-------- 08 --------
Su Mo Tu We Th Fr Sa 
      01 02 03 04 05 
06 07 08 09 10 11 12 
13 14 15 16 17 18 19 
20 21 22 23 24 25 26 
27 28 29 30 31 

-------- 09 --------
Su Mo Tu We Th Fr Sa 
               01 02 
03 04 05 06 07 08 09 
10 11 12 13 14 15 16 
17 18 19 20 21 22 23 
24 25 26 27 28 29 30 

-------- 10 --------
Su Mo Tu We Th Fr Sa 
01 02 03 04 05 06 07 
08 09 10 11 12 13 14 
15 16 17 18 19 20 21 
22 23 24 25 26 27 28 
29 30 31 

-------- 11 --------
Su Mo Tu We Th Fr Sa 
         01 02 03 04 
05 06 07 08 09 10 11 
12 13 14 15 16 17 18 
19 20 21 22 23 24 25 
26 27 28 29 30 

-------- 12 --------
Su Mo Tu We Th Fr Sa 
               01 02 
03 04 05 06 07 08 09 
10 11 12 13 14 15 16 
17 18 19 20 21 22 23 
24 25 26 27 28 29 30 
31 
$ php practice.php 2022
====================
======= 2022 =======
====================

-------- 01 --------
Su Mo Tu We Th Fr Sa 
                  01 
02 03 04 05 06 07 08 
09 10 11 12 13 14 15 
16 17 18 19 20 21 22 
23 24 25 26 27 28 29 
30 31 

-------- 02 --------
Su Mo Tu We Th Fr Sa 
      01 02 03 04 05 
06 07 08 09 10 11 12 
13 14 15 16 17 18 19 
20 21 22 23 24 25 26 
27 28 

-------- 03 --------
Su Mo Tu We Th Fr Sa 
      01 02 03 04 05 
06 07 08 09 10 11 12 
13 14 15 16 17 18 19 
20 21 22 23 24 25 26 
27 28 29 30 31 

-------- 04 --------
Su Mo Tu We Th Fr Sa 
               01 02 
03 04 05 06 07 08 09 
10 11 12 13 14 15 16 
17 18 19 20 21 22 23 
24 25 26 27 28 29 30 

-------- 05 --------
Su Mo Tu We Th Fr Sa 
01 02 03 04 05 06 07 
08 09 10 11 12 13 14 
15 16 17 18 19 20 21 
22 23 24 25 26 27 28 
29 30 31 

-------- 06 --------
Su Mo Tu We Th Fr Sa 
         01 02 03 04 
05 06 07 08 09 10 11 
12 13 14 15 16 17 18 
19 20 21 22 23 24 25 
26 27 28 29 30 

-------- 07 --------
Su Mo Tu We Th Fr Sa 
               01 02 
03 04 05 06 07 08 09 
10 11 12 13 14 15 16 
17 18 19 20 21 22 23 
24 25 26 27 28 29 30 
31 

-------- 08 --------
Su Mo Tu We Th Fr Sa 
   01 02 03 04 05 06 
07 08 09 10 11 12 13 
14 15 16 17 18 19 20 
21 22 23 24 25 26 27 
28 29 30 31 

-------- 09 --------
Su Mo Tu We Th Fr Sa 
            01 02 03 
04 05 06 07 08 09 10 
11 12 13 14 15 16 17 
18 19 20 21 22 23 24 
25 26 27 28 29 30 

-------- 10 --------
Su Mo Tu We Th Fr Sa 
                  01 
02 03 04 05 06 07 08 
09 10 11 12 13 14 15 
16 17 18 19 20 21 22 
23 24 25 26 27 28 29 
30 31 

-------- 11 --------
Su Mo Tu We Th Fr Sa 
      01 02 03 04 05 
06 07 08 09 10 11 12 
13 14 15 16 17 18 19 
20 21 22 23 24 25 26 
27 28 29 30 

-------- 12 --------
Su Mo Tu We Th Fr Sa 
            01 02 03 
04 05 06 07 08 09 10 
11 12 13 14 15 16 17 
18 19 20 21 22 23 24 
25 26 27 28 29 30 31 

解答例

<?php

function is_leap_year( $year ) {
    
    if( $year % 4 == 0 && ( $year % 100 != 0 || $year % 400 == 0 ) ) {
        return true;
    }
    
    return false;
}

function days_in_year( $year ) {
    
    $days = 365;
    if( is_leap_year($year) ) $days = 366;
    
    return $days;
}

function last_day_of_month( $year, $month ) {
    
    $last_day_map = [
        1 => 31, 2 => 28, 3 => 31, 4 => 30, 5 => 31, 6 => 30,
        7 => 31, 8 => 31, 9 => 30, 10 => 31, 11 => 30, 12 => 31,
    ];
    
    $last_day = $last_day_map[$month];
    if( is_leap_year($year) && $month == 2 ) $last_day = 29;
    
    return $last_day;
}

function day_of_week( $year, $month, $day ) {
    
    $days_elapsed = 0;
    for( $i = 1873; $i < $year; $i++ ) {
        $days_elapsed += days_in_year($i);
    }
    for( $i = 1; $i < $month; $i++ ) {
        $days_elapsed += last_day_of_month($year, $i);
    }
    $days_elapsed += $day;
    
    return ( $days_elapsed + 2 ) % 7;
}

function calendar( $year ) {

    $dws = [
        'Su','Mo','Tu','We','Th','Fr','Sa',
    ];

    echo "====================\n";
    echo '======= '.$year." =======\n";
    echo "====================\n\n";

    for( $month = 1; $month <= 12; $month++ ) {
        echo '-------- ';
        if( $month < 10 ) echo '0';
        echo $month." --------\n";

        $count = 0;
        $start_day_of_week = day_of_week($year, $month, 1);
        $last_day = last_day_of_month($year, $month);

        for( $dw = 0; $dw < 7 ; $dw++ ) {
            echo $dws[$dw].' ';
        }
        echo "\n";

        for( $i = 0; $i < $start_day_of_week; $i++ ) {
            echo '   ';
            $count++;
        }

        for( $day = 1; $day <= $last_day; $day++ ) {
            if( $day < 10 ) echo '0';
            echo $day.' ';

            $count++;

            if( $count % 7 == 0 ) echo "\n";
        }

        if( $count % 7 != 0 ) echo "\n";
        echo "\n";
    }

}

$year = $argv[1];
calendar($year);

?>