Hi everybody,
For a TL;DR section just skip to the end.
Getting that out of the way, let's get started. So, today I wanted to explore again some algorithmics problems and I returned to CodeForces.
Lately, I have used a lot of Typescript so naturally, I wanted to use it here too and I gladly discovered that you can actually use javascript in it.
Then the next question was, but how can I run only a single file in my Typescript project that holds many other problems (or at least it will)?
I tried many solutions but I came about creating an npm package
that I can simply import or require since otherwise, I had issues with imports, paths, and more.
This is the package codeforces-io.
It is a simple mock for the readline()
and print()
functions so you do not have to modify your existing code while copying it to submission.
The documentation covers how to use it as a simple package, so I will write here a tutorial from start to finish with some advanced usages that you might like.
I created this package for those who want their code to be as close to the submission code
as possible without having to deal with the boilerplate™
e.g.1,2.
IP-Algorithmics / CodeForcesIO
Small package to mock Codeforces Javascript IO functions
CodeForces IO
Small package to mock Codeforces Javascript IO functions.
Install
npm i @ip-algorithmics/codeforces-io
Intro
Codeforces for Javascript/Typescript uses readline()
and print()
functions for input and output to the standard input/console.
How to use
This library exposes the functions in a manner that allows you to just copy the source code for the submission.
Importing the functions
The functions can be imported both as ES6 modules or using the require
function. The difference lays in how you access it.
// using ES6 modules import - you need to have the "module" property set to "commonjs" in the package.json
import { readline, print } from '@ip-algorithmics/codeforces-io';
// using require
const codeForcesIO = require('@ip-algorithmics/codeforces-io');
const readline = codeForcesIO.readline;
const print = codeForcesIO.print;
// alternative
const { readline, print, console } = require('@ip-algorithmics/codeforces-io');
readline()
This…
Too much talk, let's see the usage
First, you have to have an npm
project in the folder. So open up a terminal in your desired folder and just type npm init
. You can use the default.
Then npm i @ip-algorithmics/codeforces-io
If you do not use Typescript this is all you need to do, otherwise... just run this one after the other.
npm i -g typescript ts-node
Note: if you want to configure Typescript you will additionally need to run
tsc --init
Remember to not
include the "DOM" library into the lib
because the print
function is already declared in the DOM library for printing files.
You can just require/import the print
function for this package for output to the console. If need other functions from the console object you can require the entire console
.
Usage with ts-node
or node
Now that you have a working environment you can create a .js
or .ts
file and get going.
This library uses modern ES6 import/export modules but that means declaring a few more things in the project configuration.
So let's stay to require
for now.
At the top of your file just write
const {nextLine, print, console} = require('@ip-algorithmics/codeforces-io')
Now that we have our functions we can use them in the project.
The readline
function reads from input.txt
file that needs to be in the same folder.
Here is a quick example
// example.js or example.ts
const { readline, print } = require('@ip-algorithmics/codeforces-io');
let numberOfLines = parseInt(readline(), 10);
for (let i = 0; i < numberOfLines; i++) {
let x = readline()
.trim()
.split(',')
.map((x) => parseInt(x, 10));
if (x[0] < 90 || x[0] > 90 || x[1] < 90 || x[1] > 90) {
print(x);
break;
}
// do something with x
}
And here is the input.txt
3
-47,23
34,56
91,82
Now that we have our files in place we can just run
node example.js
or ts-node example.ts
. You can use an absolute or relative path, this library will search for the place where the script is and then read the input file from there.
So you do not have to cd <path>
you can just use node <path>/<file>
.
Usage with jest
For a simple reason. Paths can get really long and jest can use test names to find the file directly
Compare these:
ts-node src/1300-points/totally-real-problem/index.ts
-
jest -t 'totally-real-problem
I'd say it's a bit shorter. But how can you obtain that? Well, that is simple actually.
Just run npm i -g jest ts-jest
and npm i @types/jest
and then in the root of the project you need to create a file named jest.config.ts
and put the next lines in it:
export default {
preset: 'ts-jest',
testEnvironment: 'node',
transform: {
'node_modules/variables/.+\\.(j|t)sx?$': 'ts-jest'
},
transformIgnorePatterns: ['node_modules/(?!variables/.*)']
};
For javascript you can just run jest --init
and that will work by default.
Except for this, now all of your scripts will have to be a test
so the naming should be .test.ts or .spec.ts or create a folder named __tests__
and place your scripts in it (same things apply to javascript also).
Now you have to convert your scripts to tests. This is as simple as wrapping everything in
test('name of test', () => {
// your code
})
The example from above will get transformed to this.
test('example', () => {
const { readline, print, testOutput } = require('@ip-algorithmics/codeforces-io');
let numberOfLines = parseInt(readline(), 10);
for (let i = 0; i < numberOfLines; i++) {
let x = readline()
.trim()
.split(',')
.map((y) => parseInt(y, 10));
if ((x[0] < 90 && x[0] > -90) || (x[1] < 90 && x[1] > -90)) {
print(x[0] + ',' + x[1]);
break;
}
}
}
To run it just type jest -t 'example'
.
Special mention
For typescript projects if you use the same function names without putting them in a class you will get an error that the name is taken, so you have to add export {};
at the end of the file so the names will not conflict.
If something doesn't work do not hesitate to leave a comment, open an issue or even better create a pull request.
TL;DR
- Created a library for Codeforces that reads
input.txt
from the folder the script was called. npm i @ip-algorithmics/codeforces-io
- Code example
// example.js or example.ts
const { readline, print, testOutput } = require('@ip-algorithmics/codeforces-io');
let numberOfLines = parseInt(readline(), 10);
for (let i = 0; i < numberOfLines; i++) {
let x = readline()
.trim()
.split(',')
.map((y) => parseInt(y, 10));
if ((x[0] < 90 && x[0] > -90) || (x[1] < 90 && x[1] > -90)) {
print(x[0] + ',' + x[1]);
break;
}
}
And here is the input.txt
3
-47,23
34,56
91,82
-
node <path to file>/file.js
orts-node <path to file>/file.ts
Happy codding!
Update
I added the testOutput
function. Now you can create your output.txt
file and put the outputs in it.
You just have to run the function at the end of the script and it will prompt you with a Passed
or Failed
output in the console.
Remember not to copy this function in the submission.
Internally now the print
caches everything so that the testOutput
can check if what was printed is the same as what is in the output.txt
Example:
input.txt
3
-47,23
34,56
91,82
output.txt
-47,23
const { readline, print, testOutput } = require('@ip-algorithmics/codeforces-io');
let numberOfLines = parseInt(readline(), 10);
for (let i = 0; i < numberOfLines; i++) {
let x = readline()
.trim()
.split(',')
.map((y) => parseInt(y, 10));
if ((x[0] < 90 && x[0] > -90) || (x[1] < 90 && x[1] > -90)) {
print(x[0] + ',' + x[1]);
break;
}
}
testOutput(); // Result Passed
Update 2
The solution generator is completed. Now you can just create the input.txt
, output.txt
, index.ts
and the folder with a simple command. It will also add the imports for you.
You can use this feature in 2 ways:
- Without installing globally the library using
npx @ip-algorithmics/codeforces-io
. - Installing globally the library
npm i -g @ip-algorithmics/codeforces-io
and then usingcf
in the command line.
Parameters
-
path
- the path to the solution. E.g../ProblemA
. Defaults to./New Solution
. -
--f
or--file
- the name of the js/ts file to create. E.g.mainFile
. Defaults toindex
. -
--js
- Uses.js
extension instead of.ts
-
--cjs
- Usesrequire
instead of ES6import
/export
-
--c
or--comment
- Adds a comment at the beginning of the file. E.g. the link to the problem.
Usage examples
-
npx @ip-algorithmics/codeforces-io ./ProblemA --js --cjs
-
cf ./ProblemA --js --cjs
-
cf ./ProblemA
-
cf ./ProblemA --c http://link.to.problem
Update 3 - Typescript ideas
I noticed that Codforces uses ES5 internally in both node and V8 so it has problems with const
, let
and features like spreading an array.
Personally I found that the best solution is to:
- add in the
package.json
the following script"build": "tsc --module es6 --moduleResolution node"
using it likenpm run build <path>
- manually run
tsc --module es6 --moduleResolution node <path>
Top comments (0)