Last active
February 14, 2023 04:41
-
-
Save kawasima/12143f104ce685e75a5a14d90f2cc2bf to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { match } from "ts-pattern"; | |
import z from "zod"; | |
const Station = z.object({ | |
name: z.string() | |
}) | |
const Time = z.object({ | |
hour: z.number().int().min(0).max(12), | |
minute: z.number().int().min(0).max(59), | |
}) | |
type Time = z.infer<typeof Time> | |
const Gender = z.union([z.literal("MALE"), z.literal("FEMALE")]) | |
type Gender = z.infer<typeof Gender> | |
const Age = z.number().int().min(0) | |
type Age = z.infer<typeof Age> | |
const Train = z.object({ | |
departureFrom: Station, | |
depatureAt: Time, | |
}) | |
type Train = z.infer<typeof Train> | |
const Person = z.object({ | |
gender: Gender, | |
age: Age, | |
hasHandicap: z.boolean(), | |
isHelper: z.boolean(), | |
}).brand("Person") | |
type Person = z.infer<typeof Person> | |
const Section = z.object({ | |
from: Station, | |
to: Station, | |
}) | |
type Section = z.infer<typeof Section> | |
type CanBoard = (p: Person, s :Section, t: Train) => boolean | |
type CanPersonBoardWomenOnly = (p: Person) => boolean | |
type IsWomenOnlyTrain = (t: Train) => boolean | |
type IsWomenOnlySection = (s: Section) => boolean | |
type HasHandicapOrHelper = (p: Person) => boolean | |
type IsJuvenile = (p: Person) => boolean | |
type TimeContains = (target: Time, from: Time, to: Time) => boolean | |
type SectionContains = (target: Section, preselected: Section) => boolean | |
// Implementations | |
const timeContains: TimeContains = (target, from, to) => | |
(from.hour < target.hour && target.hour < to.hour) | |
|| (target.hour === from.hour && target.minute >= from.minute) | |
|| (target.hour === to.hour && target.minute <= to.minute) | |
const sectionContains: SectionContains = (target, preselected)=> | |
true // Dummy; 実際は総武線の駅区間と照らし合わせて判定 | |
const hasHandicapOrHelper: HasHandicapOrHelper = person => | |
person.hasHandicap || person.isHelper | |
const isJuvenile:IsJuvenile = person => person.age <= 12 | |
const canPersonBoardWomenOnly: CanPersonBoardWomenOnly = person => | |
match(person) | |
.with({ gender: "MALE"}, p => hasHandicapOrHelper(p) || isJuvenile(p)) | |
.with({ gender: "FEMALE"}, _ => true) | |
.exhaustive() | |
const isWomenOnlyTrain: IsWomenOnlyTrain = train => | |
train.departureFrom.name === "西船橋" | |
&& timeContains(train.depatureAt, {hour: 6, minute: 57}, {hour: 8, minute: 56}) | |
const isWomenOnlySection: IsWomenOnlySection = section => | |
sectionContains(section, {from: {name: "千葉"}, to: {name: "御茶ノ水"}}) | |
const canBoard: CanBoard = (person, section, train) => | |
!isWomenOnlySection(section) | |
|| !isWomenOnlyTrain(train) | |
|| canPersonBoardWomenOnly(person) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment