{ }codelper
飛ばしながらループ三項演算子桁そろえP0126

複数月のカレンダー

カレンダーを何か月分か続けて出力するプログラムを作る。
一行目に月の数 k と、最初の月の 1 日の曜日 w が与えられる。
曜日は 0 が日曜、1 が月曜、2 が火曜、3 が水曜、4 が木曜、5 が金曜、6 が土曜である。
二行目に各月の日数 k 個が順に与えられる。
次の月の 1 日は、前の月の最終日の次の曜日である。
月ごとに一週間を一行に出力し、一行は日曜から土曜までの七マスである。
最初の行は 1 日を含む週、最後の行は最終日を含む週である。
マスは二文字幅で、日付は右寄せにする(一桁の日付は前に空白一つ)。
1 日より前のマスは空白二つで埋める。
マスとマスの間には空白を一つ置く。
行末の空白は採点しないので、最終日より後のマスは出力してもしなくてもよい。
月と月の間には空行を一つ出力する。

入力
1 ≤ k ≤ 12、0 ≤ w ≤ 6、日数は 28 以上 31 以下
出力
月ごとに 4~6 行、月の間に空行一つ
例 1 · stdin
2 3
30 31
stdout
          1  2  3  4
 5  6  7  8  9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30

                1  2
 3  4  5  6  7  8  9
10 11 12 13 14 15 16
17 18 19 20 21 22 23
24 25 26 27 28 29 30
31
main.py
入力(stdin)

実行すると、これらの行が順に input()・標準入力に渡されます(実行中に入力を求めません)。

$ 準備完了

コードを入力して解くにはパソコンで開いてください。モバイルでは問題と解答を見られます。

ほかの言語では?言語別の解答を見る · 8 言語の解答

週ごとの日曜の日付を 1 - w から 7 ずつ進めれば(0 以下は前の月のマス)、行数を別に数える必要はありません。
7 ずつ進むループ:Python range(1 - w, n + 1, 7)(終わりの n + 1 は含まれない)、C 系・JS・TS for (s = 1 - w; s <= n; s += 7)、Craykon 繰り返す (s = 1 - w; s <= n; s += 7)。
よくある落とし穴は三つ。
Python で終わりを n にすると、n 日が日曜になる最後の週が抜けます。
行数を (w + n) / 7 + 1 で数えると、土曜でちょうど終わる月に空行が一つ増えます。
次の月の曜日は (w + n) % 7 です(w + n - 1 は最終日の曜日)。
マスを埋めるのは三項演算子一行です:Python f"{d:2d}" if 1 <= d <= n else " "(条件が真ん中)、他は 条件 ? 値 : 値。
右寄せ:Python f"{d:2d}"、JS・TS String(d).padStart(2)(padEnd は左寄せなので誤り)、Java String.format("%2d", d)、C# d.ToString().PadLeft(2)、C printf("%2d")、C++ std::setw(2)、Craykon ("" + d).前埋め(2)。

Pythonmain.py · 12 行
k, w = map(int, input().split())lengths = list(map(int, input().split()))months = []for n in lengths:    lines = []    # 한 주의 일요일 날짜: 1 - w부터 7씩 건너뛴다(0 이하면 지난달 칸)    for start in range(1 - w, n + 1, 7):        cells = [f"{d:2d}" if 1 <= d <= n else "  " for d in range(start, start + 7)]        lines.append(" ".join(cells).rstrip())    months.append("\n".join(lines))    w = (w + n) % 7  # 다음 달 1일의 요일print("\n\n".join(months))
JavaScriptmain.js · 15 行
const [, first, ...lengths] = require("fs").readFileSync(0, "utf8").trim().split(/\s+/).map(Number);let w = first;const months = [];for (const n of lengths) {  const lines = [];  // 한 주의 일요일 날짜: 1 - w부터 7씩 건너뛴다(0 이하면 지난달 칸)  for (let start = 1 - w; start <= n; start += 7) {    const cells = [];    for (let d = start; d < start + 7; d++) cells.push(d >= 1 && d <= n ? String(d).padStart(2) : "  ");    lines.push(cells.join(" ").trimEnd());  }  months.push(lines.join("\n"));  w = (w + n) % 7; // 다음 달 1일의 요일}console.log(months.join("\n\n"));
TypeScriptmain.ts · 16 行
import { readFileSync } from "node:fs";const [, first, ...lengths]: number[] = readFileSync(0, "utf8").trim().split(/\s+/).map(Number);let w: number = first;const months: string[] = [];for (const n of lengths) {  const lines: string[] = [];  // 한 주의 일요일 날짜: 1 - w부터 7씩 건너뛴다(0 이하면 지난달 칸)  for (let start = 1 - w; start <= n; start += 7) {    const cells: string[] = [];    for (let d = start; d < start + 7; d++) cells.push(d >= 1 && d <= n ? String(d).padStart(2) : "  ");    lines.push(cells.join(" ").trimEnd());  }  months.push(lines.join("\n"));  w = (w + n) % 7; // 다음 달 1일의 요일}console.log(months.join("\n\n"));
JavaMain.java · 25 行
import java.util.Scanner; public class Main {    public static void main(String[] args) {        Scanner sc = new Scanner(System.in);        int k = sc.nextInt();        int w = sc.nextInt();        StringBuilder out = new StringBuilder();        for (int m = 0; m < k; m++) {            int n = sc.nextInt();            if (m > 0) out.append('\n');            // 한 주의 일요일 날짜: 1 - w부터 7씩 건너뛴다(0 이하면 지난달 칸)            for (int start = 1 - w; start <= n; start += 7) {                StringBuilder line = new StringBuilder();                for (int d = start; d < start + 7; d++) {                    if (d > start) line.append(' ');                    line.append(d >= 1 && d <= n ? String.format("%2d", d) : "  ");                }                out.append(line.toString().stripTrailing()).append('\n');            }            w = (w + n) % 7; // 다음 달 1일의 요일        }        System.out.print(out);    }}
C#Main.cs · 30 行
using System;using System.Collections.Generic;using System.Text; class Program{    static void Main()    {        string[] first = Console.ReadLine().Split(' ', StringSplitOptions.RemoveEmptyEntries);        int w = int.Parse(first[1]);        string[] lengths = Console.ReadLine().Split(' ', StringSplitOptions.RemoveEmptyEntries);        var months = new List<string>();        foreach (string s in lengths)        {            int n = int.Parse(s);            var lines = new List<string>();            // 한 주의 일요일 날짜: 1 - w부터 7씩 건너뛴다(0 이하면 지난달 칸)            for (int start = 1 - w; start <= n; start += 7)            {                var cells = new List<string>();                for (int d = start; d < start + 7; d++)                    cells.Add(d >= 1 && d <= n ? d.ToString().PadLeft(2) : "  ");                lines.Add(string.Join(" ", cells).TrimEnd());            }            months.Add(string.Join("\n", lines));            w = (w + n) % 7; // 다음 달 1일의 요일        }        Console.WriteLine(string.Join("\n\n", months));    }}
C++main.cpp · 23 行
#include <iomanip>#include <iostream>#include <string> int main() {    int k, w;    std::cin >> k >> w;    for (int m = 0; m < k; m++) {        int n;        std::cin >> n;        if (m > 0) std::cout << '\n';        // 한 주의 일요일 날짜: 1 - w부터 7씩 건너뛴다(0 이하면 지난달 칸)        for (int start = 1 - w; start <= n; start += 7) {            for (int d = start; d < start + 7 && d <= n; d++) {                if (d > start) std::cout << ' ';                if (d >= 1) std::cout << std::setw(2) << d;                else std::cout << "  ";            }            std::cout << '\n';        }        w = (w + n) % 7; // 다음 달 1일의 요일    }}
Cmain.c · 23 行
#include <stdio.h> int main(void) {    int k, w;    scanf("%d %d", &k, &w);    for (int m = 0; m < k; m++) {        int n;        scanf("%d", &n);        if (m > 0) putchar('\n');        // 한 주의 일요일 날짜: 1 - w부터 7씩 건너뛴다(0 이하면 지난달 칸)        for (int start = 1 - w; start <= n; start += 7) {            // 마지막 날 뒤 칸은 줄 끝 빈칸이라 찍지 않는다            for (int d = start; d < start + 7 && d <= n; d++) {                if (d > start) putchar(' ');                if (d >= 1) printf("%2d", d);                else printf("  ");            }            putchar('\n');        }        w = (w + n) % 7; // 다음 달 1일의 요일    }    return 0;}
Craykonmain.cray · 23 行
kw = コンソール.数読み();k = kw[0];w = kw[1];lengths = コンソール.数読み();繰り返す (m = 0; m < k; m++){    n = lengths[m];    もし (m > 0)    {        コンソール.書く("");    }    // 한 주의 일요일 날짜: 1 - w부터 7씩 건너뛴다(0 이하면 지난달 칸)    繰り返す (start = 1 - w; start <= n; start += 7)    {        cells = [];        繰り返す (d = start; d < start + 7; d++)        {            cells.追加(d >= 1 && d <= n ? ("" + d).前埋め(2) : "  ");        }        コンソール.書く(cells.つなぐ(" "));    }    w = (w + n) % 7; // 다음 달 1일의 요일}