{ }codelper
methodsclasses64-bit integersP0276

Editing a floor plan with chained methods

A room on the floor plan is a rectangle with sides parallel to the axes, given by its lower-left corner (x1, y1) and upper-right corner (x2, y2) (x1 < x2, y1 < y2). Make a room a class Room with the following methods. move(dx, dy) moves the room by dx horizontally and dy vertically. scale(k) enlarges the room k times about the origin.
That is, every corner coordinate is multiplied by k. turn(t) rotates the room about the origin by 90 degrees counterclockwise, t times.
One turn sends a point (x, y) to (−y, x). After turning, the room is still given by its lower-left and upper-right corners. move, scale and turn return the room object itself, so they can be chained as room.move(dx, dy).scale(k).turn(t). copy() returns a new room in the same place.
After copying, the two rooms move separately. area() returns the area, and overlap(other) returns the area of the part where the two rooms overlap.
If they only touch along a side or at a corner, the overlap is 0. The first line gives the number of commands q, and each of the next q lines gives one command. "new name x1 y1 x2 y2" creates a room with that name.
If the name already exists, it is replaced by the new room. "copy newname name" copies the room name with copy() and stores it as newname.
If newname exists it is replaced, and the two names may be the same. "do name dx dy k t" calls move(dx, dy).scale(k).turn(t) on that room as one chain. "area name" prints the area, "overlap name1 name2" the overlap area, and "show name" prints "x1 y1 x2 y2" on one line.

Input
1 ≤ q ≤ 2,000.
Names are 1 to 10 lowercase letters or digits.
Every room named by a command other than new and copy, and the source of a copy, already exists.
−1,000,000 ≤ dx, dy ≤ 1,000,000, 1 ≤ k ≤ 3, 0 ≤ t ≤ 3.
Every room's coordinates are always integers from −1,000,000 to 1,000,000, after every command and after every single method call within a chain
Output
One line for each area, overlap and show command (areas as plain digits, no commas)
Example 1 · stdin
9
new a 0 0 4 2
copy b a
do b 1 1 2 1
show a
show b
area b
new c -3 -1 0 5
overlap b c
overlap a c
stdout
0 0 4 2
-6 2 -2 10
32
3
0
main.py
Input (stdin)

When you run, these lines are fed to input()/stdin in order (the program doesn't stop to ask).

$ Ready

Open this on a computer to write and run code. On mobile you can read the problem and the solutions.

In other languagesShow solutions by language · 6 languages

This problem accepts only Python, JavaScript, TypeScript, Java, C# and C++, the languages with classes and methods (C has no methods, and Craykon cannot define classes yet).
To chain methods, a method returns the object itself: Python return self, JS/Java/C# return this, TypeScript writes the return type as this and return this, and C++ returns Room& with return *this.
The big difference is whether 'itself' travels as a reference or a copy.
Class objects in Python, JS, TS, Java and C# are always references, so returning this lets the next method change the same room.
In C++, returning Room (by value) hands back a copy, so in rooms[a].move(…).scale(…) everything from scale on changes the copy and is lost — it compiles with no warning.
The other way round, references are the trap when copying: in Python, JS, TS, Java and C#, rooms[b] = rooms[a] only makes two names point to the same object, so moving b moves a too.
That is why you need a copy() that makes a new object.
C++ stores objects by value, so rooms[b] = rooms[a] already copies (the copy constructor plays the part of copy()).
In C#, making Room a struct gives a copy every time you take it out of the dictionary, so changes vanish; make it a class.
Turning: one turn sends the lower-left (x1, y1) to (−y1, x1), which becomes the lower-right, so the new lower-left is (−y2, x1) and the new upper-right is (−y1, x2) — just turning the two corners gives x1 > x2 and a negative area.
The overlap area is max(0, width) × max(0, height) — multiplying directly turns two rooms apart along a diagonal into negative × negative = positive.
Areas reach (2×10^6)² = 4×10^12, so Java, C# and C++ need long or long long (multiplying two ints overflows); Python integers have no limit, and JS/TS numbers are exact up to 2^53, so they work as they are.
Example: b goes (1, 1, 5, 3) → (2, 2, 10, 6) → turned to (−6, 2, −2, 10), and a stays where it was.

Pythonmain.py · 66 lines
import sys  class Room:    """도면 위의 네모난 방: 왼쪽 아래 (x1, y1), 오른쪽 위 (x2, y2)"""     def __init__(self, x1, y1, x2, y2):        self.x1, self.y1, self.x2, self.y2 = x1, y1, x2, y2     # move·scale·turn은 자기 자신(self)을 돌려준다: room.move(...).scale(...).turn(...)처럼 이어 부를 수 있다    def move(self, dx, dy):        self.x1 += dx        self.x2 += dx        self.y1 += dy        self.y2 += dy        return self     def scale(self, k):        self.x1 *= k        self.y1 *= k        self.x2 *= k        self.y2 *= k        return self     def turn(self, times):        for _ in range(times):            # 원점을 중심으로 왼쪽으로 90도: (x, y) → (-y, x). 돌린 뒤 왼쪽 아래·오른쪽 위를 다시 고른다            self.x1, self.y1, self.x2, self.y2 = -self.y2, self.x1, -self.y1, self.x2        return self     def copy(self):        return Room(self.x1, self.y1, self.x2, self.y2)  # 새 객체: 앞으로 따로 움직인다     def area(self):        return (self.x2 - self.x1) * (self.y2 - self.y1)     def overlap(self, other):        w = min(self.x2, other.x2) - max(self.x1, other.x1)        h = min(self.y2, other.y2) - max(self.y1, other.y1)        return max(0, w) * max(0, h)  # 한쪽이라도 0 이하면 겹치지 않는다     def __str__(self):        return f"{self.x1} {self.y1} {self.x2} {self.y2}"  lines = sys.stdin.read().split("\n")q = int(lines[0])rooms = {}out = []for i in range(1, q + 1):    p = lines[i].split()    cmd = p[0]    if cmd == "new":        rooms[p[1]] = Room(*map(int, p[2:6]))    elif cmd == "copy":        rooms[p[1]] = rooms[p[2]].copy()    elif cmd == "do":        dx, dy, k, t = map(int, p[2:6])        rooms[p[1]].move(dx, dy).scale(k).turn(t)    elif cmd == "area":        out.append(str(rooms[p[1]].area()))    elif cmd == "overlap":        out.append(str(rooms[p[1]].overlap(rooms[p[2]])))    else:  # show        out.append(str(rooms[p[1]]))print("\n".join(out))
JavaScriptmain.js · 70 lines
const lines = require("fs").readFileSync(0, "utf8").split("\n"); // 도면 위의 네모난 방: 왼쪽 아래 (x1, y1), 오른쪽 위 (x2, y2)class Room {  constructor(x1, y1, x2, y2) {    this.x1 = x1;    this.y1 = y1;    this.x2 = x2;    this.y2 = y2;  }   // move·scale·turn은 자기 자신(this)을 돌려준다: room.move(...).scale(...).turn(...)처럼 이어 부를 수 있다  move(dx, dy) {    this.x1 += dx;    this.x2 += dx;    this.y1 += dy;    this.y2 += dy;    return this;  }   scale(k) {    this.x1 *= k;    this.y1 *= k;    this.x2 *= k;    this.y2 *= k;    return this;  }   turn(times) {    for (let i = 0; i < times; i++) {      // 원점을 중심으로 왼쪽으로 90도: (x, y) → (-y, x). 돌린 뒤 왼쪽 아래·오른쪽 위를 다시 고른다      [this.x1, this.y1, this.x2, this.y2] = [-this.y2, this.x1, -this.y1, this.x2];    }    return this;  }   copy() {    return new Room(this.x1, this.y1, this.x2, this.y2); // 새 객체: 앞으로 따로 움직인다  }   area() {    return (this.x2 - this.x1) * (this.y2 - this.y1); // 4×10^12까지: number는 2^53까지 정확하다  }   overlap(other) {    const w = Math.min(this.x2, other.x2) - Math.max(this.x1, other.x1);    const h = Math.min(this.y2, other.y2) - Math.max(this.y1, other.y1);    return Math.max(0, w) * Math.max(0, h); // 한쪽이라도 0 이하면 겹치지 않는다  }   toString() {    return `${this.x1} ${this.y1} ${this.x2} ${this.y2}`;  }} const q = Number(lines[0]);const rooms = new Map();const out = [];for (let i = 1; i <= q; i++) {  const p = lines[i].trim().split(" ");  const [cmd, a, b] = p;  const num = p.slice(2).map(Number);  if (cmd === "new") rooms.set(a, new Room(num[0], num[1], num[2], num[3]));  else if (cmd === "copy") rooms.set(a, rooms.get(b).copy());  else if (cmd === "do") rooms.get(a).move(num[0], num[1]).scale(num[2]).turn(num[3]);  else if (cmd === "area") out.push(rooms.get(a).area());  else if (cmd === "overlap") out.push(rooms.get(a).overlap(rooms.get(b)));  else out.push(String(rooms.get(a)));}console.log(out.join("\n"));
TypeScriptmain.ts · 73 lines
import { readFileSync } from "node:fs"; const lines: string[] = readFileSync(0, "utf8").split("\n"); // 도면 위의 네모난 방: 왼쪽 아래 (x1, y1), 오른쪽 위 (x2, y2)class Room {  constructor(    private x1: number,    private y1: number,    private x2: number,    private y2: number,  ) {}   // move·scale·turn은 자기 자신을 돌려준다(돌려주는 타입 this): room.move(...).scale(...).turn(...)  move(dx: number, dy: number): this {    this.x1 += dx;    this.x2 += dx;    this.y1 += dy;    this.y2 += dy;    return this;  }   scale(k: number): this {    this.x1 *= k;    this.y1 *= k;    this.x2 *= k;    this.y2 *= k;    return this;  }   turn(times: number): this {    for (let i = 0; i < times; i++) {      // 원점을 중심으로 왼쪽으로 90도: (x, y) → (-y, x). 돌린 뒤 왼쪽 아래·오른쪽 위를 다시 고른다      [this.x1, this.y1, this.x2, this.y2] = [-this.y2, this.x1, -this.y1, this.x2];    }    return this;  }   copy(): Room {    return new Room(this.x1, this.y1, this.x2, this.y2); // 새 객체: 앞으로 따로 움직인다  }   area(): number {    return (this.x2 - this.x1) * (this.y2 - this.y1); // 4×10^12까지: number는 2^53까지 정확하다  }   overlap(other: Room): number {    const w = Math.min(this.x2, other.x2) - Math.max(this.x1, other.x1);    const h = Math.min(this.y2, other.y2) - Math.max(this.y1, other.y1);    return Math.max(0, w) * Math.max(0, h); // 한쪽이라도 0 이하면 겹치지 않는다  }   toString(): string {    return `${this.x1} ${this.y1} ${this.x2} ${this.y2}`;  }} const q = Number(lines[0]);const rooms = new Map<string, Room>();const out: string[] = [];const get = (name: string): Room => rooms.get(name)!; // 입력에 나오는 이름은 모두 이미 있다for (let i = 1; i <= q; i++) {  const p = lines[i].trim().split(" ");  const [cmd, a, b] = p;  const num = p.slice(2).map(Number);  if (cmd === "new") rooms.set(a, new Room(num[0], num[1], num[2], num[3]));  else if (cmd === "copy") rooms.set(a, get(b).copy());  else if (cmd === "do") get(a).move(num[0], num[1]).scale(num[2]).turn(num[3]);  else if (cmd === "area") out.push(String(get(a).area()));  else if (cmd === "overlap") out.push(String(get(a).overlap(get(b))));  else out.push(get(a).toString());}console.log(out.join("\n"));
JavaMain.java · 66 lines
import java.io.*;import java.util.*; public class Main {    // 도면 위의 네모난 방: 왼쪽 아래 (x1, y1), 오른쪽 위 (x2, y2)    static class Room {        private long x1, y1, x2, y2;         Room(long x1, long y1, long x2, long y2) {            this.x1 = x1; this.y1 = y1; this.x2 = x2; this.y2 = y2;        }         // move·scale·turn은 자기 자신(this)을 돌려준다: room.move(...).scale(...).turn(...)처럼 이어 부를 수 있다        Room move(long dx, long dy) {            x1 += dx; x2 += dx;            y1 += dy; y2 += dy;            return this;        }         Room scale(long k) {            x1 *= k; y1 *= k; x2 *= k; y2 *= k;            return this;        }         Room turn(int times) {            for (int i = 0; i < times; i++) {                // 원점을 중심으로 왼쪽으로 90도: (x, y) → (-y, x). 돌린 뒤 왼쪽 아래·오른쪽 위를 다시 고른다                long nx1 = -y2, ny1 = x1, nx2 = -y1, ny2 = x2;                x1 = nx1; y1 = ny1; x2 = nx2; y2 = ny2;            }            return this;        }         Room copy() { return new Room(x1, y1, x2, y2); } // 새 객체: 앞으로 따로 움직인다         long area() { return (x2 - x1) * (y2 - y1); } // 4×10^12까지라 long         long overlap(Room o) {            long w = Math.min(x2, o.x2) - Math.max(x1, o.x1);            long h = Math.min(y2, o.y2) - Math.max(y1, o.y1);            return Math.max(0, w) * Math.max(0, h); // 한쪽이라도 0 이하면 겹치지 않는다        }         @Override        public String toString() { return x1 + " " + y1 + " " + x2 + " " + y2; }    }     public static void main(String[] args) throws IOException {        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));        int q = Integer.parseInt(br.readLine().trim());        Map<String, Room> rooms = new HashMap<>();        StringBuilder sb = new StringBuilder();        for (int i = 0; i < q; i++) {            String[] p = br.readLine().trim().split(" ");            switch (p[0]) {                case "new" -> rooms.put(p[1], new Room(Long.parseLong(p[2]), Long.parseLong(p[3]), Long.parseLong(p[4]), Long.parseLong(p[5])));                case "copy" -> rooms.put(p[1], rooms.get(p[2]).copy());                case "do" -> rooms.get(p[1]).move(Long.parseLong(p[2]), Long.parseLong(p[3])).scale(Long.parseLong(p[4])).turn(Integer.parseInt(p[5]));                case "area" -> sb.append(rooms.get(p[1]).area()).append('\n');                case "overlap" -> sb.append(rooms.get(p[1]).overlap(rooms.get(p[2]))).append('\n');                default -> sb.append(rooms.get(p[1])).append('\n');            }        }        System.out.print(sb);    }}
C#Main.cs · 76 lines
using System;using System.Collections.Generic;using System.Text; // 도면 위의 네모난 방: 왼쪽 아래 (X1, Y1), 오른쪽 위 (X2, Y2)// struct가 아니라 class: struct면 사전에서 꺼낼 때마다 복사본이 나와 바꾼 것이 사라진다class Room{    public long X1 { get; private set; }    public long Y1 { get; private set; }    public long X2 { get; private set; }    public long Y2 { get; private set; }     public Room(long x1, long y1, long x2, long y2) { X1 = x1; Y1 = y1; X2 = x2; Y2 = y2; }     // Move·Scale·Turn은 자기 자신(this)을 돌려준다: room.Move(...).Scale(...).Turn(...)처럼 이어 부를 수 있다    public Room Move(long dx, long dy)    {        X1 += dx; X2 += dx;        Y1 += dy; Y2 += dy;        return this;    }     public Room Scale(long k)    {        X1 *= k; Y1 *= k; X2 *= k; Y2 *= k;        return this;    }     public Room Turn(int times)    {        for (int i = 0; i < times; i++)        {            // 원점을 중심으로 왼쪽으로 90도: (x, y) → (-y, x). 돌린 뒤 왼쪽 아래·오른쪽 위를 다시 고른다            (X1, Y1, X2, Y2) = (-Y2, X1, -Y1, X2);        }        return this;    }     public Room Copy() => new Room(X1, Y1, X2, Y2); // 새 객체: 앞으로 따로 움직인다     public long Area() => (X2 - X1) * (Y2 - Y1); // 4×10^12까지라 long     public long Overlap(Room o)    {        long w = Math.Min(X2, o.X2) - Math.Max(X1, o.X1);        long h = Math.Min(Y2, o.Y2) - Math.Max(Y1, o.Y1);        return Math.Max(0, w) * Math.Max(0, h); // 한쪽이라도 0 이하면 겹치지 않는다    }     public override string ToString() => $"{X1} {Y1} {X2} {Y2}";} class Program{    static void Main()    {        int q = int.Parse(Console.ReadLine()!.Trim());        var rooms = new Dictionary<string, Room>();        var sb = new StringBuilder();        for (int i = 0; i < q; i++)        {            var p = Console.ReadLine()!.Trim().Split(' ');            switch (p[0])            {                case "new": rooms[p[1]] = new Room(long.Parse(p[2]), long.Parse(p[3]), long.Parse(p[4]), long.Parse(p[5])); break;                case "copy": rooms[p[1]] = rooms[p[2]].Copy(); break;                case "do": rooms[p[1]].Move(long.Parse(p[2]), long.Parse(p[3])).Scale(long.Parse(p[4])).Turn(int.Parse(p[5])); break;                case "area": sb.Append(rooms[p[1]].Area()).Append('\n'); break;                case "overlap": sb.Append(rooms[p[1]].Overlap(rooms[p[2]])).Append('\n'); break;                default: sb.Append(rooms[p[1]]).Append('\n'); break;            }        }        Console.Write(sb);    }}
C++main.cpp · 86 lines
#include <algorithm>#include <iostream>#include <string>#include <unordered_map> // 도면 위의 네모난 방: 왼쪽 아래 (x1, y1), 오른쪽 위 (x2, y2)class Room {public:    Room() = default;    Room(long long x1, long long y1, long long x2, long long y2) : x1_(x1), y1_(y1), x2_(x2), y2_(y2) {}     // move·scale·turn은 자기 자신의 참조(Room&)를 돌려준다: room.move(...).scale(...).turn(...)    // Room(값)으로 돌려주면 그다음 메서드는 복사본을 바꾸고, 원래 방에는 move만 남는다    Room &move(long long dx, long long dy) {        x1_ += dx, x2_ += dx;        y1_ += dy, y2_ += dy;        return *this;    }     Room &scale(long long k) {        x1_ *= k, y1_ *= k, x2_ *= k, y2_ *= k;        return *this;    }     Room &turn(int times) {        for (int i = 0; i < times; i++) {            // 원점을 중심으로 왼쪽으로 90도: (x, y) → (-y, x). 돌린 뒤 왼쪽 아래·오른쪽 위를 다시 고른다            long long nx1 = -y2_, ny1 = x1_, nx2 = -y1_, ny2 = x2_;            x1_ = nx1, y1_ = ny1, x2_ = nx2, y2_ = ny2;        }        return *this;    }     // 같은 자리의 새 방. 객체를 값으로 담는 C++에서는 복사 생성자가 하는 일과 같다    Room copy() const { return *this; }     long long area() const { return (x2_ - x1_) * (y2_ - y1_); } // 4×10^12까지라 long long     long long overlap(const Room &o) const {        long long w = std::min(x2_, o.x2_) - std::max(x1_, o.x1_);        long long h = std::min(y2_, o.y2_) - std::max(y1_, o.y1_);        return std::max(0LL, w) * std::max(0LL, h); // 한쪽이라도 0 이하면 겹치지 않는다    }     std::string str() const {        return std::to_string(x1_) + " " + std::to_string(y1_) + " " + std::to_string(x2_) + " " + std::to_string(y2_);    } private:    long long x1_ = 0, y1_ = 0, x2_ = 0, y2_ = 0;}; int main() {    std::ios::sync_with_stdio(false);    std::cin.tie(nullptr);    int q;    std::cin >> q;    // 사전에 객체를 값으로 담는다: rooms[b] = rooms[a]는 복사라서 copy() 메서드가 따로 없어도 둘이 따로 움직인다    std::unordered_map<std::string, Room> rooms;    for (int i = 0; i < q; i++) {        std::string cmd, a;        std::cin >> cmd >> a;        if (cmd == "new") {            long long x1, y1, x2, y2;            std::cin >> x1 >> y1 >> x2 >> y2;            rooms[a] = Room(x1, y1, x2, y2);        } else if (cmd == "copy") {            std::string b;            std::cin >> b;            rooms[a] = rooms[b].copy(); // 사전에 값으로 담으니 rooms[a] = rooms[b]만 써도 복사다        } else if (cmd == "do") {            long long dx, dy, k;            int t;            std::cin >> dx >> dy >> k >> t;            rooms[a].move(dx, dy).scale(k).turn(t);        } else if (cmd == "area") {            std::cout << rooms[a].area() << '\n';        } else if (cmd == "overlap") {            std::string b;            std::cin >> b;            std::cout << rooms[a].overlap(rooms[b]) << '\n';        } else {            std::cout << rooms[a].str() << '\n';        }    }}