Skip to content

Commit

Permalink
First working version
Browse files Browse the repository at this point in the history
  • Loading branch information
anakreon committed Aug 19, 2019
1 parent 26e6542 commit a6d307b
Show file tree
Hide file tree
Showing 18 changed files with 132 additions and 31 deletions.
1 change: 1 addition & 0 deletions src/Bulletin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ export class Bulletin {
this.requiredVaccinationsByNation[nation].add(vaccine);
}
public noLongerRequireVaccinationForNation (nation: Nation, vaccine: Vaccine): void {
console.log('noLongerRequireVaccinationForNation', nation, vaccine, this.requiredVaccinationsByNation[nation]);
this.requiredVaccinationsByNation[nation] = this.requiredVaccinationsByNation[nation] || new Set<Vaccine>();
this.requiredVaccinationsByNation[nation].delete(vaccine);
}
Expand Down
6 changes: 6 additions & 0 deletions src/Inspector.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import { RulesetBuilder } from './RulesetBuilder';
import { Ruleset } from './Ruleset';
import { CertificateOfVaccinationInterpreter } from './interpreters/paper/CertificateOfVaccinationInterpreter';
import { IdCardInterpreter } from './interpreters/paper/IdCardInterpreter';
import { WorkPassInterpreter } from './interpreters/paper/WorkPassInterpreter';

export class Inspector {
private bulletin: Bulletin;
Expand Down Expand Up @@ -82,6 +83,11 @@ export class Inspector {
const idCard = interpreter.interpret(inputPapers.ID_card);
papers.setIdCard(idCard);
}
if (inputPapers.work_pass) {
const interpreter = new WorkPassInterpreter();
const workPass = interpreter.interpret(inputPapers.work_pass);
papers.setWorkPass(workPass);
}
return papers;
}
}
8 changes: 8 additions & 0 deletions src/Papers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { DiplomaticAuthorization } from './papers/DiplomaticAuthorization';
import { PersonalData } from './papers/PersonalData';
import { IdCard } from './papers/IdCard';
import { CertificateOfVaccination } from './papers/CertificateOfVaccination';
import { WorkPass } from './papers/WorkPass';

export class Papers {
private passport: Passport;
Expand All @@ -13,6 +14,7 @@ export class Papers {
private diplomaticAuthorization: DiplomaticAuthorization;
private certificateOfVaccination: CertificateOfVaccination;
private idCard: IdCard;
private workPass: WorkPass;
private personalData: PersonalData;

constructor () {
Expand Down Expand Up @@ -43,6 +45,9 @@ export class Papers {
this.idCard = idCard;
this.personalData.fromIdCard(idCard);
}
public setWorkPass (workPass: WorkPass): void {
this.workPass = workPass;
}

public getPassport (): Passport {
return this.passport;
Expand All @@ -62,6 +67,9 @@ export class Papers {
public getIdCard (): IdCard {
return this.idCard;
}
public getWorkPass (): WorkPass {
return this.workPass;
}
public getPersonalData (): PersonalData {
return this.personalData;
}
Expand Down
62 changes: 40 additions & 22 deletions src/RulesetBuilder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,17 @@ import { NegateValidator } from './validators/NegateValidator';
import { NationConsistencyValidator } from './validators/NationConsistencyValidator';
import { HasIdCardValidator } from './validators/HasIDCardValidator';
import { HasVaccinationValidator } from './validators/HasVaccinationValidator';
import { Arstotzka } from './constants';
import { DisjunctiveValidator } from './validators/DisjunctiveValidator';
import { HasWorkPassValidator } from './validators/HasWorkPassValidator';
import { HasCertificateOfVaccinationValidator } from './validators/HasCertificateOfVaccinationValidator';
import { IsValidDiplomaticAuthorizationValidator } from './validators/IsValidDiplomaticAuthorizationValidator';
import { IsCitizenOfUnknownNationValidator } from './validators/IsCitizenOfUnknownNationValidator';

export class RulesetBuilder {
private deny: Rule[] = [];
private deny: Rule[] = [
new Rule(new IsCitizenOfUnknownNationValidator(), 'missing required passport.')
];
private detain: Rule[] = [
new Rule(new NegateValidator(new IdConsistencyValidator()), 'ID number mismatch.'),
new Rule(new NegateValidator(new DOBConsistencyValidator()), 'Date of birth mismatch.'),
Expand All @@ -36,9 +44,10 @@ export class RulesetBuilder {
];

public fromBulletin (bulletin: Bulletin): void {
bulletin.getDenied().forEach((nation: Nation) => {
this.deny.push(new Rule(new IsCitizenOfNationValidator(nation), 'citizen of banned nation.'));
});
const wantedName = bulletin.getWantedName();
if (wantedName) {
this.detain.unshift(new Rule(new IsAWantedCriminalValidator(wantedName), 'Entrant is a wanted criminal.'));
}
const requiredDocumentsByNation = bulletin.getRequiredDocumentsByNation();
for (var nation in requiredDocumentsByNation) {
if (requiredDocumentsByNation.hasOwnProperty(nation)) {
Expand All @@ -47,6 +56,9 @@ export class RulesetBuilder {
});
}
}
bulletin.getDenied().forEach((nation: Nation) => {
this.deny.push(new Rule(new IsCitizenOfNationValidator(nation), 'citizen of banned nation.'));
});
const requiredDocumentsForWorkers = bulletin.getrequiredDocumentsForWorkers();
requiredDocumentsForWorkers.forEach((document: Document) => {
this.addDocumentValidatorsForWorkers(document);
Expand All @@ -55,14 +67,11 @@ export class RulesetBuilder {
for (var nation in requiredVaccinationsByNation) {
if (requiredVaccinationsByNation.hasOwnProperty(nation)) {
requiredVaccinationsByNation[nation].forEach((vaccine: Vaccine) => {
this.deny.push(new Rule(new NegateValidator(new ImplicativeValidator(new IsCitizenOfNationValidator(nation), new HasVaccinationValidator(vaccine))), 'missing required certificate of vaccination.'));
this.deny.push(new Rule(new NegateValidator(new ImplicativeValidator(new IsCitizenOfNationValidator(nation), new HasCertificateOfVaccinationValidator())), 'missing required certificate of vaccination.'));
this.deny.push(new Rule(new NegateValidator(new ImplicativeValidator(new IsCitizenOfNationValidator(nation), new HasVaccinationValidator(vaccine))), 'missing required vaccination.'));
});
}
}
const wantedName = bulletin.getWantedName();
if (wantedName) {
this.detain.unshift(new Rule(new IsAWantedCriminalValidator(wantedName), 'Entrant is a wanted criminal.'));
}
}

private addDocumentValidatorsForNation (nation: Nation, document: Document) {
Expand All @@ -75,17 +84,26 @@ export class RulesetBuilder {
this.deny.push(new Rule(new NegateValidator(new ImplicativeValidator(new IsCitizenOfNationValidator(nation), new HasIdCardValidator())), 'missing required ' + document + '.'));
break;
case 'access permit':
this.deny.push(new Rule(new NegateValidator(new ImplicativeValidator(new IsCitizenOfNationValidator(nation), new HasAccessPermitValidator())), 'missing required ' + document + '.'));
this.deny.push(new Rule(new NegateValidator(new ImplicativeValidator(new IsCitizenOfNationValidator(nation), new NegateValidator(new IsAccessPermitExpiredValidator()))), document + ' expired.'));
//if foreigner ->
//OR
//grant of asylum - valid
//OR
//diplomatic authorization - valid & Arstotzka in list of nations
if (nation === Arstotzka) {
this.deny.push(new Rule(new NegateValidator(new ImplicativeValidator(new IsCitizenOfNationValidator(nation), new HasAccessPermitValidator())), 'missing required ' + document + '.'));
this.deny.push(new Rule(new NegateValidator(new ImplicativeValidator(new IsCitizenOfNationValidator(nation), new NegateValidator(new IsAccessPermitExpiredValidator()))), document + ' expired.'));
} else {
const hasAccessPermit = new HasAccessPermitValidator();
const hasGrantOfAsylumOrDiplomaticAuthorization = new DisjunctiveValidator(new HasGrantOfAsylumValidator(), new HasDiplomaticAuthorizationValidator());
this.deny.push(new Rule(new NegateValidator(new ImplicativeValidator(new IsCitizenOfNationValidator(nation), new DisjunctiveValidator(hasAccessPermit, hasGrantOfAsylumOrDiplomaticAuthorization))), 'missing required ' + document + '.'));
const ifHasAccessPermitItIsValid = new ImplicativeValidator(hasAccessPermit, new NegateValidator(new IsAccessPermitExpiredValidator()));
this.deny.push(new Rule(new NegateValidator(new ImplicativeValidator(new IsCitizenOfNationValidator(nation), ifHasAccessPermitItIsValid)), document + ' expired.'));
const ifHasGrantOfAsylumItIsNotExpired = new ImplicativeValidator(new HasGrantOfAsylumValidator(), new NegateValidator(new IsGrantOfAsylumExpiredValidator()));
this.deny.push(new Rule(new NegateValidator(new ImplicativeValidator(new IsCitizenOfNationValidator(nation), ifHasGrantOfAsylumItIsNotExpired)), 'grant of asylum expired.'));
const ifHasDiplomaticAuthorizationItIsNotExpired = new ImplicativeValidator(new HasDiplomaticAuthorizationValidator(), new NegateValidator(new IsDiplomaticAuthorizationExpiredValidator()));
this.deny.push(new Rule(new NegateValidator(new ImplicativeValidator(new IsCitizenOfNationValidator(nation), ifHasDiplomaticAuthorizationItIsNotExpired)), 'diplomatic authorization expired.'));
const ifHasDiplomaticAuthorizationItIsValid = new ImplicativeValidator(new HasDiplomaticAuthorizationValidator(), new IsValidDiplomaticAuthorizationValidator());
this.deny.push(new Rule(new NegateValidator(new ImplicativeValidator(new IsCitizenOfNationValidator(nation), ifHasDiplomaticAuthorizationItIsValid)), 'invalid diplomatic authorization.'));
}
break;
case 'work pass':
this.deny.push(new Rule(new NegateValidator(new ImplicativeValidator(new IsCitizenOfNationValidator(nation), new HasWorkPassValidator())), 'missing required ' + document + '.'));
break;
/*case 'work pass':
documentValidator = new HasWorkPassValidator();
break;*/
case 'grant of asylum':
this.deny.push(new Rule(new NegateValidator(new ImplicativeValidator(new IsCitizenOfNationValidator(nation), new HasGrantOfAsylumValidator())), 'missing required ' + document + '.'));
this.deny.push(new Rule(new NegateValidator(new ImplicativeValidator(new IsCitizenOfNationValidator(nation), new NegateValidator(new IsGrantOfAsylumExpiredValidator()))), document + ' expired.'));
Expand Down Expand Up @@ -115,9 +133,9 @@ export class RulesetBuilder {
//OR
//diplomatic authorization - valid & Arstotzka in list of nations
break;
/*case 'work pass':
documentValidator = new HasWorkPassValidator();
break;*/
case 'work pass':
this.deny.push(new Rule(new NegateValidator(new ImplicativeValidator(new IsWorkerValidator(), new HasWorkPassValidator())), 'missing required ' + document + '.'));
break;
case 'grant of asylum':
this.deny.push(new Rule(new NegateValidator(new ImplicativeValidator(new IsWorkerValidator(), new HasGrantOfAsylumValidator())), 'missing required ' + document + '.'));
this.deny.push(new Rule(new NegateValidator(new ImplicativeValidator(new IsWorkerValidator(), new NegateValidator(new IsGrantOfAsylumExpiredValidator()))), document + ' expired.'));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@ import { Nation, Vaccine } from '../../../types';

export class RequireVaccinationForNationExpression extends Expression {
protected processLine (line: string, bulletin: Bulletin): void {
const isNoLongerRule = line.includes('no longer');
if (isNoLongerRule) return;

const requireRegex = /^Citizens of (.*) require (.*) vaccination$/;
const lineDecomposition = line.trim().match(requireRegex);
if (!lineDecomposition) return;
Expand Down
2 changes: 2 additions & 0 deletions src/interpreters/paper/DiplomaticAuthorizationInterpreter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,15 @@ import { NationExpression } from './expressions/NationExpression';
import { ExpiryExpression } from './expressions/ExpiryExpression';
import { IdExpression } from './expressions/IdExpression';
import { DiplomaticAuthorization } from '../../papers/DiplomaticAuthorization';
import { AccessExpression } from './expressions/AccessExpression';

export class DiplomaticAuthorizationInterpreter {

public interpret (input: string): DiplomaticAuthorization {
const diplomaticAuthorization = new DiplomaticAuthorization();
const tree = <Expression<DiplomaticAuthorization>[]> [];
tree.push(new IdExpression());
tree.push(new AccessExpression());
tree.push(new NameExpression());
tree.push(new NationExpression());
tree.push(new ExpiryExpression());
Expand Down
17 changes: 17 additions & 0 deletions src/interpreters/paper/WorkPassInterpreter.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import { Expression } from './expressions/Expression';
import { AccessPermit } from '../../papers/AccessPermit';
import { WorkPass } from '../../papers/WorkPass';

export class WorkPassInterpreter {

public interpret (input: string): WorkPass {
const accessPermit = new AccessPermit();
const tree = <Expression<AccessPermit>[]> [];

tree.forEach((expression: Expression<AccessPermit>) => {
expression.interpret(input, accessPermit);
});

return accessPermit;
}
}
3 changes: 2 additions & 1 deletion src/interpreters/paper/expressions/AccessExpression.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ export class AccessExpression extends Expression<AccessSetter> {
return name === 'ACCESS';
}
protected setValue (setter: AccessSetter, value: Nation): void {
setter.setAccess(value);
const nations = <Nation[]>value.split(', ');
setter.setAccess(nations);
}
}
8 changes: 4 additions & 4 deletions src/papers/DiplomaticAuthorization.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,13 @@ import { Paper } from './Paper';
import { Nation } from '../types';

export class DiplomaticAuthorization extends Paper {
private access: Nation;
private access: Nation[];

public setAccess (access: Nation): void {
public setAccess (access: Nation[]): void {
this.access = access;
}

public getAccess (): Nation {
return this.access;
public canAccess (nation: Nation): boolean {
return this.access.includes(nation);
}
}
3 changes: 3 additions & 0 deletions src/papers/WorkPass.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export class WorkPass {

}
4 changes: 3 additions & 1 deletion src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { DiplomaticAuthorization } from './papers/DiplomaticAuthorization';
import { PersonalData } from './papers/PersonalData';
import { IdCard } from './papers/IdCard';
import { CertificateOfVaccination } from './papers/CertificateOfVaccination';
import { WorkPass } from './papers/WorkPass';

export type Nation = 'Arstotzka' | 'Antegria' | 'Impor' | 'Kolechia' | 'Obristan' | 'Republia' | 'United Federation'
export type Sex = 'M' | 'F';
Expand All @@ -27,7 +28,7 @@ export interface InputPapers {
}

export interface AccessSetter {
setAccess (access: Nation): void;
setAccess (access: Nation[]): void;
}
export interface AccessGetter {
getAccess (): Nation;
Expand Down Expand Up @@ -112,6 +113,7 @@ export interface Papers {
getDiplomaticAuthorization (): DiplomaticAuthorization;
getCertificateOfVaccination (): CertificateOfVaccination;
getIdCard (): IdCard;
getWorkPass (): WorkPass;
getPersonalData (): PersonalData;
}

Expand Down
9 changes: 9 additions & 0 deletions src/validators/DisjunctiveValidator.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import { Validator, Papers } from '../types';

export class DisjunctiveValidator implements Validator {
constructor (private validatorA: Validator, private validatorB: Validator) {}

public validate (papers: Papers): boolean {
return this.validatorA.validate(papers) || this.validatorB.validate(papers);
}
}
7 changes: 7 additions & 0 deletions src/validators/HasCertificateOfVaccinationValidator.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import { Validator, Papers } from '../types';

export class HasCertificateOfVaccinationValidator implements Validator {
public validate (papers: Papers): boolean {
return !!papers.getCertificateOfVaccination();
}
}
7 changes: 7 additions & 0 deletions src/validators/HasWorkPassValidator.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import { Validator, Papers } from '../types';

export class HasWorkPassValidator implements Validator {
public validate (papers: Papers): boolean {
return !!papers.getWorkPass()
}
}
3 changes: 2 additions & 1 deletion src/validators/IdConsistencyValidator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@ export class IdConsistencyValidator extends ConsistencyValidator<IdGetter, strin
papers.getAccessPermit(),
papers.getDiplomaticAuthorization(),
papers.getGrantOfAsylum(),
papers.getPassport()
papers.getPassport(),
papers.getCertificateOfVaccination()
];
}

Expand Down
3 changes: 1 addition & 2 deletions src/validators/IsCitizenOfNationValidator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ export class IsCitizenOfNationValidator implements Validator {

public validate (papers: Papers): boolean {
const personalData = papers.getPersonalData();
const nation = personalData.getNation();
return !nation || nation === this.nationName;
return this.nationName === personalData.getNation();
}
}
8 changes: 8 additions & 0 deletions src/validators/IsCitizenOfUnknownNationValidator.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import { Papers, Validator } from '../types';

export class IsCitizenOfUnknownNationValidator implements Validator {
public validate (papers: Papers): boolean {
const personalData = papers.getPersonalData();
return !personalData.getNation();
}
}
9 changes: 9 additions & 0 deletions src/validators/IsValidDiplomaticAuthorizationValidator.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import { Validator, Papers } from '../types';
import { Arstotzka } from '../constants';

export class IsValidDiplomaticAuthorizationValidator implements Validator {
public validate (papers: Papers): boolean {
const diplomaticAuthorization = papers.getDiplomaticAuthorization();
return diplomaticAuthorization && diplomaticAuthorization.canAccess(Arstotzka);
}
}

0 comments on commit a6d307b

Please sign in to comment.