自分のサイトをプログラミングして作らないのはプログラマーとして問題なのでは?
ということで作った。
サイト自体は年の初めくらいにほぼ完成していたものの、デザインがいけてなかったり良いタイトルが思いつかなかったりで放置してた。
4か月かかったこのタイトルだが、アグロとはTCG文脈での「序盤から高い攻撃力を出して速攻する」ような戦術のことで、タイトルは寿司屋で速攻でマグロを頼むという意味。美味いからね、マグロ。
ゲームもあるのでアクセスして遊んでね!!!!!
自分のサイトをプログラミングして作らないのはプログラマーとして問題なのでは?
ということで作った。
サイト自体は年の初めくらいにほぼ完成していたものの、デザインがいけてなかったり良いタイトルが思いつかなかったりで放置してた。
4か月かかったこのタイトルだが、アグロとはTCG文脈での「序盤から高い攻撃力を出して速攻する」ような戦術のことで、タイトルは寿司屋で速攻でマグロを頼むという意味。美味いからね、マグロ。
ゲームもあるのでアクセスして遊んでね!!!!!
アスペクト比を維持して固定値を使わずに整列させる方法をなんと2つも説明します。
まずは目指す状態について説明します。
上の画像では半透明の範囲に本の画像とその白背景のセットが2つ描かれています。また白背景は正方形で、本の画像はその中に収まります。つまり、本+白背景の縦横比は1:1になります。
整列の設定を上手く施すことで、中身を増減させても自動的に間隔を調整してくれます。実際私は、以下の画像を作る時に位置や大きさを入力しませんでした。
以降の章でこの自動整列の設定方法について解説します。
なお、この記事では横に整列させる方法を解説しますが、Horizontal←→Vertical、Width←→Heigh(t)と適宜変換すれば縦にも同様に整列させられます。
自動整列を実装する方法は複数ありますので、まずはそれらの共通部分について説明します。
上の画像は本の画像と白背景のセットが2つある場合のヒエラルキーです。
上のヒエラルキーに登場するCanvas内のGameObjectが有するComponentを以下に示します。
これらに追加でComponentを加えるケースもあります。
Areaに紐づける"Horizontal Layout Group"の"Control Child Size"のHeighがTrueになっている場合(上の画像)、子のオブジェクト(GameObject1)のHeightには何も入力できない状態になります。"Control Child Size"はその名の通り、子のWidthやHeightを親が決定するかどうかのフラグであり、Trueになると子オブジェクトに対するWidth/Heightの入力を受け付けなくなります。
本と白画像のセットの縦横比は1:1にするためには、Widthの値をHeightからコピーしてくる必要があります。そこで、子オブジェクトに"Aspect Ratio Filter"を適用します。
Aspect Ratio Filterはそのオブジェクトのアスペクト比を自動で決定するためのComponentです。Aspect Modeで"Height Controls Width"を選択すると、WidthがHeightの値から自動入力されます。このように設定することで、本+白背景を複製しても同じ親にある限り上手に間隔を作ってくれます。
しかし残念なことに、子オブジェクト以下をPrefab化してスクリプト上から複製すると自動整列が機能しません。Aspect Ratio FilterとHorizontal Layout Groupが共存すると発生する問題のようで、入力をロックする箇所が異なっていても動作しないようです(実際警告が出てる)。Aspect Ratio Filterが先にWidthやHeightをロックすることで後のLayoutGroupが動作できなくなり、機能しないのではないかと睨んでいます。Prefabから生成する場合は次の方法を試してみてください。
代替案として、子オブジェクトの代わりに孫オブジェクト(Background)にAspect Ratio Filterをつけることでも自動整列が可能です。その際、Aspect Modeを"Envelope Parent"に設定しましょう。Envelope Parentモード下では、元々設定していた孫オブジェクトの大きさを子の大きさによって拡大することが可能になります。
上の画像ではW Deltaに82.79999と入力されています。これは親オブジェクトのHeightが182.79999で、元々設定されていた子オブジェクトのWidthが100であり、Envelope Parentによって引き伸ばされた分がW Deltaに入力されます。
この方法ではPrefabから生成しても自動整列が機能します。Aspect Ratio FilterとHorizontal Layout Groupが同じ箇所をロックすることもないので、警告も発生しません。
自動整列問題がややこしいのは、WidthやHeightを画面の大きさに応じて変化させようとするからです。WidthやHeightに固定値を入力させられれば、Layout Elementなどを利用してもっとわかりやすく自動整列を実装できます。まずは画面のサイズを最初に決めて、WidthやHeightに固定値を入力させるのが良いと思います(一敗)。
以上です。
こんにちは、あすらと(@__asurato__)です。
モダンなゲームではあまり見かけなくなりましたが、大戦略やCivilizationのような戦略シミュレーションではヘクス座標系が採用されています。ヘクス座標系では1つのマスが正六角形になっており、正六角形の各マスは隙間なくマップに敷き詰められます。本日はヘクス座標系のマスの管理方法について考察しましたのでご覧ください。
例えば tiles[id] 等でそのidに関するTile型のインスタンスを取得することができれば前の3つについて達成されます。言い方を変えると、関数f: id→Tile となる関数が作れるならOKです。
またマスXに隣接したマスYを取得できれば最後の項目は達成されます。前3つの項目によりidからTileへの変換は前提とするため、XのidからYのidが取得できれば達成されます。
以下からマスの管理方法について章立てで説明します。
このような場合はIDを振る方向を横に変えるとなんと解決します。
一次元的にIDを与えるのではなく、二次元座標を用いて各マスを二次元配列に格納することもできます。座標[a, b]のマスはtiles[a][b]として取得します。
問題点として、tiles[0][0]とは異なりtiles[0][1]には値が存在しません。tiles[a][b]が存在するかを常にチェックする必要があります。
上の手法の派生系で、二次元座標を文字列に変換してMapに格納する手法です。ちなみにPythonのようにタプルをキーにできる言語や、座標を示す構造体をMapのキーに自前で設定する場合は文字列への変換は不要です。メリットはメモリの無駄がないこと、デメリットは座標とMapのキーとの相互変換が面倒な点でしょう。
まず上図のように軸を設定し座標を計算します。B軸の位置について、Aの要素が0以上になるように設定しましょう。
次に2つの配列を用意します。1つ目の配列には全てのマスが格納され、もう1つの配列には前者の配列のキー(ID)が入ります。
まず要素Aが小さい順に、要素Aが同値の場合は要素Bが小さい順にマスを配列1へ格納します。その格納の際に、要素B=0となるマスの(配列1における)IDを配列2に格納します。2つの配列を用いて、座標(a, b)のマスは arr1[arr2[a] + b] として取得できます。
http://higesusk.blog.fc2.com/blog-entry-146.html
https://ninagreen.hatenablog.com/entry/2015/11/14/193417
https://sinsei.space/blog/11747
https://www.redblobgames.com/grids/hexagons/
RustはC言語並みの実行速度、モダンな言語特有の安全性、堅牢な型システムを有するプログラミング言語です。
Stack Overflowの調査ではRustは最も愛される言語に選ばれましたが、Rust固有の概念や型システムは難解で言語の性能に比べて愛用者は少ない印象です。「好きな言語?まぁ、Rustかな。」と言った日には圧倒的玄人感で周囲を威圧させ、その眩き威光には流石の水戸黄門も平伏すしかありません。
そんな厨二病患者へのサポートも欠かさない言語、Rust。私も最近勉強を始めました。しかしサクッと競プロも問題を数問解いてみたところ、このような感想を持ちました。
Rustくん、君ねVecとIteratorの関数多すぎじゃないかい?反省してる?ねぇ?
— あすらと (@__asurato__) April 19, 2023
ということで検証しました。
やっぱりVecとIteratorの数が多いですね。これはRustがオーバーロードを実装していない点が原因の一つです。reduce関数とfold関数は顕著な例で、初期値の有無のみで2つの関数に分かれています。
続いてRust以外の言語の関数の数について紹介します。
JavaScriptのArrayはVecとIteratorの役割を同時に果たすことも相俟って、関数の数は少ないです。まあブラウザで動かし続けないといけないからね。そりゃ慎重にもなる。
155個!?
これは私の推測ですが、Arraysクラスの関数の多さはJavaが互換性を残しているためだと考えられます。binarySearch関数は全部で18個存在し、T[]のようなジェネリクス以外にint[]やdouble[]を引数として用意する徹底ぶり。
しかし、比較的新しいStreamクラスについてはRustに比して関数は少なく、Listクラスについても同様です。
さて私の愛するC#ですが、意外と関数が多い。競プロで使うくらいLINQ好きなんですけどね...
なんか雲行きが怪しくなりました。
さて、Pythonは組み込み関数だから比較は難しいし、あと触ったことがある言語は......Scalaかぁ。
疑ってすまないRustくん。君も多い方なんだろうけど......
あと今日からScala叩きに転身します。
P.S. Pythonのリストの関数は11個でした。
終わり
using System;
using System.Collections.Generic;
using System.Linq;
namespace Library
{
public class SegmentTree<T> where T: struct
{
private readonly T[] data;
private int size = 1;
private T defaultValue;
private Func<T, T, T> function;
public SegmentTree(int size, T defaultValue, Func<T, T, T> function)
{
while(this.size < size) this.size *= 2;
this.defaultValue = defaultValue;
this.function = function;
data = Enumerable.Repeat(defaultValue, this.size * 2 - 1).ToArray();
}
// [a, b)
public T RangedValue(int a, int b) { return RangedValue(a, b, 0, 0, size); }
private T RangedValue(int a, int b, int now, int l, int r)
{
if (r <= a || b <= l) return defaultValue;
if (a <= l && r <= b) return data[now];
return function(RangedValue(a, b, now * 2 + 1, l, (l + r) / 2), RangedValue(a, b, now * 2 + 2, (l + r) / 2, r));
}
public T this[int index]
{
get
{
return data[size + index - 1];
}
set
{
index += size - 1;
data[index] = value;
while (index > 0)
{
index = (index - 1) / 2;
data[index] = function(data[index * 2 + 1], data[index * 2 + 2]);
}
}
}
}
}
class Input {
static IEnumerator<string> enumerator = new string[] { }.AsEnumerable().GetEnumerator();
public static string Line => Console.ReadLine();
public static string[] StrArr => Line.Split(' ');
public static int NextInt => int.Parse(NextWord());
public static long NextLong => long.Parse(NextWord());
public static List<int> IntList => StrArr.Select(int.Parse).ToList();
public static List<long> LongList => StrArr.Select(long.Parse).ToList();
public static string NextWord() {
while (!enumerator.MoveNext()) {
enumerator = StrArr.AsEnumerable().GetEnumerator();
}
return enumerator.Current;
}
}
var a = NextInt; Console.WriteLine(a);
IEnumerator DealHard () {
while (time > 0) {
time -= Time.deltaTime;
lefttime.text = ((int)time).ToString ();
}
time = 0;
Debug.Log ("タイムアップ");
}
このスクリプトは残り時間を計測しその秒数をテキストに出しています。
このコードではunityが途中でバグります。(それか一瞬でtimeが0になる)
どこが間違っているかお分かりですか?
IEnumerator DealHard () {
while (time > 0) {
time -= Time.deltaTime;
lefttime.text = ((int)time).ToString ();
yield return null; // ここ
}
time = 0;
Debug.Log ("タイムアップ");
}
正解は yield return null をwhileの中に書いていないことです。
そもそも Time.deltaTime は前のフレームと次のフレームの時間差を取るものです。
最初のコードでは無数の繰り返し処理が1フレームで行われてしまいます。
そして何やかんやでunityが死ぬ。
yield return null はそのフレームの作業を中断し次のフレームから再開させます。
つまり、 Time.deltaTime との相性がよくなるわけです。
よかった、これで解決ですね
アスラトです。
「もっとコードを綺麗に書きたいなー」と漠然と考えるようになってきた今日この頃。
アルゴリズムを勉強しようと思い立ちそれ関係の本を探していました。
が、その中でAtcoderというアルゴリズム学習に適したサイトを見つけたので
ワイ「ま、後で考えましょ」ポーイ
......ということでそれ関係の本は後回しにしてとりあえず参加してみました。
今日はその結果と感想です。ちなみにC言語で書きました
A問題はそんなに難しくはなかったです。(なおかかった時間)
絶対値の関数ってなんだっけ?
大きい方を出力する関数って何をincludeしなきゃいけないんだっけ?
ファ!?Xcodeがなんかおかしい
ということを調べていたらA問題に13分ぐらいかかってしまいました。悲しい
「正整数 X 以下の最大のべき乗数を求めてください。」という問題です。
リンク先に書いてありますが、べき乗数の底と指数は任意です。
これを私は平方数だと勘違いしていました。
aという変数に入力されたデータを代入したら、
printf("%d", (int)sqrt(a)*(int)sqrt(a));
こうやれば終わりじゃね?はっやーいと思って提出したら弾かれました。
問題文はしっかり見ような(戒め)
A,B共に問題を見たらすぐに道筋が思いつきましたがCはそうはいきませんでした。
途中でC言語きつくね?C#かjavaでlistを使ったらいけそう...?とか考えましたがやめました。
夕食食べてなかったんですよ。残り時間が半分になったところで夕食にしました。
...で戻ってきたのはコンテスト終了直前。当然できるはずもなく。
悲しいというかそれはそうという感想。
コンテストに関しての感想は
やってみて分かったこともあります。
が、何よりアルゴリズムの勉強をしようというやる気が生まれたのは大きかったです。
皆様も是非。