paizaラーニングレベルアップ問題集の「長テーブルのうなぎ屋」をオブジェクト指向でやってみた

paiza×Qiita記事投稿キャンペーンということで、paizaラーニングレベルアップ問題集の[長テーブルのうなぎ屋](https://paiza.jp/works/mondai/b_rank_skillcheck_sample/long-table)をオブジェクト指向でやってみました。対象は[コードモンスター大図鑑](https://paiza.jp/code_monster)で対応している9言語です。

2024/08/25更新
Javascriptのコードを修正いたしました。
- - -
###### 方針
- 「長テーブルのうなぎ屋」クラスを作成
- 座席数$N$をコンストラクタに渡す
- $M$個のクエリ$(a_i, b_i)$（$1\le i\le M$）をメソッドに渡す
:::note info
座席番号$N$の座席を座席番号$0$の座席とみなします。
:::

- - -
###### PHP
```php
<?php
	// 長テーブルのうなぎ屋クラス
	class LongTable {
		// 座席数
		private $nSeats;

		// 座席の状態
		private $seats;

		// 座席に着席出来ている人数
		private $nCustomers;

		// 座席に着席出来ている人数を返します。
		public function getNCustomers()
		{
			return $this->nCustomers;
		}
		
		// コンストラクタ
		public function __construct($n)
		{
			// 座席数
			$this->nSeats = $n;
	
			// 座席の状態をfalse（空席）で初期化
			$this->seats = array_fill(0, $n, false);
	
			// 座席に着席出来ている人数を0で初期化
			$this->nCustomers = 0;
		}
		
		// 座席番号bの座席を始点として、そこから時計回りにa個分の座席に座ろうとします。
		public function sit($a, $b) {
			//連続するa個の座席に一斉に座ろうとします。
			for ($i = 0; $i < $a; $i++) {
				// いずれか一つでも既に先客に座られている座席があった場合、
				// 一人も座らずにグループ全員で怒って帰ってしまいます。
				if ($this->seats[($b + $i) % $this->nSeats]) {
					return;
				}
			}
			// 座席番号bの座席を始点として、
			// そこから時計回りにa個分の座席に座ります。
			for ($i = 0; $i < $a; $i++) {
				$this->seats[($b + $i) % $this->nSeats] = true;
			}
			
			// 座席に着席出来ている人数を更新します。
			$this->nCustomers += $a;
		}
	}
	
	// 1行目にはn(座席数)とm(グループ数)が半角スペース区切りで入力されます。
	[$n, $m] = explode(" ", fgets(STDIN));

	// 長テーブルのうなぎ屋クラスをインスタンス化します。
	$longTable = new LongTable($n);
	
	for ($i = 0; $i < $m; $i++) {
		// 2個の整数a(グループの人数)とb(着席開始座席番号)が
		// 半角スペース区切りで入力されます。
		[$a, $b] = explode(" ", fgets(STDIN));

		// 座席番号bの座席を始点として、
		// そこから時計回りにa個分の座席に座ろうとします。
		$longTable->sit($a, $b);
	}

	// 最後のグループが座りに来た後、
	// 無事に座席に着席出来ている人数を出力します。
	echo $longTable->getNCustomers()."\n";
?>
```
- - -
###### Ruby
```rb
# 長テーブルのうなぎ屋クラス
class LongTable
	# コンストラクタ
	def initialize(n)
		# 座席数
		@n_seats = n

		# 座席の状態をfalse（空席）で初期化
		@seats = Array.new(n, false)

		# 座席に着席出来ている人数を0で初期化
		@n_customers = 0
	end

	# 座席に着席出来ている人数を返します。
	def get_n_customers()
		return @n_customers
	end

	# 座席番号bの座席を始点として、そこから時計回りにa個分の座席に座ろうとします。
	def sit(a, b)
		#連続するa個の座席に一斉に座ろうとします。
		# いずれか一つでも既に先客に座られている座席があった場合、
		# 一人も座らずにグループ全員で怒って帰ってしまいます。
		if a.times.none?{|i| @seats[(b + i) % @n_seats]}
			# 座席番号bの座席を始点として、
			# そこから時計回りにa個分の座席に座ります。
			a.times do |i| 
				@seats[(b + i) % @n_seats] = true
			end
	
			# 座席に着席出来ている人数を更新します。
			@n_customers += a
		end
	end
end

# 1行目にはn(座席数)とm(グループ数)が半角スペース区切りで入力されます。
n, m = gets.split.map(&:to_i)

# 長テーブルのうなぎ屋クラスをインスタンス化します。
long_table = LongTable.new(n)

m.times do
	# 2個の整数a(グループの人数)とb(着席開始座席番号)が
	# 半角スペース区切りで入力されます。
	a, b = gets.split.map(&:to_i)

	# 座席番号bの座席を始点として、
	# そこから時計回りにa個分の座席に座ろうとします。
	long_table.sit(a, b)
end

# 最後のグループが座りに来た後、
# 無事に座席に着席出来ている人数を出力します。
p long_table.get_n_customers()
```
- - -
###### Java	
```java
import java.util.*;
import java.util.stream.IntStream;

// 長テーブルのうなぎ屋クラス
class LongTable {
	// 座席数
	private int nSeats;

	// 座席の状態
	private boolean[] seats;

	// 座席に着席出来ている人数
	private int nCustomers;

	// 座席に着席出来ている人数を返します。
	public int getNCustomers() {
		return nCustomers;
	}

	// コンストラクタ
	public LongTable(int n) {
		// 座席数
		nSeats = n;

		// 座席の状態をfalse（空席）で初期化
		seats = new boolean[n];

		// 座席に着席出来ている人数を0で初期化
		nCustomers = 0;
	}

	// 座席番号bの座席を始点として、そこから時計回りにa個分の座席に座ろうとします。
	public void sit(int a, int b) {
		// 連続するa個の座席に一斉に座ろうとします。
		// いずれか一つでも既に先客に座られている座席があった場合、
		// 一人も座らずにグループ全員で怒って帰ってしまいます。
		if (IntStream.range(0, a).noneMatch(i -> seats[(b + i) % nSeats])) {
			// 座席番号bの座席を始点として、
			// そこから時計回りにa個分の座席に座ります。
			for (int i = 0; i < a; i++) {
				seats[(b + i) % nSeats] = true;
			}
			
			// 座席に着席出来ている人数を更新します。
			nCustomers += a;
		}
	}
}
	
public class Main {
	public static void main(String[] args) {
		Scanner sc = new Scanner(System.in);
		// 1行目にはn(座席数)とm(グループ数)が半角スペース区切りで入力されます。
		int n = sc.nextInt();
		int m = sc.nextInt();
	
		// 長テーブルのうなぎ屋クラスをインスタンス化します。
		LongTable longTable = new LongTable(n);
		
		for (int i = 0; i < m; i++) {
			// 2個の整数a(グループの人数)とb(着席開始座席番号)が
			// 半角スペース区切りで入力されます。
			int a = sc.nextInt();
			int b = sc.nextInt();
	
			// 座席番号bの座席を始点として、
			// そこから時計回りにa個分の座席に座ろうとします。
			longTable.sit(a, b);
		}
		sc.close();

		// 最後のグループが座りに来た後、
		// 無事に座席に着席出来ている人数を出力します。
		System.out.println(longTable.getNCustomers());
	}
}
```
- - -
###### Python
```py
# 長テーブルのうなぎ屋クラス
class LongTable:
	# コンストラクタ
	def __init__(self, n):
		# 座席数
		self.n_seats = n

		# 座席の状態をfalse（空席）で初期化
		self.seats = [False for _ in range(n)]

		# 座席に着席出来ている人数を0で初期化
		self.n_customers = 0

	# 座席に着席出来ている人数を返します。
	def get_n_customers(self):
		return self.n_customers

	# 座席番号bの座席を始点として、そこから時計回りにa個分の座席に座ろうとします。
	def sit(self, a, b):
		# 連続するa個の座席に一斉に座ろうとします。
		if any(self.seats[(b + i) % self.n_seats] for i in range(a)):
			# いずれか一つでも既に先客に座られている座席があった場合、
			# 一人も座らずにグループ全員で怒って帰ってしまいます。
			return

		# 座席番号bの座席を始点として、
		# そこから時計回りにa個分の座席に座ります。
		for i in range(a):
			self.seats[(b + i) % self.n_seats] = True

		# 座席に着席出来ている人数を更新します。
		self.n_customers += a


# 1行目にはn(座席数)とm(グループ数)が半角スペース区切りで入力されます。
n, m = map(int, input().split())

# 長テーブルのうなぎ屋クラスをインスタンス化します。
long_table = LongTable(n)

for _ in range(m):
	# 2個の整数a(グループの人数)とb(着席開始座席番号)が
	# 半角スペース区切りで入力されます。
	a, b = map(int, input().split())

	# 座席番号bの座席を始点として、
	# そこから時計回りにa個分の座席に座ろうとします。
	long_table.sit(a, b)

# 最後のグループが座りに来た後、
# 無事に座席に着席出来ている人数を出力します。
print(long_table.get_n_customers())
```
- - -
###### C言語
```c
#include <stdio.h>
#include <stdbool.h>
#include <string.h>

// 長テーブルのうなぎ屋構造体
typedef struct LongTable {
	// 座席数
	int nSeats;

	// 座席の状態
	bool *seats;

	// 座席に着席出来ている人数
	int nCustomers;
} LongTable;

// 座席番号bの座席を始点として、そこから時計回りにa個分の座席に座ろうとします。
void sit(LongTable *lngtbl, int a, int b) {
	//連続するa個の座席に一斉に座ろうとします。
	for (int i = 0; i < a; i++) {
		// いずれか一つでも既に先客に座られている座席があった場合、
		// 一人も座らずにグループ全員で怒って帰ってしまいます。
		if (lngtbl->seats[(b + i) % lngtbl->nSeats]) {
			return;
		}
	}
	// 座席番号bの座席を始点として、
	// そこから時計回りにa個分の座席に座ります。
	for (int i = 0; i < a; i++) {
		lngtbl->seats[(b + i) % lngtbl->nSeats] = true;
	}

	// 座席に着席出来ている人数を更新します。
	lngtbl->nCustomers += a;
}

int main() {
	// 1行目にはn(座席数)とm(グループ数)が半角スペース区切りで入力されます。
	int n, m;
	scanf("%d %d", &n, &m);

	// 長テーブルのうなぎ屋クラスを“インスタンス化”します。
	bool seats[n];
	memset(seats, false, sizeof(seats));
	LongTable long_table = { n, seats, 0 };

	for (int i = 0; i < m; i++) {
		// 2個の整数a(グループの人数)とb(着席開始座席番号)が
		// 半角スペース区切りで入力されます。
		int a, b;
		scanf("%d %d", &a, &b);

		// 座席番号bの座席を始点として、
		// そこから時計回りにa個分の座席に座ろうとします。
		sit(&long_table, a, b);
	}

	// 最後のグループが座りに来た後、
	// 無事に座席に着席出来ている人数を出力します。
	printf("%d\n", long_table.nCustomers);
}
```
- - -
###### C#
```cs
using System;

// 長テーブルのうなぎ屋クラス
class LongTable {
	// 座席数
	private int nSeats;

	// 座席の状態
	private bool[] seats;

	// 座席に着席出来ている人数
	private int nCustomers;

	// 座席に着席出来ている人数を返します。
	public int NCustomers {
		get{ return nCustomers; }
	}

	// コンストラクタ
	public LongTable(int n) {
		// 座席数
		nSeats = n;

		// 座席の状態をfalse（空席）で初期化
		seats = new bool[n];

		// 座席に着席出来ている人数を0で初期化
		nCustomers = 0;
	}

	// 座席番号bの座席を始点として、そこから時計回りにa個分の座席に座ろうとします。
	public void Sit(int a, int b) {
		// 連続するa個の座席に一斉に座ろうとします。
		for (int i = 0; i < a; i++) {
			// いずれか一つでも既に先客に座られている座席があった場合、
			// 一人も座らずにグループ全員で怒って帰ってしまいます。
			if (seats[(b + i) % nSeats]) {
				return;
			}
		}
		// 座席番号bの座席を始点として、
		// そこから時計回りにa個分の座席に座ります。
		for (int i = 0; i < a; i++) {
			seats[(b + i) % nSeats] = true;
		}
		
		// 座席に着席出来ている人数を更新します。
		nCustomers += a;
	}
}
	
class Program {
	static void Main() {
		// 1行目にはn(座席数)とm(グループ数)が半角スペース区切りで入力されます。
		int[] nm = Array.ConvertAll(Console.ReadLine().Split(), int.Parse);
		int n = nm[0];
		int m = nm[1];
	
		// 長テーブルのうなぎ屋クラスをインスタンス化します。
		LongTable longTable = new LongTable(n);
		
		for (int i = 0; i < m; i++) {
			// 2個の整数a(グループの人数)とb(着席開始座席番号)が
			// 半角スペース区切りで入力されます。
			int[] ab = Array.ConvertAll(Console.ReadLine().Split(), int.Parse);
			int a = ab[0];
			int b = ab[1];
	
			// 座席番号bの座席を始点として、
			// そこから時計回りにa個分の座席に座ろうとします。
			longTable.Sit(a, b);
		}

		// 最後のグループが座りに来た後、
		// 無事に座席に着席出来ている人数を出力します。
		Console.WriteLine(longTable.NCustomers);
	}
}
```
- - -
###### Javascript
2024/08/25 `parseInt`を`Nnumber`に修正
```js
// 長テーブルのうなぎ屋クラス
class LongTable {
	// 座席数
	nSeats = 0;

	// 座席の状態
	seats = null;

	// 座席に着席出来ている人数
	nCustomers = 0;

	// 座席に着席出来ている人数を返します。
	getNCustomers() {
		return this.nCustomers;
	}

	// コンストラクタ
	constructor(n) {
		// 座席数
		this.nSeats = n;

		// 座席の状態をfalse（空席）で初期化
		this.seats = new Array(n).fill(false);

		// 座席に着席出来ている人数を0で初期化
		this.nCustomers = 0;
	}

	// 座席番号bの座席を始点として、そこから時計回りにa個分の座席に座ろうとします。
	sit(a, b) {
		// 連続するa個の座席に一斉に座ろうとします。
		for (var i = 0; i < a; i++) {
			// いずれか一つでも既に先客に座られている座席があった場合、
			// 一人も座らずにグループ全員で怒って帰ってしまいます。
			if (this.seats[(b + i) % this.nSeats]) {
				return;
			}
		}
		// 座席番号bの座席を始点として、
		// そこから時計回りにa個分の座席に座ります。
		for (i = 0; i < a; i++) {
			this.seats[(b + i) % this.nSeats] = true;
		}

		// 座席に着席出来ている人数を更新します。
		this.nCustomers += a;
	}
}


const lines = require("fs").readFileSync("/dev/stdin", "utf8").split("\n");

// 1行目にはn(座席数)とm(グループ数)が半角スペース区切りで入力されます。
// const [n, m] = lines[0].split(" ").map(x => parseInt(x, 10));
const [n, m] = lines[0].split(" ").map(Number);

// 長テーブルのうなぎ屋クラスをインスタンス化します。
const longTable = new LongTable(n);

for (var i = 1; i <= m; i++) {
	// 2個の整数a(グループの人数)とb(着席開始座席番号)が
	// 半角スペース区切りで入力されます。
	// let [a, b] = lines[i].split(" ").map(x => parseInt(x, 10));
    let [a, b] = lines[i].split(" ").map(Number);

	// 座席番号bの座席を始点として、
	// そこから時計回りにa個分の座席に座ろうとします。
	longTable.sit(a, b);
}

// 最後のグループが座りに来た後、
// 無事に座席に着席出来ている人数を出力します。
console.log(longTable.getNCustomers());
```
- - -
###### C++
```cpp
#include <iostream>
#include <vector>
using namespace std;

// 長テーブルのうなぎ屋クラス
class LongTable {
	// 座席数
	int nSeats;

	// 座席の状態
	vector<bool> seats;

	// 座席に着席出来ている人数
	int nCustomers;

public:
	// 座席に着席出来ている人数を返します。
	int getNCustomers() {
		return nCustomers;
	}

	// コンストラクタ
	LongTable(int n) :
			nSeats(n) {
		// 座席の状態をfalse（空席）で初期化
		seats.resize(n, false);

		// 座席に着席出来ている人数を0で初期化
		nCustomers = 0;
	}

	// 座席番号bの座席を始点として、そこから時計回りにa個分の座席に座ろうとします。
	void sit(int a, int b) {
		// 連続するa個の座席に一斉に座ろうとします。
		for (int i = 0; i < a; i++) {
			// いずれか一つでも既に先客に座られている座席があった場合、
			// 一人も座らずにグループ全員で怒って帰ってしまいます。
			if (seats[(b + i) % nSeats]) {
				return;
			}
		}

		// 座席番号bの座席を始点として、
		// そこから時計回りにa個分の座席に座ります。
		for (int i = 0; i < a; i++) {
			seats[(b + i) % nSeats] = true;
		}

		// 座席に着席出来ている人数を更新します。
		nCustomers += a;
	}
};

int main() {
	// 1行目にはn(座席数)とm(グループ数)が半角スペース区切りで入力されます。
	int n, m;
	cin >> n >> m;

	// 長テーブルのうなぎ屋クラスをインスタンス化します。
	LongTable long_table(n);

	for (int i = 0; i < m; i++) {
		// 2個の整数a(グループの人数)とb(着席開始座席番号)が
		// 半角スペース区切りで入力されます。
		int a, b;
		cin >> a >> b;

		// 座席番号bの座席を始点として、
		// そこから時計回りにa個分の座席に座ろうとします。
		long_table.sit(a, b);
	}

	// 最後のグループが座りに来た後、
	// 無事に座席に着席出来ている人数を出力します。
	cout << long_table.getNCustomers() << endl;
}
```
- - -
###### Kotlin
```kotlin
import java.util.*

// 長テーブルのうなぎ屋クラス
class LongTable {
	// 座席数
	var nSeats: Int

	// 座席の状態
	var seats: Array<Boolean>

	// 座席に着席出来ている人数
	var nCustomers: Int
		get() {
			return field
		}

	// コンストラクタ
	constructor(n: Int) {
		// 座席数
		nSeats = n

		// 座席の状態をfalse（空席）で初期化
		seats = Array(n){ false }

		// 座席に着席出来ている人数を0で初期化
		nCustomers = 0
	}

	// 座席番号bの座席を始点として、そこから時計回りにa個分の座席に座ろうとします。
	fun sit(a: Int, b: Int) {
		// 連続するa個の座席に一斉に座ろうとします。
		// いずれか一つでも既に先客に座られている座席があった場合、
		// 一人も座らずにグループ全員で怒って帰ってしまいます。
		if ((0 until a).none{ i -> seats[(b + i) % nSeats]}) {
			// 座席番号bの座席を始点として、
			// そこから時計回りにa個分の座席に座ります。
			for (i in 0 until a) {
				seats[(b + i) % nSeats] = true
			}
			
			// 座席に着席出来ている人数を更新します。
			nCustomers += a
		}
	}
}
	

fun main() {
	val sc = Scanner(System.`in`)
	// 1行目にはn(座席数)とm(グループ数)が半角スペース区切りで入力されます。
	val n = sc.nextInt()
	val m = sc.nextInt()

	// 長テーブルのうなぎ屋クラスをインスタンス化します。
	val longTable = LongTable(n)
	
	for (i in 1..m) {
		// 2個の整数a(グループの人数)とb(着席開始座席番号)が
		// 半角スペース区切りで入力されます。
		var a = sc.nextInt()
		var b = sc.nextInt()

		// 座席番号bの座席を始点として、
		// そこから時計回りにa個分の座席に座ろうとします。
		longTable.sit(a, b)
	}
	sc.close()
	
	// 最後のグループが座りに来た後、
	// 無事に座席に着席出来ている人数を出力します。
	println(longTable.nCustomers)
}
```