Home Punched Cards
Post
Cancel

Punched Cards

This page is still in WIP. A lot of information is missing or not reviewed.


Try this problem by yourself first! Check the Code Jam Page.

Overview

We want to draw a Punched Card with ASCII art. We first receive an integer $T$. This will be the total number of test cases. Then each line will represent two integers: $R$ the number of rows of the Punched Card and $C$ the number of columns. Let’s give an example.

Sample InputSample Output
2
2 2
3 4
Case #1:
..+-+
..|.|
+-+-+
|.|.|
+-+-+
Case #2:
..+-+-+-+
..|.|.|.|
+-+-+-+-+
|.|.|.|.|
+-+-+-+-+
|.|.|.|.|
+-+-+-+-+

For each Punched Card, we can notice four distinct patterns.

  • First line: ..+-+-+-+. String that starts with ..+ and has a repeating pattern of -+ for a total of $C - 1$ times.
  • Second line: ..|.|.|.|. Starts with . and has a repeating pattern of .| for a total of $C$ times.
  • Rest of odd lines: +-+-+-+-+. Starts with + and repeats -+ $C$ times.
  • Rest of even lines: |.|.|.|.|. Prefix is | and repeats .| $C$ times.

We can create a function that creates a string with a prefix and repeats a pattern $n$ times. Then we group all rows and print them. This will give us our Punched Card!


O     O     O
o o o
...


Context

In very simple terms, you want to draw a Punched Card with ASCII art. Your input will be two integers $R, C$ representing the number of rows and the number of columns of your punched card, respectively. See the following example:

1
2
3
4
5
6
7
8
9
Input:
2 4

Output:
..+-+-+-+
..|.|.|.|
+-+-+-+-+
|.|.|.|.|
+-+-+-+-+

Notice the four dots at the top-left corner of the ASCII art. Those four dots will ALWAYS be on that same position on every Punched Card you draw.

Searching for patterns

To make this task easier, we will search for patterns to help us automate this task. We can immediately see two distinct patterns:

Top and Bottom:In Between:
+-+-+-+-+-+-+-+-+-+|.|.|.|.|.|.|.|

We can then break this patterns into \(\underbrace{+}_{P}\) and \(\underbrace{-+-+-+-+-+}_{Repeat}\), where $P$ is our prefix + and $Repeat$ is the pattern -+ that we’ll repeat after the prefix. This also applies to the pattern |.|.|.|.|.|.

Then we can exploit the prefix part for the top four dots by using ..+ as our prefix and -+ as our repeating pattern.


O     O     O
o o o
...


Solution

As seen on the Context section, we will automate the creation of every line using a prefix, a repeating pattern and the number of times the pattern will repeat. The code is as following:

1
2
3
function createRow(prefix: string, middle: string, count: number): string {
    return [prefix, ...Array(count + 1).join(middle).split(' ')].join('') + "\n";
}

The code starts by creating an array with the prefix as the first element. The rest of the elements will be count copies of the middle repeating pattern. Finally we join all the strings and append a new line \n.

After this, we can start creating the punch card ASCII art. We will define 4 different rows in total:

  1. rowX, which will serve as the +-+ pattern with the first .. dots.
  2. rowY will define the |.| pattern with the first two dots.
  3. rowA will be just the pattern of +-+.
  4. rowB bin be the pattern |.|.

The code will be the following:

1
2
3
4
5
6
7
8
9
10
11
12
13
function cardBuilder(row: number, col: number): string {
    const rowX = createRow("..+", "-+", col - 1);
    const rowY = createRow(".", ".|", col);
    const rowA = createRow("+", "-+", col);
    const rowB = createRow("|", ".|", col);

    return [
        rowX,   // <- First row.
        rowY,   // <- Second row.
        ...Array(row).join(rowA + rowB).split(' '),   // <- Rest of middle rows.
        rowA.substring(0, rowA.length - 1)   // <- Bottom row.
    ].join('');
}

Notice that we use a substring on the last rowA (line 11). This is because we get rid of the last \n, as the command console.log will print our last new line.

And this code will solve our problem. We just need to read the R C input and print the result from cardBuilder(R, C).

Reading the input

The best way that was found to read the input from stdin in Typescript was with first defining the following function:

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
declare var require: any;
declare var process: any;

// We import the library `readline`.
const readline = require('readline');

function read_lines_from_stdin(callback: (input_lines: string[]) => void) {
    // We will create an array to store all inputs.
    const input_lines: string[] = [];
    // We tell `readline` to read from stdin.
    const rl = readline.createInterface({
        input: process.stdin,
        output: process.stdout,
        terminal: false
    });

    // Every time a new input line is given, push it to our array.
    rl.on('line', (input: string) => {
        input_lines.push(input);
    });

    // When we finish reading the input, "return" the array of inputs.
    rl.on('close', () => {
        callback(input_lines);
    });
}

Then we can use the function to retrieve all the input lines and work with them. Here’s an example on how to use the function:

1
2
3
4
5
6
7
8
9
10
read_lines_from_stdin((input_lines) => {
    let first_input = parseInt(input_lines[0]);
    console.log(`The first input was ${first_input}.`);

    for (var i: number = 1; i <= first_input; i++)
    {
        my_input = input_lines[i];
        console.log(`Input #${i} is ${my_input}.`)
    }
})

We could’ve used the module Promises, but because Code Jam compiled Typescript in the following way:1

  • TypeScript:
    • 3.3.3333 (package: node-typescript)
    • tsc Solution.ts --module system --outFile Solution.js
    • nodejs Solution.js

we couldn’t really make the Promises module work. That’s why we share how we managed to read the user input.


O     O     O
o o o
...


Alternative Solutions

There’s really no alternative solutions that we could think of.


Footnotes

  1. See Code Jam FAQ on section Platform

This post is licensed under CC BY 4.0 by the author.

-

3D Printing