Skip to content

Selfhosting

Tinnaphop Choonchuachan edited this page May 12, 2025 · 1 revision

(Updated for version 0.1.0-alpha.10)

Requirements

To selfhost UntitledPasswordFindingGame, you will need:

  • A MongoDB instance installed on your server
  • Node.js installed on your server

Steps

0a. Setting Up

Clone the repository, then install dependencies.

0b. Environment Variables

An file called .env is also required for a UntitledPasswordFindingGame instance.

The file must contain the following keys:

  • DATABASE_URI, the URI to connect to MongoDB on.
  • PORT, the port for the app to run on.
  • RECAPTCHA_SECRET_KEY
  • RECAPTCHA_SITE_KEY
  • COOKIE_SECRET
  • CSRF_SECRET

The file should also contain these additional keys:

  • ENVIRONMENT
  • NODE_ENV
  • TESTING_RECAPTCHA_SITE_KEY
  • TESTING_RECAPTCHA_SECRET_KEY

1. Running

Run the command npm run start and access localhost on port PORT. That's it.

Appendix

A-1. Administrator Users

Set the isAdministrator field of the user(s) to make an administrator.

Administrators can access the administrator dashboard.

A-2. Configuring a Contest

Although problems can be directly added through the admin panel version 0.1.0-alpha.10 of UntitledPasswordFindingGame, contests can't be added in the same way.

For now, it must be added directly through the database.

The Contest schema is:

const contestSchema = new Schema({
  contestID: String,
  contestName: String,
  startDateAndTime: Date,
  endDateAndTime: Date,
  timestamp: Date,
  rules: {
    pointsLostPer: {
      interval: Number,
      intervalAmount: Number,
      wrongAnswers: Number,
      wrongAnswersAmount: Number
    },
    minimumPointsPerProblem: Number
  },
  participants: Array<String>,
  problems: Array<ContestProblemInterface>
});

See the full file for more details.

The keys are, in line order:

  • contestID
  • contestName
  • startDateAndTime, the timestamp to start the contest, in milliseconds after the epoch (i.e., start this contest this number of milliseconds after January 1, 1970 00:00 UTC)
  • endDateAndTime, the timestamp to end the contest, in milliseconds after the epoch (i.e., end this contest this number of milliseconds after January 1, 1970 00:00 UTC)
  • timestamp, unused, I forgot to remove it lol
  • rules.pointsLostPer.interval, the number of milliseconds since the contest start that must have passed before an "interval" is considered to have passed.
  • rules.pointsLostPer.intervalAmount, the amount of points to deduct per interval that passed.
  • rules.pointsLostPer.wrongAnswers, the number of wrong answers that must be sent before one "point deduction" is made.
  • rules.pointsLostPer.wrongAnswersAmount, the amount of points to deduct every rules.pointsLostPer.wrongAnswers wrong answers.
  • rules.minimumPointsPerProblem, the minimum score that a solved problem is guaranteed to earn a contestant.
  • participants, leave empty, used in a feature update.
  • problems, see the full file, should be self explanatory. Note that the problemID is the ID of the problem set in the problems collection.

A-2a. An Example Situtation

Assume a contest has interval of 1000ms, intervalAmount of 10, wrongAnswers of 2, wrongAnswersAmount of 200, minimumPointsPerProblem of 500, and a problem in problems having a maximumScore of 2500.

This is the score given to each fictional contestant. Assume that every contestant solved the problem, then, their scores would be:

Contestant Milliseconds since start time before solve Wrong answers before solve Score calculation Score for that problem
The Perfect 500 0 max(500, 2500 - floor(500/1000) * 10 - floor(0/2) * 200) 2500
The Speed Demon 500 17 max(500, 2500 - floor(500/1000) * 10 - floor(17/2) * 200) 900
The Thinker 5500 0 max(500, 2500 - floor(5500/1000) * 10 - floor(0/2) * 200) 2450
The Guesser 5500 17 max(500, 2500 - floor(5500/1000) * 10 - floor(17/2) * 200) 850
The Brute Forcer 30000 300 max(500, 2500 - floor(30000/1000) * 10 - floor(300/2) * 200) 500