20210906のC#に関する記事は3件です。

【C#】小数点の四捨五入

今回学んだこと 小数点の四捨五入 小数点以下の一部をゼロで埋める方法 コード 小数点の四捨五入 //四捨五入したい数と、小数点第何位までの桁数を表示させたいかを入力する。 //桁数が足りない場合は0が入る。 decimal[] N = Console.ReadLine().Split().Select(decimal.Parse).ToArray(); decimal num = Math.Round(N[0], (int)N[1], MidpointRounding.AwayFromZero); Console.WriteLine(num.ToString().PadRight((int)N[1] + 2, '0')); Math.Round()だけたど、最近接偶数というものが発生する。 端数が真ん中0.5だと、値に一番近い偶数になってしまうというもの。 (例えば、2.5を四捨五入して3になるだろうと思ったら、実際は2になる) そのため、Math.Round()の引数で MidpointRounding.AwayFromZeroを追加して四捨五入ができるようにします。 ちなみに配列Nは、 N[0] 四捨五入したい数 N[1] 四捨五入したい数を小数点第何位まで表示するかを指定 を表しています。 そしてnum.ToString()で文字列に変換。 PadRight((int)N[1] + 2, '0')で右から0をN[1]個詰めていきます。 +2と書いてあるのは、PadRightがコンマも計算に入れるからです。 というよりも、他の良い方法が思いつかなかっただけ…。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

行レベルセキュリティーを考慮したQuickSightの登録済みユーザーの埋め込みダッシュボード機能を利用する

はじめに 前回この記事でQuickSightのRLSを考慮した匿名ユーザー向けの埋め込みダッシュボードの表示について説明しましたが、登録済みユーザーのダッシュボードも試したので記録として残しておきます。 前編及び後編で作成したダッシュボードやソースをもとに設定を追加していくので、実際に手を動かして確認する場合はまず前編及び後編を確認してみてください。 匿名ユーザーと登録済みユーザーの埋め込みダッシュボードの違い 前回作成した匿名ユーザーの埋め込みダッシュボードと、登録済みユーザーの埋め込みダッシュボードには次のような違いがあります。 登録済みユーザーの埋め込みダッシュボードは、 EnterpriseEditionは必須だが、セッションキャパシティープランでなくても利用できる ダッシュボード表示時にQuickSightのReader以上のアカウントを割り当てる必要がある セッションタグを利用した行レベルセキュリティー(RLS)は利用できないため、事前にユーザーごとのRLSを設定する必要がある やはり一番の違いはセッションキャパシティープランでなくても利用できる点だと思います。セッションキャパシティープランを必要とする匿名ユーザーの埋め込みダッシュボードでは開いたセッション数で課金されるのに対し、登録済みユーザーの埋め込みダッシュボードでは登録されたユーザーの数で課金されます。 QuickSight 料金 このため、ダッシュボードの利用人数は少ないんだけれど特定の人が良く見るとか、一人当たりのダッシュボード表示回数はあまりないんだけれどとにかく利用者数が多いといった埋め込みダッシュボードの表示パターンをもとにQuickSightの契約プランを検討する必要があります。 また、いつRLSを割り当てるかも重要な観点です。登録済みユーザーの埋め込みダッシュボードではセッションタグが利用できないため、RLSは事前に登録しておく必要があります。匿名ダッシュボードのようにダッシュボードURL発行時に割り当てるRLSを制御できない点も注意が必要です。 グループの追加 匿名ユーザーの埋め込みダッシュボードの場合、作成したダッシュボードはユーザーかグループに対して事前に共有しておく必要があります。ユーザーごとにダッシュボードを共有するとユーザー登録が煩雑になるため、ダッシュボードをグループに共有しそのグループにユーザーを登録してあげたほうが運用しやすいと思います。グループはUIからは追加できないのでAWS CLIから登録する必要があります。 aws quicksight create-group --aws-account-id $awsAccountId --namespace default --group-name SampleDashboard { "Status": 201, "Group": { "Arn": "arn:aws:quicksight:ap-northeast-1:xxxxxxxxxxxx:group/default/SampleDashboard", "GroupName": "SampleDashboard", "PrincipalId": "group/d-xxxxxxxxxx/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" }, "RequestId": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" } ダッシュボードをグループに公開 埋め込みたいダッシュボードを先ほど作成したグループに割り当てていきます。ここはUIからやったほうが分かりやすいのでUIで操作します。 ダッシュボードの共有メニューから 共有したいグループを検索して共有ボタンをクリックします。 ダッシュボードアクセスの管理ボタンをクリックすると、現在共有されているユーザー、もしくはグループの一覧を確認できます。 登録済みユーザーの埋め込みダッシュボードの表示 それではダッシュボードを表示していきましょう。 まずはダッシュボードを表示するためのユーザーを登録し、先ほどダッシュボードを公開したグループに所属させます。 ユーザーの登録やグループへの参加はあらかじめCLIから設定しておいてもよいのですが、アプリ側でダッシュボードURLの作成時にQuickSightのユーザーを登録してグループに参加させたほうが運用が楽になるケースが多いと思うので、ここからはアプリ側で実装していきます。 前回使った画面に登録済みユーザーでダッシュボードを表示するためのボタンを一つ配置しておきます。 Index.cshtml @page @model IndexModel @{ ViewData["Title"] = "Home page"; } <div class="text-center"> <form method="post"> <div><select asp-for="SelectedDashboard" asp-items="Model.DashboardList" name="dashboard" id="dashboard"></select></div> <div><input type="submit" value="表示(User)" asp-page-handler="ViewDashboardForUser"/></div> <div><input type="submit" value="表示(Admin)" asp-page-handler="ViewDashboardForAdmin"/></div> + <div><input type="submit" value="表示(test1ユーザー)" asp-page-handler="ViewDashboardForTest1User"/></div> </form> @if (!string.IsNullOrEmpty(Model.EmbedDashboardUrl)) { <div style="width: 100%"> <iframe style="width: 100%; height: 600px" src="@Model.EmbedDashboardUrl"></iframe> </div> } </div> このボタンを押されたときに実施するのは次の3つです。 1.ユーザーを取得(いなかったら登録) 2.ユーザーをグループに追加 3.埋め込みダッシュボードのURLを取得してページのEmbedDashboardUrlプロパティーに設定 ここでは固定でtest1@example.comというユーザーをQuickSightのユーザーとして作成していますが、実際はアプリ側で認証したユーザーのメールアドレスなどを使うことになると思います(アプリ側ではここで現在のユーザーが埋め込みダッシュボードを表示できるかのチェックを行ってもよいですね)。 Index.cshtml.cs public async Task OnPostViewDashboardForTest1User(string dashboard) { const string userName = "test1@example.com"; // STSからAWSのアカウントIDを取得し var account = await _amazonSecurityTokenService.GetCallerIdentityAsync(new GetCallerIdentityRequest()); await LoadDashBoardsAsync(account.Account); // 1.ユーザーを取得(いなかったら登録) var quickSightUserArn = await GetUserArnAsync(account.Account, "default", userName); if (string.IsNullOrEmpty(quickSightUserArn)) { quickSightUserArn = await RegisterUserAsync(account.Account, "default", userName, UserRole.READER); } // 2.ユーザーをグループに追加 await _amazonQuickSight.CreateGroupMembershipAsync( new CreateGroupMembershipRequest { AwsAccountId = account.Account, GroupName = "SampleDashboard", Namespace = "default", MemberName = userName }); // 3.埋め込みダッシュボードのURLを取得 var response = await _amazonQuickSight.GenerateEmbedUrlForRegisteredUserAsync(new GenerateEmbedUrlForRegisteredUserRequest { AwsAccountId = account.Account, ExperienceConfiguration = new RegisteredUserEmbeddingExperienceConfiguration { Dashboard = new RegisteredUserDashboardEmbeddingConfiguration { InitialDashboardId = dashboard, } }, UserArn = quickSightUserArn, SessionLifetimeInMinutes = 15, }); EmbedDashboardUrl = response.EmbedUrl; } ユーザーの存在を確認するにはユーザー一覧を取得するAPI(ListUserAsync)を呼んでもいいのですが、ユーザーでフィルターするインターフェイスが無いので全ユーザーをロードしてしまいます。ここではユーザーが存在するかはユーザーの詳細表示API(DescribeUserAsync)を呼び出して、ResourceNotFoundExceptionが発生したかどうかで判断しています。 public async Task<string> GetUserArnAsync(string awsAccountId, string @namespace, string userName) { try { var user = await _amazonQuickSight.DescribeUserAsync(new DescribeUserRequest { AwsAccountId = awsAccountId, Namespace = @namespace, UserName = userName }); return user.User.Arn; } catch (ResourceNotFoundException) { return null; } } public async Task<string> RegisterUserAsync(string awsAccountId, string @namespace, string userName, UserRole userRole) { var registerUserResponse = await _amazonQuickSight.RegisterUserAsync(new RegisterUserRequest { AwsAccountId = awsAccountId, Namespace = @namespace, IdentityType = IdentityType.QUICKSIGHT, Email = userName, UserName = userName, UserRole = userRole }); return registerUserResponse.User.Arn; } さっそく実行してあげましょう。ローカルで実行する場合はngrokでブリッジしQuickSightにドメインを登録するのを忘れないでください。 ... おや? あっ!肝心なRLSを追加するのを忘れていましたね。 RLSをCSVで設定している場合、新しいファイルをアップロードして更新する必要があるので新しいデータセットからデータセットを追加していきます。 今回はもとからいるqsadmin1に加え、今回アプリ側で利用するtest1@example.comユーザーを追加します。 bi_sample_dashboard_permission.csv UserName,role qsadmin1,"user,admin" test1@example.com,user 無事表示されましたね! まとめ 匿名ユーザーを利用するか登録済みユーザーを利用するかはダッシュボードの組み込み要件で決定する あらかじめグループを作成し、ダッシュボードをグループに対して共有する QuickSightユーザーはダッシュボードURL取得時に確認し、いなかったら登録してダッシュボードを共有したグループに所属させる
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Unityの物理エンジンを使ってブロック崩しを作ってみた

作るもの Unityをつかってブロック崩しを作成する。 仕様は以下の通り。 プログラム実行と同時にボールが右上に向かって発射 バーはキーボード矢印で操作。(面白そうなので上下にも動くようにする) ボールがバーより下の壁に当たると壁が消える ボールが、消えた壁の上を通過するとゲームオーバー ブロックに当たるとブロックが消える(ブロックは6つ) ブロックをすべて消してもクリア画面等は用意しない 開発環境 Unity 2020.3.2f1 Visual Studio Code 1.55.0 開発スタート 1.ブロック崩しに必要なものを配置 床、壁、ボールなどのブロック崩しに必要なオブジェクトを画面に配置する。 追加は画面上部のバーから「アセット」>「作成」を選択して行う いろいろなアセットがありますが、今回配置するオブジェクトに使うのは「マテリアル」のみ! ↓マテリアルを追加するとボール状のものがプロジェクトに追加されます 2.ボールに物理演算(物理エンジン)を付与する Unityには様々な物理演算機能が用意されています 今回はその中でも Rigidbody (重力付与及び動作制御) Sphere Collider (球体の衝突に関する設定) Rigidbodyの追加 「コンポーネント>物理>リジットボディ」からプロパティを追加します 今回Y軸(高さ)方向に動いてほしくないので、Constraintsの位置を固定にてYをチェックします。 また、回転も特に必要ないのですべてにチェックをします。 Sphere Colliderの追加 「アセット>作成>物理マテリアル」からプロジェクトにアセットを追加します ↓こんなアセットが追加されます。 ボールは等速でシンプルな動作をしてほしいので。 摩擦ゼロ 物体に当たったら跳ね返る 設定をします。 プロパティー説明 プロパティー 機能 Dynamic Friction 移動している物体に対する摩擦。通常は、0 から 1 の間の値を使用します。0 の場合、氷のような感じになります。1 の場合、強い力や重力がオブジェクトを押さない限り、すぐに止まります。 Static Friction 面上で静止しているオブジェクトに使用される摩擦。通常は、0 から 1 の間の値を使用します。0 の場合、氷のような感じになります。1 の場合、強い力を加えないとオブジェクトは動きません。 Bounciness 表面にどれだけ弾性があるか。0 の場合は弾性がありません。1 の場合はエネルギーが減ることなく跳ねます。シミュレーションには少量のエネルギーを加えるかもしれませんが、ある程度の近似が予想されます。 Friction Combine 衝突するオブジェクト間の摩擦をどう処理するか。 Bounce Combine 衝突するオブジェクト間の跳ね返し度合いをどう処理するか。Friction Combineと同じです。 以上の設定が完了したら、この物理マテリアルをボールの「Sphere Collider」に設定します。(マテリアルに設定した物理マテリアル名が表示されればOK) 3.スクリプトでものを動かす 物理エンジンでボールの動きは設定できたので、後は下記の動きをスクリプトで実装します。 ①ゲームスタートでボールを右上に発射 ②キーボードでバーを操作 ③ボールがブロックにあたったらブロックを消す ④(おまけ)ボールが、バーより下を2回通過するとゲームオーバーの文字を表示 ①④ using System.Collections; using System.Collections.Generic; using UnityEngine; public class ball : MonoBehaviour { public float speed = 1.0f; private Rigidbody myRigid; private bool OutFlg = false; public GameObject lightObj; public GameObject gameOverObj; light script; //UnityChanScriptが入る変数 // ゲームスタートでボールを右上に発射 void Start () { myRigid = this.GetComponent<Rigidbody>(); myRigid.AddForce((transform.forward + transform.right) * speed, ForceMode.VelocityChange); } // (おまけ)ボールが、バーより下を2回通過するとゲームオーバーの文字を表示 void Update() { if (this.transform.position.z < -7 && !OutFlg){ OutFlg = true; lightObj.GetComponent<light>().removeLight(); Rigidbody rd; rd = gameOverObj.GetComponent<Rigidbody>(); rd.useGravity = true; Destroy(this.gameObject); } } } ② using System.Collections; using System.Collections.Generic; using UnityEngine; public class player : MonoBehaviour { public float speed = 1.0f; // Start is called before the first frame update void Start() { } // キーボードでバーを操作 void Update() { if (Input.GetKey(KeyCode.LeftArrow)){ if(this.transform.position.x > -4) this.transform.position += Vector3.left * speed * Time.deltaTime; } if (Input.GetKey(KeyCode.RightArrow)){ if(this.transform.position.x < 4) this.transform.position += Vector3.right * speed * Time.deltaTime; } if(Input.GetKey(KeyCode.UpArrow)){ if(this.transform.position.z < 5.5) this.transform.position += Vector3.forward * speed * Time.deltaTime; } if(Input.GetKey(KeyCode.DownArrow)){ if(this.transform.position.z > -5.5) this.transform.position += Vector3.back * speed * Time.deltaTime; } } } ③ using System.Collections; using System.Collections.Generic; using UnityEngine; public class block : MonoBehaviour { // Start is called before the first frame update void Start() { } // Update is called once per frame void Update() { } // ボールがブロックにあたったらブロックを消す private void OnCollisionEnter(Collision collision){ Destroy(this.gameObject); } } 以上で完成です 出来上がったものがこちら
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む