Skip to content

Instantly share code, notes, and snippets.

@kawasima
Last active February 14, 2023 04:41
Show Gist options
  • Save kawasima/12143f104ce685e75a5a14d90f2cc2bf to your computer and use it in GitHub Desktop.
Save kawasima/12143f104ce685e75a5a14d90f2cc2bf to your computer and use it in GitHub Desktop.
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