Skip to content Skip to sidebar Skip to footer

Getting Input In Kattis Challenges - Readline Js

I am doing a Kattis challenge - https://open.kattis.com/problems/bookingaroom Basically, I get initial input - let's say 6, 4 I have to store that input somewhere and then ask fo

Solution 1:

Kattis has a pretty tricky setup for Node due to the asynchronous callback API of readline. I'd normally use promises, then use split, map and + to parse the relevant input since numbers are usually involved. However, Kattis will stream readline's "line" events, then fire an end-of-file "close" event when the stream ends, and these aren't easy to use with promises.

Here's the high-level overview:

const readline = require("readline");

const rl = readline.createInterface({
  input: process.stdin,
  output: process.stdout,
});

rl.once("line", line => {
  // collect line 1, the preamble data

  rl.on("line", line => {
      // parse a line of the body data
    })
    .on("close", () => {
      // all data has been read// print the solution
    })
  ;
});

Here's an example that works for the booking a room problem:

const readline = require("readline");

const rl = readline.createInterface({
  input: process.stdin,
  output: process.stdout,
});

rl.once("line", line => {
  // collect line 1, the preamble dataconst rooms = [];
  const [r, n] = line.split(/ +/).map(Number);
  rl.on("line", line => {
      // parse a line of the body data
      rooms.push(+line);
    })
    .on("close", () => {
      // all data has been read// print the solutionif (r === n) {
        console.log("too late");
      }
      else {
        for (let i = 1; i <= r; i++) {
          if (!rooms.includes(i)) {
            console.log(i);
            break;
          }
        }
      }
    })
  ;
});

If the preamble is more than one line or you don't like the nesting, you could use an array or object of handlers, where each index is the handler for that particular line:

const readline = require("readline");

const rl = readline.createInterface({
  input: process.stdin,
  output: process.stdout,
});

let r;
let n;
const rooms = [];

const handlers = [
  line => { // handler for line 0
    [r, n] = line.split(/ +/).map(Number);
  },

  /* add more handlers as needed, for lines 2, 3... */// handler for all remaining linesline => rooms.push(+line),
];
let lines = 0;

rl.on("line", line => {
    handlers[Math.min(lines++, handlers.length - 1)](line);
  })
  .on("close", () => {
    // print the solutionif (r === n) {
      console.log("too late");
    }
    else {
      for (let i = 1; i <= r; i++) {
        if (!rooms.includes(i)) {
          console.log(i);
          break;
        }
      }
    }
  })
;

This isn't nearly as nice as promises or languages that allow blocking input, but it gets the job done.

See this gist for a similar approach that uses n as a counter to figure out when to print the final solution rather than listening for the "close" event. I haven't seen any problems where this is necessary yet -- Kattis usually seems to send the EOF, but I haven't used Kattis enough to know that my proposal will always work.

On many problems, you don't need to aggregate a final result at the end, so you can skip .close() and print results as they stream into your body data's "line" handler.

Solution 2:

As I understand the task I would do something like this:

let a, b;

rl.on('init', (line) => { 
   const nums = line.split(' '); 
   a = parseInt(nums[0]); 
   b = parseInt(nums[1]); 
});

//next partconst nextAnswers = [...Array(a)].map((_,i)=>{
   let answer;
   rl.on(`Next answer N:${i + 1}:`, a => (answer = a));    
   returnparseInt(answer);
})

Post a Comment for "Getting Input In Kattis Challenges - Readline Js"