Calendar - for "REAL" programmers: Difference between revisions
Content added Content deleted
No edit summary |
(Added Kotlin) |
||
Line 1,483: | Line 1,483: | ||
Note that this version of F will work fine with a left argument of 20 (why anyone felt that this was important to mention is perhaps best thought of as an issue lost in history). |
Note that this version of F will work fine with a left argument of 20 (why anyone felt that this was important to mention is perhaps best thought of as an issue lost in history). |
||
=={{header|Kotlin}}== |
|||
Kotlin is case-sensitive: all its keywords and packages are lower case, all its library classes are mixed case and its library functions are either lower case or mixed case. Consequently, it is impossible to run an upper case version of the Calendar task program as it stands. So what I've done instead (and similar to what several other languages in the same boat have done) is: |
|||
1. Saved the Calendar program, after conversion to upper case and a small marked alteration to give upper case output, to a text file called calendar_UC.txt. |
|||
2. Written another program called real_calendar.kt which takes calendar_UC.txt as input, outputs a runnable program called calendar_NC.kt to disk, compiles it to a .jar file, runs it, captures the output and prints it to the terminal (Ubuntu 14.04 being used). This program only makes the minimum changes to calendar_UC.txt to enable it to run. Everything else is left as upper case even though almost certainly no Kotlin programmer ("REAL" or not) would write such a program in practice. |
|||
This is calendar_UC.txt: |
|||
<lang scala>IMPORT JAVA.TEXT.* |
|||
IMPORT JAVA.UTIL.* |
|||
IMPORT JAVA.IO.PRINTSTREAM |
|||
INTERNAL FUN PRINTSTREAM.PRINTCALENDAR(YEAR: INT, NCOLS: BYTE, LOCALE: LOCALE?) { |
|||
IF (NCOLS < 1 || NCOLS > 12) |
|||
THROW ILLEGALARGUMENTEXCEPTION("ILLEGAL COLUMN WIDTH.") |
|||
VAL W = NCOLS * 24 |
|||
VAL NROWS = MATH.CEIL(12.0 / NCOLS).TOINT() |
|||
VAL DATE = GREGORIANCALENDAR(YEAR, 0, 1) |
|||
VAR OFFS = DATE.GET(CALENDAR.DAY_OF_WEEK) - 1 |
|||
VAL DAYS = DATEFORMATSYMBOLS(LOCALE).SHORTWEEKDAYS.SLICE(1..7).MAP { IT.SLICE(0..1) }.JOINTOSTRING(" ", " ") |
|||
VAL MONS = ARRAY(12) { ARRAY(8) { "" } } |
|||
DATEFORMATSYMBOLS(LOCALE).MONTHS.SLICE(0..11).FOREACHINDEXED { M, NAME -> |
|||
VAL LEN = 11 + NAME.LENGTH / 2 |
|||
VAL FORMAT = MESSAGEFORMAT.FORMAT("%{0}S%{1}S", LEN, 21 - LEN) |
|||
MONS[M][0] = STRING.FORMAT(FORMAT, NAME, "") |
|||
MONS[M][1] = DAYS |
|||
VAL DIM = DATE.GETACTUALMAXIMUM(CALENDAR.DAY_OF_MONTH) |
|||
FOR (D IN 1..42) { |
|||
VAL ISDAY = D > OFFS && D <= OFFS + DIM |
|||
VAL ENTRY = IF (ISDAY) STRING.FORMAT(" %2S", D - OFFS) ELSE " " |
|||
IF (D % 7 == 1) |
|||
MONS[M][2 + (D - 1) / 7] = ENTRY |
|||
ELSE |
|||
MONS[M][2 + (D - 1) / 7] += ENTRY |
|||
} |
|||
OFFS = (OFFS + DIM) % 7 |
|||
DATE.ADD(CALENDAR.MONTH, 1) |
|||
} |
|||
PRINTF("%" + (W / 2 + 10) + "S%N", "[SNOOPY PICTURE]") |
|||
PRINTF("%" + (W / 2 + 4) + "S%N%N", YEAR) |
|||
FOR (R IN 0..NROWS - 1) { |
|||
FOR (I IN 0..7) { |
|||
VAR C = R * NCOLS |
|||
WHILE (C < (R + 1) * NCOLS && C < 12) { |
|||
PRINTF(" %S", MONS[C][I].TOUPPERCASE()) // ORIGINAL CHANGED TO PRINT IN UPPER CASE |
|||
C++ |
|||
} |
|||
PRINTLN() |
|||
} |
|||
PRINTLN() |
|||
} |
|||
} |
|||
FUN MAIN(ARGS: ARRAY<STRING>) { |
|||
SYSTEM.OUT.PRINTCALENDAR(1969, 3, LOCALE.US) |
|||
}</lang> |
|||
and this is real_calendar.kt: |
|||
<lang scala>// version 1.1.3 |
|||
import java.io.File |
|||
import java.io.BufferedReader |
|||
import java.io.InputStreamReader |
|||
fun main(args: Array<String>) { |
|||
val keywords = listOf( |
|||
"import", "internal", "fun", "if", "throw", "val", "var", "for", "in", "while" |
|||
) |
|||
val singleCase = listOf( |
|||
"java.text", |
|||
"java.util", |
|||
"java.io", |
|||
"else", // really a keyword but doesn't have a following space here |
|||
"ceil", |
|||
"it", // really a keyword but doesn't have a following space here |
|||
"get(", // also included in GETACTUALMAXIMUM |
|||
"slice", |
|||
"map", |
|||
"months", |
|||
"length", |
|||
".format", // also variable called FORMAT |
|||
"add", |
|||
"printf", |
|||
"println", |
|||
"out", |
|||
"main", |
|||
"args", |
|||
"s%{1}s", |
|||
"%2s", |
|||
"s%n%n", |
|||
"s%n", |
|||
"%s" |
|||
) |
|||
val mixedCase = listOf( |
|||
"PRINTSTREAM" to "PrintStream", |
|||
"INT," to "Int,", // also included in PRINTCALENDAR |
|||
"BYTE" to "Byte", |
|||
"LOCALE?" to "Locale?", // also variable called LOCALE |
|||
"LOCALE." to "Locale.", |
|||
"ILLEGALARGUMENTEXCEPTION" to "IllegalArgumentException", |
|||
"MATH" to "Math", |
|||
"GREGORIANCALENDAR" to "GregorianCalendar", |
|||
"DATEFORMATSYMBOLS" to "DateFormatSymbols", |
|||
"ARRAY" to "Array", |
|||
"MESSAGEFORMAT" to "MessageFormat", |
|||
"JOINTOSTRING" to "joinToString", |
|||
"STRING" to "String", |
|||
"CALENDAR." to "Calendar.", // also included in PRINTCALENDAR |
|||
"SYSTEM" to "System", |
|||
"TOINT" to "toInt", |
|||
"SHORTWEEKDAYS" to "shortWeekdays", |
|||
"FOREACHINDEXED" to "forEachIndexed", |
|||
"GETACTUALMAXIMUM" to "getActualMaximum", |
|||
"TOUPPERCASE" to "toUpperCase" |
|||
) |
|||
var text = File("calendar_UC.txt").readText() |
|||
for (k in keywords) text = text.replace("${k.toUpperCase()} ", "$k ") // add a following space to be on safe side |
|||
for (s in singleCase) text = text.replace(s.toUpperCase(), s) |
|||
for (m in mixedCase) text = text.replace(m.first, m.second) |
|||
File("calendar_NC.kt").writeText(text) |
|||
val commands = listOf("kotlinc", "calendar_NC.kt", "-include-runtime", "-d", "calendar_X.jar") |
|||
val pb = ProcessBuilder(commands) |
|||
pb.redirectErrorStream(true) |
|||
val process = pb.start() |
|||
process.waitFor() |
|||
val commands2 = listOf("java", "-jar", "calendar_NC.jar") |
|||
val pb2 = ProcessBuilder(commands2) |
|||
pb2.redirectErrorStream(true) |
|||
val process2 = pb2.start() |
|||
val out = StringBuilder() |
|||
val br = BufferedReader(InputStreamReader(process2.inputStream)) |
|||
while (true) { |
|||
val line = br.readLine() |
|||
if (line == null) break |
|||
out.append(line).append('\n') |
|||
} |
|||
br.close() |
|||
println(out.toString()) |
|||
}</lang> |
|||
which generates (on disk) calendar_NC.kt: |
|||
<lang scala>import java.text.* |
|||
import java.util.* |
|||
import java.io.PrintStream |
|||
internal fun PrintStream.PRINTCALENDAR(YEAR: Int, NCOLS: Byte, LOCALE: Locale?) { |
|||
if (NCOLS < 1 || NCOLS > 12) |
|||
throw IllegalArgumentException("ILLEGAL COLUMN WIDTH.") |
|||
val W = NCOLS * 24 |
|||
val NROWS = Math.ceil(12.0 / NCOLS).toInt() |
|||
val DATE = GregorianCalendar(YEAR, 0, 1) |
|||
var OFFS = DATE.get(Calendar.DAY_OF_WEEK) - 1 |
|||
val DAYS = DateFormatSymbols(LOCALE).shortWeekdays.slice(1..7).map { it.slice(0..1) }.joinToString(" ", " ") |
|||
val MONS = Array(12) { Array(8) { "" } } |
|||
DateFormatSymbols(LOCALE).months.slice(0..11).forEachIndexed { M, NAME -> |
|||
val LEN = 11 + NAME.length / 2 |
|||
val FORMAT = MessageFormat.format("%{0}s%{1}s", LEN, 21 - LEN) |
|||
MONS[M][0] = String.format(FORMAT, NAME, "") |
|||
MONS[M][1] = DAYS |
|||
val DIM = DATE.getActualMaximum(Calendar.DAY_OF_MONTH) |
|||
for (D in 1..42) { |
|||
val ISDAY = D > OFFS && D <= OFFS + DIM |
|||
val ENTRY = if (ISDAY) String.format(" %2s", D - OFFS) else " " |
|||
if (D % 7 == 1) |
|||
MONS[M][2 + (D - 1) / 7] = ENTRY |
|||
else |
|||
MONS[M][2 + (D - 1) / 7] += ENTRY |
|||
} |
|||
OFFS = (OFFS + DIM) % 7 |
|||
DATE.add(Calendar.MONTH, 1) |
|||
} |
|||
printf("%" + (W / 2 + 10) + "s%n", "[SNOOPY PICTURE]") |
|||
printf("%" + (W / 2 + 4) + "s%n%n", YEAR) |
|||
for (R in 0..NROWS - 1) { |
|||
for (I in 0..7) { |
|||
var C = R * NCOLS |
|||
while (C < (R + 1) * NCOLS && C < 12) { |
|||
printf(" %s", MONS[C][I].toUpperCase()) // ORIGINAL CHANGED TO PRINT in UPPER CASE |
|||
C++ |
|||
} |
|||
println() |
|||
} |
|||
println() |
|||
} |
|||
} |
|||
fun main(args: Array<String>) { |
|||
System.out.PRINTCALENDAR(1969, 3, Locale.US) |
|||
}</lang> |
|||
which when compiled and run produces output of: |
|||
<pre> |
|||
[SNOOPY PICTURE] |
|||
1969 |
|||
JANUARY FEBRUARY MARCH |
|||
SU MO TU WE TH FR SA SU MO TU WE TH FR SA SU MO TU WE TH FR SA |
|||
1 2 3 4 1 1 |
|||
5 6 7 8 9 10 11 2 3 4 5 6 7 8 2 3 4 5 6 7 8 |
|||
12 13 14 15 16 17 18 9 10 11 12 13 14 15 9 10 11 12 13 14 15 |
|||
19 20 21 22 23 24 25 16 17 18 19 20 21 22 16 17 18 19 20 21 22 |
|||
26 27 28 29 30 31 23 24 25 26 27 28 23 24 25 26 27 28 29 |
|||
30 31 |
|||
APRIL MAY JUNE |
|||
SU MO TU WE TH FR SA SU MO TU WE TH FR SA SU MO TU WE TH FR SA |
|||
1 2 3 4 5 1 2 3 1 2 3 4 5 6 7 |
|||
6 7 8 9 10 11 12 4 5 6 7 8 9 10 8 9 10 11 12 13 14 |
|||
13 14 15 16 17 18 19 11 12 13 14 15 16 17 15 16 17 18 19 20 21 |
|||
20 21 22 23 24 25 26 18 19 20 21 22 23 24 22 23 24 25 26 27 28 |
|||
27 28 29 30 25 26 27 28 29 30 31 29 30 |
|||
JULY AUGUST SEPTEMBER |
|||
SU MO TU WE TH FR SA SU MO TU WE TH FR SA SU MO TU WE TH FR SA |
|||
1 2 3 4 5 1 2 1 2 3 4 5 6 |
|||
6 7 8 9 10 11 12 3 4 5 6 7 8 9 7 8 9 10 11 12 13 |
|||
13 14 15 16 17 18 19 10 11 12 13 14 15 16 14 15 16 17 18 19 20 |
|||
20 21 22 23 24 25 26 17 18 19 20 21 22 23 21 22 23 24 25 26 27 |
|||
27 28 29 30 31 24 25 26 27 28 29 30 28 29 30 |
|||
31 |
|||
OCTOBER NOVEMBER DECEMBER |
|||
SU MO TU WE TH FR SA SU MO TU WE TH FR SA SU MO TU WE TH FR SA |
|||
1 2 3 4 1 1 2 3 4 5 6 |
|||
5 6 7 8 9 10 11 2 3 4 5 6 7 8 7 8 9 10 11 12 13 |
|||
12 13 14 15 16 17 18 9 10 11 12 13 14 15 14 15 16 17 18 19 20 |
|||
19 20 21 22 23 24 25 16 17 18 19 20 21 22 21 22 23 24 25 26 27 |
|||
26 27 28 29 30 31 23 24 25 26 27 28 29 28 29 30 31 |
|||
30 |
|||
</pre> |
|||
=={{header|Lua}}== |
=={{header|Lua}}== |