はてなキーワード: Nameとは
メタファーのシステム&デザインでロマサガ2 リメイク『ロマンシング サガ2 リベンジオブザセブン』が出てくてりゃ、日本のゲームやJRPGの未来は明るかったのにな
『アトラス(とセガ)』と『スクエニ』、どうして差がついたのか・・・慢心、環境の違い・・・・・・と思いつつ、
『メタファー:リファンタジオ(Metaphor: ReFantazio) 』の1周目をクリアしたので、前回(https://anond.hatelabo.jp/20241020022808#)の感想の続き
一般的なコマンド型のJRPGなら、緊迫した状況でも以下のことができる
しかし、ロマサガ2には年代ジャンプがあるため、無計画にこういった行動を続けると、状況が変わり取り返しがつかなくなることも(放置した場所が滅ぶなど)
これが、メタファーの『カレンダーシステム』では更にシビアになっている
ちなみに、メタファーのカレンダーシステムは以下の仕様で、ひとつひとつの行動に非常に緊張感がある。
『これだよこれ!本当にやりたかったロマサガ2のリメイクはよぉ!!!』ときゃっきゃ楽しんでいたのだが、
異常にそそっかしいワイ氏、 期待を裏切らず や ら か す !!!!!!!!
ファーーーーーーーーーーーwwwww
その瞬間は、『へへ、やっちまったぜ・・・』と思いつつも、まぁノーマルの難易度なら魔職でゴリ押しできるでしょとタカをくくっていた
ところが、重要そうな依頼イベントをクリアする時間が半日分足りない!!!!(クリアした後に依頼が新たに追加されて日付計算が狂うパターン)
どうやら最序盤の王の資質上げで無駄な行動をしていた模様・・・
い、いやでも、イベント取り逃がしても、エンディングには影響しない要素かも知れんし?と、おそるおそるネットの攻略情報を特別解禁したところ、
(自分で試行錯誤せず、攻略情報見ながらゲームをプレイするのは好きじゃないので、基本的にクリア前は攻略情報を封印している)
テテテテテテテテテ・テーーーン
(ビーバップ・ハイスクール 高校生極楽伝説のゲームオーバーのBGM https://www.youtube.com/watch?v=5AKM0fHc2Ps&t=48s)
たまたま上書きしていないデータもあったものの、それはメタファーのカレンダー上で30日も前のデータ
リアルの雑用対応中ゲーム付けたまま放置した時間や、プレイ中に寝落ちして放置した時間も含まれているが、約20時間くらいの巻き戻しだ
一晩考えたが、エンディング差分回収を2周目に回したり、動画で差分回収済ませると熱が冷めそうなので、20時間前のデータからやり直すことにした・・・
前回(https://anond.hatelabo.jp/20241020022808#)の感想にも書いた通り、序盤で適当にクラスやスキルを取ったせいで、
上位職のクラスを取得するためのポイントがどう考えても足りなかった
地形が楽で高額アイテム売れる洞窟でポイント稼ぎを 数時間 して挽回したのだが、数時間をもう一度やり直すことになり、かなりきつかった・・・
まぁおそらく、ワイと似たような失敗をしたんじゃないかなぁ・・・って思います😅
カレンダーシステム自体は緊張感があってとても面白いので、今後も是非続けて欲しい
だけど、うっかりセーブミスをする愚か者のために、個別データセーブに加えて、定期セーブシステムもあるとめっちゃ助かる・・・
例えば、個別データセーブとは別に、週の始めに『定期セーブ』を自動でシステム作成、
最大で3週間前の週はじめまで戻れるとかあるとめっちゃ助かるので、ゲーム中の快適を追求する開発陣のみなさま何卒・・・🙏
ワイが終盤の展開に入り込めなかった一番の理由は、属性過多で矛盾だらけのラスボスのルイが好みじゃなかったからやね・・・
結論だけ書けば、貴族枠の女性軍人だったら、矛盾も魅力に映ったかなぁって思う
順を追って書くなら、
特権階級をぶち壊す象徴は『叩き上げ』じゃないとダメなんだよ!!!!!で譲らないにしても(過酷な現実と日々向き合って、あんな抽象的な思想や混沌への憧れを持たないと思うが)、
ルイには、おもしれー男 要素まで盛り込まれている。たとえば、
などなど、確信犯的におもしれー描写が続く。でも、ルイがバットマン のジョーカーのように混沌と無秩序そのものを楽しんでいる風でもないんだよね
そもそもルイのような叩き上げの軍人にとって無秩序や混沌といった要素は本来、相性が悪いはずだし、ジョーカーみたいな気質のヤツが真の目的を隠して縦社会で勝ち上がっていけるイメージがわかない
属性過多はこれだけでは終わらず、ルイには『絶対的な力の象徴で信奉者』という設定もあり、常に落ち着き払っていて感情を露わにすることがない
そのため、突然叫び出したり、会話を一方的に打ち切るようなこともなく、紳士的で不気味さがないんだよね
キレどこがわからない怪異やクトゥルフの上位存在が不気味で怖いように、対話が成立しないキャラのほうが恐怖感はあるよね
まぁワイとしては、ルイがあまりにてんこ盛り属性で一貫性を欠いているため(現役軍人、女性的な外見、理想主義者、エキセントリックな行動、紳士的な態度など、相反する要素が詰め込まれすぎ)、シリアスさを感じなかったし、最終盤はただただポカーンとした
せめて、ルイが上位貴族という設定であれば、独自の行動や破壊的な思想、突飛な振る舞いも『特権的な気まぐれ』として説明がつき、てんこ盛り属性でもまとまりのあるキャラクターになった気がする
あと、女性的な外見ではなく本当にお嬢さんだったら、賭ケグルイ の 桃喰綺羅莉 のように、『怖さ(狂気)』と『おもしれー』を自然に両立できたと思う
桃喰綺羅莉は、冷酷な暴君でありながら優雅さを保ち、狂気と不気味さが同居しているキャラだ
危険分子を放置したり、突飛な行動をとって自らの命を掛けたり、自らが支配していた学園のシステムやお気に入りの人物を壊されても『失うから面白い』と笑っており、
混沌を楽しむおもしれー女としても成立している
貴族的な立場からくる特権と傲慢さと少女の無邪気さがあってこそ、エキセントリックな行動も説得力を持つと思うんです
最終盤のストーリーは若干気になる点があって、これたぶん、個人的な好みではない違和感だと思うので書いとく
→ 人の心、どこかに置き忘れた?と思うが、理性的で高い志を持つ人物の主張としてギリわかる
→ 復讐が無益なのはそれはそうだし、負の連鎖を断ち切って未来だけ見つめられるなら大変素晴らしいことだ
→ じゃあ、不安を持ち主に返そうとするルイ討たずに、放っておいてもよかったんじゃね?
→ 『溜まった不安を一気に返すと狂化して化け物になるんだよ!』なら、ルイに交渉して少しずつ持ち主に返せばよかったのでは?
わざわざ冷静沈着で会話出来るヤツにしたんだし
というか、ルイがあくまで一気に不安を返して化け物化させることにこだわっているなら、結局、世の中への復讐心が動機ってことでいいの?
あと、やっぱりジュナだよなぁ
パーティメンバーのみんな命を掛けることになった納得感ある理由があるのに、ジュナだけ自ら諜報活動(当然命のやり取りがある)を始めた理由が、
歌の真剣み?深み?を持たせるためとか言う理由なのだが、後半で『歌だけでいいのかしら』、『歌だけじゃ寂しい』とか言い出す
どういうことなの・・・?せめて歌キチだけは貫いてよ、救われた命・拾った命を自らわざわざ張ってるんだし
あと、三下に対する態度が酷かったのに、パーティに加入したあと個別イベント等では、善人通り越して聖人モード
あんなに心広いなら、三下永井豪眉にも、もう少しまともな態度は取れなかったもんなぁ・・・
終盤の展開とルイとジュナといくつかの事柄に対する態度は気になりつつも、ゲームとしてはすこぶる快適で、派手で挑戦的で面白くて、1000000点なので言うこと無いっす
(しいていうなら、うっかり上書きセーブしちゃう愚か者のために、個別データセーブとは別に、週の始めに『定期セーブ』を自動でシステム作成、
最大で3週間前の週はじめまで戻れるとかあるとめっちゃ助かる)
『幻想は無力なんかじゃない』もそうだねって思うね、あと考えるきっかけを作ろうって野心的な姿勢は感動した
「支部政党交付金支給通知書」には「この度の選挙に関して、必要な資金を選挙運動費用に充てる場合、貴支部から候補者への寄附として支出してください」と書いてあるのに、「選挙に使うことも全くない」とは、嘘も強弁すれば真実になるというトランプ・安倍方式?
https://pbs.twimg.com/media/GahdJQAbEAIpHCq?format=jpg&name=4096x4096
https://news.yahoo.co.jp/articles/34781b475c27f5eb47e8b73f6e691226c295e93d
首相は「この厳しい(情勢の)中、自民党の公約、政策を分かってもらいたいとの思いで支部に(活動費を)出している。選挙に使うことも全くない」と説明した。
https://www.geonames.org から取れる、人口500人以上の都市の名前に限定すると、
Santa Maria Magdalena Cahuacan
import logging import tempfile import zipfile from collections import Counter import httpx FILE_NAME_BASE = 'cities500' GEONAME_FIELDS = ( 'geoname_id', 'name', 'ascii_name', 'alternate_names', 'latitude', 'longitude', 'feature_class', 'feature_code', 'country_code', 'cc2', 'admin1_code', 'admin2_code', 'admin3_code', 'admin4_code', 'population', 'elevation', 'dem', 'timezone', 'modification_date', ) def retrieve_cities(): """Retrieve city names from a remote server.""" response = httpx.get(f'https://download.geonames.org/export/dump/{FILE_NAME_BASE}.zip') response.raise_for_status() tmpdir = tempfile.TemporaryDirectory() with open(tmpdir.name + f'/{FILE_NAME_BASE}.zip', 'wb') as f: f.write(response.content) with zipfile.ZipFile(tmpdir.name + f'/{FILE_NAME_BASE}.zip', 'r') as z: z.extractall(tmpdir.name) with open(tmpdir.name + f'/{FILE_NAME_BASE}.txt', 'r') as f: for line in f: yield line.split('\t') def count_characters(to_check='ascii_name', filter_func=lambda _: True): """Count characters in city names.""" cities = {} for city_fields in retrieve_cities(): city = dict(zip(GEONAME_FIELDS, city_fields)) if not filter_func(city): continue counter = Counter() for c in city[to_check]: counter[c] += 1 cities[city['geoname_id']] = {'characters': counter, 'city': city} return cities def count_chars_of_city_names(cities, char=None): """Find the city with the most occurrences of a given character.""" cities_by_char_count = {} max_count = 0 max_count_char = None for city_id, data in cities.items(): if 'characters' not in data or not data['characters']: logging.debug(f'No characters found for city {city_id}', data) continue count = 0 if char and char in data['characters']: count = data['characters'][char] cities_by_char_count.setdefault(count, []).append(data) elif char is None: most_common = data['characters'].most_common(1)[0] char, count = most_common cities_by_char_count.setdefault(count, []).append(data) if count > max_count: max_count = count max_count_char = char cities_by_char_count.setdefault(count, []).append(data) return cities_by_char_count.get(max_count, []), max_count_char def not_contain_invalid_chars(city): return ( '(' not in city.get('ascii_name', '') and '/' not in city.get('ascii_name', '') ) def main(): cities = count_characters(filter_func=not_contain_invalid_chars) for char in 'abcdefghijklmnopqrstuvwxyz': cities_counted, char = count_chars_of_city_names(cities, char) max_count = cities_counted[0]['characters'][char] print(f'The character "{char}" appears the most ({max_count} times) in the following cities:') for city in cities_counted: print("\t", city['city']['ascii_name']) if __name__ == "__main__": main()
1. NAMM 2013での “What’s My Name?” のパフォーマンス: MiyaviがTaylorギターを使用し、独自のスラップスタイルを披露しています 。
2. Slap The Beat DVD / ギターチュートリアル: Miyaviのギタープレイに関するチュートリアルで、彼のスラップ奏法やテクニックが解説されています 。
3. Billboard LIVE 2020での “What’s My Name?” アコースティックバージョン: Miyaviがアコースティックセットで演奏している様子が見られ、カポの使用も確認できます 。
切腹はどこでみれるの?
羽生結弦は、野球部にイジメられた逆境から立ち直って見返した努力家だから、そんなに嫌いになれないんだよな。東日本大震災被災地で火事場泥棒した野球部と違って、羽生は寄付やボランティアで励ましてたし
まあ結婚は失敗したけど、それはそれで彼も完璧じゃない所があるってことだ#羽生結弦 https://t.co/tYIFR5eokT pic.twitter.com/1TVZfB9XrT— いろどり豊 (@KK0TrEXg0RcXgOe) February 23, 2024
https://pbs.twimg.com/media/GHCimmyasAIdbzR?format=jpg&name=small
https://type.jp/et/feature/26796/
この発言にもあるように「コードを綺麗にする=読みやすくする」ってことだと勘違いしてる
コードを綺麗にするのは「バグを少なくする」ためであって読み手のためじゃない
グローバルに一文字変数を使って困るのは「どこでそれを触ってるか分からないから」であって「読みにくいから」ではない(まぁ読みにくいけど)
特に昔だとLintもないし変数の参照先を探すのはgrepぐらいしかなくて
$iとかだと$iiもひっかかるし$iの後ろにスペースがあったり無かったりするともう探すのは不可能に近くなる
それでも動いているなら最悪問題無いんだがバグの修正時にめちゃくちゃ困って
「作り直すしか無いな」
ってなるのでビジネス的にも大きな影響が出る
「どんなコードでも動くコードを作るのが正しい」「done is better than perfect(完璧を目指すよりも、まずは終わらせることが重要) 」のスタンスが効率的だろうなぁ、、と思うおいらです。
これも元の言葉の意味を曲解していて、「終わらせることが重要」というのはバグがあって良いわけじゃない
例えばログインボタンを実装したときに、ユーザー名とパスワードに何を入れてもログインできる状態にするのも「終わらせること」だし
ただこのままリリースできるわけではないし、プロダクトとしては「終わっていない」
パスワードを平文で保存して実装するのも「終わらせること」ではあるけれどそのままリリースしていいわけではないし
下手に動いてしまうとそのままリリースされたりもするのでよりタチが悪い
この言葉の重要なのは「better than perfect」の方であって「done」の方ではない
全てを完璧にする必要は無い(し、そもそも完璧は定義できない)ので「perfectでなくていいよ」というだけ
バグがあったり不十分だったりセキュリティ不備があって良いわけではない
毎日論理構成の中に浸ってる人は、推理小説は向いてるかもしれないですね。初期にちょろっと設定したグローバル変数が、最終的な結果に大きく影響してくるとか、「ここで使われてるのかー」みたいな感慨とか。
残念ながら「ああ、まともなコードしか読んできてないんだな」としか思えない
例えば「ユーザーの名前と住所は設定できてるから、性別を設定できるようにして」という依頼があって
コードを確認してみるとuser1, user2, user3という変数が100個用意されていて、user1.name = 'hoge', user2.name = 'gaga' って感じで100行書いてあって、更に住所で100行あって、性別も同じように100行追加しろっていうコードを読んだことが無いんだろう
そしてそのコードのどこかで住所設定が間違えているから確認しないといけないような作業をしてないんだと思う
小説で言うと同じ文章が100ページ続いていて、その中のどこかの漢字が違っていて、そいつが犯人、みたいな推理小説、面白いか?
他にも足したり引いたりこねくり回された変数値が最後に定数値で上書きされてたり、UserのオブジェクトがいきなりWeatherのオブジェクトに置き換えられていて、name属性に晴れとか雨のデータが入ってたりしたことがないんだと思う
汚いコードは伏線を回収しないし最終的に犯人も分からないし無駄に長いので推理小説には全く向いてない
で、やっぱりこういう汚いコードの問題は「バグが混入しやすいかどうか」であって「読みやすいかどうか」ではない
下手するとuserオブジェクトを100行ずつ書いてくれてる方が読みやすさはあるかもしれないが
「user36だけ住所が設定されていない」といったバグが混入し得るし、それを確認するのに多大な労力を必要とする
人間は誰もが間違いを犯すので誰もがバグを混入させる危険性があるんだけれど
その危険性は最大限まで下げるように努力するべきだし、インシデントを引き起こすことでビジネス的なインパクトも大きい
In today’s fast-paced travel industry, small businesses need to stay nimble and connected. One way to do this is by tapping into flight APIs. These powerful tools can elevate your travel booking system, making it easier to offer competitive flight options. So, what’s the the best flight API for your small travel business? Let’s explore some of the top choices out there.
Understanding Flight APIs: What Are They?
At their core, flight APIs allow access to flight data. Think of them as a bridge connecting users to various airlines and travel service providers. By integrating these APIs, small businesses can fetch flight schedules, availability, and prices, helping travelers find the deals they need, all in one place.
Skyscanner API: A Treasure Trove of Options
Skyscanner API stands out as a favorite. It's like having your own travel assistant at your fingertips. This API provides comprehensive data on flights, accommodations, and car rentals across multiple airlines. With its user-friendly structure, you can seamlessly integrate it into your website. Plus, it’s excellent for small businesses looking to offer a wide range of options without getting bogged down by complex systems.
Amadeus API: Powering Your Travel Solutions
Amadeus isn't just a giant in the travel world; it’s a goldmine for small businesses too. This API provides robust functionalities, allowing you to access information about flight availability, fare rules, and even check-in details. Imagine being able to offer your customers personalized travel experiences, all thanks to the wealth of data Amadeus supplies.
Kiwi.com API: The Flexibility You Need
Kiwi.com API gives you the flexibility to combine different airlines and find unique routes. It’s like having a magic wand that creates unconventional itineraries! You can cater to budget travelers who love to explore offbeat paths. In a world where travelers crave personalized experiences, this API offers just that.
Travelport API: A Well-Rounded Option
If you’re looking for a well-rounded travel API, Travelport does not disappoint. It offers access to a multitude of airlines and provides detailed pricing and availability. Using Travelport, you can manage bookings and even handle customer service queries seamlessly. It’s like having a one-stop shop for all your travel API needs.
Sabre API: The Industry Leader
Sabre API is another heavyweight champion in the travel industry. With a vast network and established reputation, it provides detailed flight information and booking capabilities. If your small business aims to grow into a trusted name, partnering with Sabre can help you reach a broader audience.
What to Consider When Choosing an API
Choosing the right API can be overwhelming, but it boils down to a few essential factors:
• Cost: Is there a fee to use the API? Always weigh the costs against your potential revenue.
• Documentation: How easy is it to integrate? Well-documented APIs are easier and less time-consuming to implement.
• Support: If you run into issues, how responsive is their support team? Quality customer support can save you a lot of headaches.
For small travel businesses, flight APIs are more than just tools; they’re keys to unlocking wider opportunities. Each API has its unique perks, so it’s crucial to find the one that aligns with your business goals. With the right flight API, you can simplify booking processes, enhance customer satisfaction, and ultimately boost your bottom line. Embrace the innovation, and let your travel business soar!
Source & Published by: https://www.namantechnolab.com/
そんな手作業でやらなくてよいぞ
これで思う存分やりなさい
(function() {
const data = [];
$$('span.hatena-star-inner-count').map(x => x.click());
$$('.js-bookmarks-recent .entry-comment-contents').map(content => {
const userName = content.getAttribute('data-user-name');
const comment = content.querySelector('.entry-comment-text')?.textContent;
content.querySelectorAll('a.hatena-star-star').forEach(a => { stars.push(a.href.split('/')[3]); })
data.push([userName, comment, stars]);
});
data.sort((a,b) => b[2].length - a[2].length);
copy(data.map(d => `| ${d[0]} | ${d[1]} | ${d[2].join(',')} |`).join("\n"));
})();
https://www.youtube.com/watch?v=AEbfiLaOdJA
https://www.youtube.com/watch?v=ysqiEC6bLUI
オフィシャルトレイラーも相変わらずセンス良くてブチ上がりですよ
Season1の
からのSeason2の
"Jinx!"
は悲しすぎる😭😭😭
この二人の話はSeason2で完結らしいけどほんとに終わるんか~??
早くみたい!!!
In today’s fast-paced travel industry, small businesses need to stay nimble and connected. One way to do this is by tapping into flight APIs. These powerful tools can elevate your travel booking system, making it easier to offer competitive flight options. So, what’s the the best flight API for your small travel business? Let’s explore some of the top choices out there.
Understanding Flight APIs: What Are They?
At their core, flight APIs allow access to flight data. Think of them as a bridge connecting users to various airlines and travel service providers. By integrating these APIs, small businesses can fetch flight schedules, availability, and prices, helping travelers find the deals they need, all in one place.
Skyscanner API: A Treasure Trove of Options
Skyscanner API stands out as a favorite. It's like having your own travel assistant at your fingertips. This API provides comprehensive data on flights, accommodations, and car rentals across multiple airlines. With its user-friendly structure, you can seamlessly integrate it into your website. Plus, it’s excellent for small businesses looking to offer a wide range of options without getting bogged down by complex systems.
Amadeus API: Powering Your Travel Solutions
Amadeus isn't just a giant in the travel world; it’s a goldmine for small businesses too. This API provides robust functionalities, allowing you to access information about flight availability, fare rules, and even check-in details. Imagine being able to offer your customers personalized travel experiences, all thanks to the wealth of data Amadeus supplies.
Kiwi.com API: The Flexibility You Need
Kiwi.com API gives you the flexibility to combine different airlines and find unique routes. It’s like having a magic wand that creates unconventional itineraries! You can cater to budget travelers who love to explore offbeat paths. In a world where travelers crave personalized experiences, this API offers just that.
Travelport API: A Well-Rounded Option
If you’re looking for a well-rounded travel API, Travelport does not disappoint. It offers access to a multitude of airlines and provides detailed pricing and availability. Using Travelport, you can manage bookings and even handle customer service queries seamlessly. It’s like having a one-stop shop for all your travel API needs.
Sabre API: The Industry Leader
Sabre API is another heavyweight champion in the travel industry. With a vast network and established reputation, it provides detailed flight information and booking capabilities. If your small business aims to grow into a trusted name, partnering with Sabre can help you reach a broader audience.
What to Consider When Choosing an API
Choosing the right API can be overwhelming, but it boils down to a few essential factors:
• Cost: Is there a fee to use the API? Always weigh the costs against your potential revenue.
• Documentation: How easy is it to integrate? Well-documented APIs are easier and less time-consuming to implement.
• Support: If you run into issues, how responsive is their support team? Quality customer support can save you a lot of headaches.
For small travel businesses, flight APIs are more than just tools; they’re keys to unlocking wider opportunities. Each API has its unique perks, so it’s crucial to find the one that aligns with your business goals. With the right flight API, you can simplify booking processes, enhance customer satisfaction, and ultimately boost your bottom line. Embrace the innovation, and let your travel business soar!
Source & Published by: https://www.namantechnolab.com/
URI(Uniform Resource Identifier)
URL(Uniform Resource Locator)
大雑把にはそんな感じ
よく、「URIって呼べよ恥かしい」みたいな人いるけど、そっちが恥ずかしいです
例えば、下記のようなURLがあったとして
https://test:testpw@hogehogefugafuga.jp/index.html:8080
① スキーム
② オーソリティ
//test:testpw@hogehogefugafuga.jp/index.html:8080
ポート :8080
hogehogefugafuga.jp にアクセスしますよぉ、提示した情報でというもの
インターネットを作った人は全世界の人が使うようになる前提で、ややこしいhttp://を決めたのかなぁ?
こんなに使われることになるくらいならもっとシンプルなものにしてた可能性が高かったんじゃないかなと技術脳ゼロの自分は思ってしまうわけです。
すげぇシンプルです
これ以上シンプルにするって逆にどうやるの?
例えばメールサーバーには、「mx」や「mail」などのサブドメインが付きます
これに対して、webサーバーを示すサブドメインとして「www」を使ったわけです
すげぇシンプルです
ロックに条件持たせる
やりたいことはできてるように見えるが、うーんしんどい
# Entity Relation Diagram
# ```mermaid
# ---
# title: Rental Office example
# ---
# erDiagram
# OFFICE ||--|{ ROOM : x
# OFFICE {
# number office_id
# }
# ROOM {
# number office_id
# number room_id
# }
# ROOM ||--|{ SCHEDULE : x
# SCHEDULE {
# number room_id
# datetime start_at
# datetime end_at
# }
# OFFICE ||--|{ BUSINESS_HOUR : x
# BUSINESS_HOUR {
# number office_id
# enum week_of_day
# datetime start_at
# datetime end_at
# }
# ```
# Directed Acyclic Graph
#
# ```mermaid
# graph LR
# A[OFFICE] --> B[ROOM]
# B --> C[SCHEDULE]
# A[OFFICE] --> D[BUSINESS_HOUR]
# D --> C
# A --> C
# ```
# 基底クラス: EntityLock
class EntityLock
attr_accessor :entity_name, :entity_locked, :attribute_locks
def initialize(entity_name)
@entity_name = entity_name
@entity_locked = false # エンティティ全体のロック状態を保持
@attribute_locks = {} # IDに対するロックを管理するハッシュ
end
def lock_entity
@entity_locked = true
puts "Entity '#{@entity_name}' is now locked."
end
def unlock_entity
@entity_locked = false
puts "Entity '#{@entity_name}' is now unlocked."
end
def lock(attributes)
entity_id = attributes["#{@entity_name.downcase}_id"]
if entity_id && !@attribute_locks[entity_id]
@attribute_locks[entity_id] = true
puts "#{@entity_name} with ID '#{entity_id}' is now locked."
end
end
def unlock(attributes)
entity_id = attributes["#{@entity_name.downcase}_id"]
if entity_id && @attribute_locks[entity_id]
@attribute_locks.delete(entity_id)
puts "#{@entity_name} with ID '#{entity_id}' is now unlocked."
end
end
def locked?(attributes)
# まずエンティティ全体がロックされているかチェック
return true if @entity_locked
# 次に特定のIDがロックされているかチェック
entity_id = attributes["#{@entity_name.downcase}_id"]
if entity_id && @attribute_locks[entity_id]
return true
end
# ロックされていなければfalseを返す
false
end
end
# 子クラス: OfficeLock, RoomLock, ScheduleLock
class OfficeLock < EntityLock
def initialize
super("Office")
end
end
class RoomLock < EntityLock
def initialize
super("Room")
end
end
class ScheduleLock < EntityLock
def initialize
super("Schedule")
end
end
# 子クラス: BusinessHourLock
class BusinessHourLock < EntityLock
def initialize
super("BusinessHour")
@attribute_locks = [] # BusinessHour用のロックを配列で管理
end
def lock(attributes)
start_at = attributes["start_at"]
end_at = attributes["end_at"]
if start_at && end_at
@attribute_locks << [start_at, end_at]
puts "BusinessHour from '#{start_at}' to '#{end_at}' is now locked."
end
end
def unlock(attributes)
start_at = attributes["start_at"]
end_at = attributes["end_at"]
if @attribute_locks.include?([start_at, end_at])
@attribute_locks.delete([start_at, end_at])
puts "BusinessHour from '#{start_at}' to '#{end_at}' is now unlocked."
end
end
def locked?(attributes)
# まずエンティティ全体がロックされているかチェック
return true if @entity_locked
# 次に特定の時間範囲がロックされているかチェック
start_at = attributes["start_at"]
end_at = attributes["end_at"]
if start_at && end_at
@attribute_locks.each do |(locked_start, locked_end)|
if locked_start <= start_at && end_at <= locked_end
return true
end
end
end
# ロックされていなければfalseを返す
false
end
end
# TreeNodeクラス
class TreeNode
attr_accessor :name, :children, :parents, :lock
def initialize(name, lock)
@name = name
@children = []
@parents = [] # 複数の親ノードを保持する配列
@lock = lock # TreeNodeにロックを持たせる
end
def add_child(child_node)
child_node.parents << self # 子ノードにこのノードを親として追加
@children << child_node
end
def display(level = 0)
indent = " " * (level * 4)
puts "#{indent}#{@name}"
@children.each { |child| child.display(level + 1) }
end
def has_dependency
return false if @parents.empty?
@parents.each do |parent|
puts "#{@name} is dependent on #{parent.name}"
return true
end
@parents.any?(&:has_dependency)
end
def locked?(attributes = {})
# 自身がロックされているか確認
return true if @lock.locked?(attributes)
# 親ノードがロックされているか再帰的に確認
@parents.any? { |parent| parent.locked?(attributes) }
end
end
# 木構造の組み立て
# ロックオブジェクトの作成
office_lock = OfficeLock.new
room_lock = RoomLock.new
schedule_lock = ScheduleLock.new
business_hour_lock = BusinessHourLock.new
# ノードの作成
office_node = TreeNode.new("Office", office_lock)
room_node = TreeNode.new("Room", room_lock)
schedule_node = TreeNode.new("Schedule", schedule_lock)
business_hour_node = TreeNode.new("BusinessHour", business_hour_lock)
# ノード間の依存関係の設定
office_node.add_child(room_node) # Office -> Room
room_node.add_child(schedule_node) # Room -> Schedule
office_node.add_child(business_hour_node) # Office -> BusinessHour
business_hour_node.add_child(schedule_node) # BusinessHour -> Schedule
# 木構造の表示
office_node.display
# ロックの確認
puts "Case 1. Office全体がロックされた場合"
puts "Is office_node locked? #{office_node.locked?({})}" # false
puts "Is schedule_node locked? #{schedule_node.locked?({})}" # false
office_lock.lock_entity
puts "Is office_node locked? #{office_node.locked?({})}" # true
puts "Is schedule_node locked? #{schedule_node.locked?({})}" # true
office_lock.unlock_entity
puts "Case 2. Room id:1 がロックされた場合"
puts "Is schedule_node locked? #{schedule_node.locked?({ "room_id" => 1 })}" # false
puts "Is schedule_node locked? #{schedule_node.locked?({ "room_id" => 2 })}" # false
room_lock.lock({ "room_id" => 1 })
puts "Is schedule_node locked? #{schedule_node.locked?({ "room_id" => 1 })}" # true
puts "Is schedule_node locked? #{schedule_node.locked?({ "room_id" => 2 })}" # false
room_lock.unlock({ "room_id" => 1 })
puts "Case 3. BusinessHour start_at:0 end_at:5 がロックされた場合"
puts "Is schedule_node locked? #{schedule_node.locked?({ "room_id" => 1, "start_at" => 0, "end_at" => 5 })}" # false
puts "Is schedule_node locked? #{schedule_node.locked?({ "room_id" => 1, "start_at" => 5, "end_at" => 10 })}" # false
business_hour_lock.lock({ "start_at" => 0, "end_at" => 5 })
puts "Is schedule_node locked? #{schedule_node.locked?({ "room_id" => 1, "start_at" => 0, "end_at" => 5 })}" # true
puts "Is schedule_node locked? #{schedule_node.locked?({ "room_id" => 1, "start_at" => 5, "end_at" => 10 })}" # false
business_hour_lock.unlock({ "start_at" => 0, "end_at" => 5 })