diff --git a/allocate_laptop.py b/allocate_laptop.py new file mode 100644 index 000000000..3a842d9dc --- /dev/null +++ b/allocate_laptop.py @@ -0,0 +1,91 @@ +from dataclasses import dataclass +from enum import Enum +from typing import List, Dict, Tuple, Optional + +class OperatingSystem(Enum): + MACOS = "macOS" + ARCH = "Arch Linux" + UBUNTU = "Ubuntu" + +@dataclass(frozen=True) +class Person: + name: str + age: int + # Sorted in order of preference, most preferred is first. + preferred_operating_systems: List[OperatingSystem] + + +@dataclass(frozen=True) +class Laptop: + id: int + manufacturer: str + model: str + screen_size_in_inches: float + operating_system: OperatingSystem + +def norm_os_values(value: str) -> OperatingSystem: + value = value.strip().lower() + if value == "ubuntu": + return OperatingSystem.UBUNTU + if value == "arch linux": + return OperatingSystem.ARCH + if value == "macos": + return OperatingSystem.MACOS + raise ValueError(f"Unknown OS: {value}") + + +people = [ + Person(name="Imran", age=22, preferred_operating_systems=[norm_os_values("Ubuntu"), norm_os_values("Arch Linux")]), + Person(name="Eliza", age=34, preferred_operating_systems=[norm_os_values("Arch Linux"), norm_os_values("macOS"), norm_os_values("Ubuntu")]), + Person(name="Ira", age=21, preferred_operating_systems=[norm_os_values("Ubuntu"), norm_os_values("Arch Linux")]), + Person(name="Anna", age=34, preferred_operating_systems=[norm_os_values("Ubuntu"), norm_os_values("macOS")]), + Person(name="Nahimn", age=42, preferred_operating_systems=[norm_os_values("Ubuntu"), norm_os_values("Arch Linux")]) +] + +laptops = [ + Laptop(id=1, manufacturer="Dell", model="XPS", screen_size_in_inches=13, operating_system=norm_os_values("Arch Linux")), + Laptop(id=2, manufacturer="Dell", model="XPS", screen_size_in_inches=15, operating_system=norm_os_values("Ubuntu")), + Laptop(id=3, manufacturer="Dell", model="XPS", screen_size_in_inches=15, operating_system=norm_os_values("ubuntu")), + Laptop(id=4, manufacturer="Apple", model="macBook", screen_size_in_inches=13, operating_system=norm_os_values("macOS")), +] + + +def allocate_laptops(people: List[Person], laptops: List[Laptop]) -> Dict[Tuple[str, int], int]: + sadness_table: Dict[Tuple[str, int], int] = {} + for person in people: + for laptop in laptops: + if laptop.operating_system in person.preferred_operating_systems: + index = person.preferred_operating_systems.index(laptop.operating_system) + sadness = index + else: + sadness = 100 + sadness_table[(person.name, laptop.id)] = sadness + return sadness_table + + +sadness_table = allocate_laptops(people, laptops) + +allocation_list: List[Tuple[str, Optional[int], int]] = [] +allocated_laptops: set[int] = set() +allocated_persons: set[str] = set() +total_happiness: int = 0 + +for (person_name, laptop_id), sadness in sorted(sadness_table.items(), key=lambda value: value[1]): + if laptop_id in allocated_laptops: + continue + if person_name in allocated_persons: + continue + allocation_list.append((person_name, laptop_id, sadness)) + allocated_laptops.add(laptop_id) + allocated_persons.add(person_name) + total_happiness += sadness + print(f"{person_name} got laptop {laptop_id}") + + +for person in people: + if person.name not in allocated_persons: + print(f"{person.name} did not get laptop") +print(f"Total happiness: {total_happiness}") + +print(allocation_list) + diff --git a/implement-shell-tools/cat/cat.js b/implement-shell-tools/cat/cat.js new file mode 100644 index 000000000..331be0929 --- /dev/null +++ b/implement-shell-tools/cat/cat.js @@ -0,0 +1,33 @@ +import process from "node:process"; +import { promises as fs } from "node:fs"; + +const arrArgv = process.argv.slice(2); + +const numberLines = arrArgv.includes("-n"); +const numberNonemptyLines = arrArgv.includes("-b"); + +const nonFlagArrArgv = arrArgv.filter((arr) => !arr.startsWith("-")); + +let number = 1; + +for (let file of nonFlagArrArgv) { + const content = await fs.readFile(file, "utf-8"); + + const linedText = content.split("\n"); + + const numbered = linedText.map((line) => { + if (numberNonemptyLines) { + if (line.trim() === "") { + return line; + } else { + return `${String(number++).padStart(3)} ${line}`; + } + } + if (numberLines) { + return `${String(number++).padStart(3)} ${line}`; + } + + return line; + }); + console.log(numbered.join("\n")); +} diff --git a/implement-shell-tools/ls/ls.js b/implement-shell-tools/ls/ls.js new file mode 100644 index 000000000..47414da60 --- /dev/null +++ b/implement-shell-tools/ls/ls.js @@ -0,0 +1,56 @@ +import process from "node:process"; +import { promises as fs } from "node:fs"; +import path from "node:path"; + +const arrArgv = process.argv.slice(2); + +const longFormat = arrArgv.includes("-l"); +const showHidden = arrArgv.includes("-a"); + +const paths = arrArgv.filter((argv) => !argv.startsWith("-")); +if (paths.length === 0) path = "[.]"; + +for (let listFile of paths) { + const status = await fs.stat(listFile); + + if (status.isFile()) { + const permissions = (status.mode & 0o777).toString(8); + const sizeFile = status.size; + const owner = status.uid; + const group = status.gid; + const timeMod = status.mtime.toLocaleString(); + + if (longFormat) { + console.log( + `${permissions}, ${owner}, ${group}, ${sizeFile}, ${timeMod}, ${listFile}` + ); + } else { + console.log(listFile); + } + } else { + let files = await fs.readdir(listFile, { withFileTypes: true }); + + if (!showHidden) { + files = files.filter((file) => !file.name.startsWith(".")); + } + + for (let file of files) { + const wholePath = path.join(listFile, file.name); + const statusFile = await fs.stat(wholePath); + + const permissions = (statusFile.mode & 0o777).toString(8); + const sizeFile = statusFile.size; + const owner = statusFile.uid; + const group = statusFile.gid; + const timeMod = statusFile.mtime.toLocaleString(); + + if (longFormat) { + console.log( + `${permissions}, ${owner}, ${group}, ${sizeFile}, ${timeMod}, ${file.name}` + ); + } else { + console.log(file.name); + } + } + } +} diff --git a/implement-shell-tools/wc/wc.js b/implement-shell-tools/wc/wc.js new file mode 100644 index 000000000..2648d62d3 --- /dev/null +++ b/implement-shell-tools/wc/wc.js @@ -0,0 +1,38 @@ +import process from "node:process"; +import { promises as fs } from "node:fs"; + +const arrArgv = process.argv.slice(2); + +const lines = arrArgv.includes("-l"); +const words = arrArgv.includes("-w"); +const bytes = arrArgv.includes("-c"); + +const noFlags = !lines && !words && !bytes; + +const paths = arrArgv.filter((argv) => !argv.startsWith("-")); + +for (let path of paths) { + const context = await fs.readFile(path, "utf-8"); + + const countLines = context.split(/\r?\n/).length; + const countWords = context.split(/\s+/).length; + const countBytes = Buffer.byteLength(context, "utf-8"); + + let startInput = ""; + + if (noFlags || lines) { + startInput += `${countLines} `; + } + + if (noFlags || words) { + startInput += `${countWords} `; + } + + if (noFlags || bytes) { + startInput += `${countBytes} `; + } + + startInput += path; + + console.log(startInput); +}