はこねのはこ

はこねさんの備忘録

積(掛け算した値)がオーバーフローするかチェックする

はじめに

ABC169のBで躓いたので。
冷静じゃなくなると間違いが見えなくなる。

結論

一度掛け算し、その積をかけた数の片方で割った場合同じ値になるかをみている。

#define ul unsigned long
bool IsOverflow(ul a, ul b){
    ul x = b * a;
    return (x/a != b);
}

補足

負の数が含まれると不正解パターンがある。
というかコンテスト中にlonglongを用いていて失敗した。

#define ll long long
bool IsOverflow(ll a, ll b){
    ll x = b * a;
    return (x/a != b);
}

これを使ってしまうと下のようになる。
割とトラウマ...。
f:id:hakonebox:20200601223006p:plain

コード

// こっちでも行ける
bool IsOver(ll a, ll b, ll lim){
    return (b > lim/a);
}

// 成功した関数
bool IsOverflow(ul a, ul b){
    ul x = b * a;
    return (x/a != b);
}

// コンテスト中の関数
bool IsOver_ng(ll a, ll b){
    ll x = b * a;
    if(x/a != b){
        return true;
    }else{
        return false;
    }
}


void Main(){
    ul limit = pow(10,18);
    ul n;
    cin >> n;
    vector<ul> a(n);
    for(ul i = 0; i<n;i++){
        cin >> a[i];
        if(a[i] == 0){
            ct(0);
            return;
        }
    }
    ul ans = 1;
    for(ul i = 0; i < n; i++){
        //if(IsOver(ans,a[i], limit)){
        if(IsOverflow(ans,a[i])){
            ct(-1);
            return;
        }else {
            ans *= a[i];
            if ( ans > limit ){
                ct(-1);
                return;
            }
        }
    }
    ct(ans);
    return;
}

int main() {
    Main();
}

C++の少数の出力結果が丸められてしまったのでsetprecisionマニピュレータをつかった。

はじめに

先日AtCoderさんのABC168に参加した時、
問題Cの出力結果の精度がどうしても欲しいところまで出なくて悩んでいた。 atcoder.jp

4.56425719433005553554
...と割り切れない値のはずが、
4.56426
と表示されていた。

結論

setprecisionマニピュレータを使って解決した。

cout << fixed << setprecision(20) << getHoge() << endl;

コンテスト中に悩んでいたコード

仕様がわからずとりあえず精度を上げればなんとかならないかと考えて無意味にキャストしている。

#define ld long double

ld getSqrtl(ld x1,ld y1,ld x2,ld y2){
    ld x = x1 - x2;
    ld y = y1 - y2;
    ld ans = (ld)sqrtl( x*x + y*y );
    return ans;
}

int main() {
    ld A,B,H,M;
    //              時間  分
    cin >> A >> B >> H >> M;

    ld do2 = (ld)360.0 * ((ld)M/(ld)60.0);
    ld ra2 = do2 * ((ld)M_PI/(ld)180.0);
    ld x2 = B * cosl(ra2);
    ld y2 = B * sinl(ra2);

    ld do1 = (ld)360.0 * ((ld)H/(ld)12.0) + ((ld)30.0*((ld)M/(ld)60.0));
    ld ra1 = do1 * ((ld)M_PI/(ld)180.0);
    ld x1 = A * cosl(ra1);
    ld y1 = A * sinl(ra1);

    cout << getSqrtl(x1,y1,x2,y2) << endl;
}

出力結果

4.56426

出力の条件として、以下を満たす必要があるため不正解となってしまう。 f:id:hakonebox:20200527214806p:plain

setprecisionマニピュレータを使う

混乱しながらたどり着いた解決策がsetprecisionを使うことでした。
浮動小数点数を出力する精度を設定できる。
下記の例では少数第20位まで出力している。

cout << fixed << setprecision(20) << getSqrtl(x1,y1,x2,y2) << endl;

出力結果

4.56425719433005553554

おまけ

一回setprecisionすると次の出力では使わなくてもその出力結果になった。

cout << getSqrtl(x1,y1,x2,y2) << endl;
cout << fixed << setprecision(20) << getSqrtl(x1,y1,x2,y2) << endl;
cout << getSqrtl(x1,y1,x2,y2) << endl;

出力結果

4.56426
4.56425719433005553554
4.56425719433005553554

Unity InputSystemの導入(XBox,PS4コントローラで動作チェック)

はじめに

InputSystemを用いてXboxPS4のコントローラ入力をしようと思います。
今回使用するInputSystemはPreviewです。

docs.unity3d.com

経緯

以前にXBoxコントローラからの入力を確認してRLトリガーの入力だけどうしていいのかわからず2年弱が経過していました。
そんな中最近ふと思いました。またプレビュー版だけどInputSystem使えばシンプルに取得できるんじゃないか..?
そんなわけで確認してみようと思いました。

過去記事 hakonebox.hatenablog.com

環境

  • Unity2019.3.7f1
  • InputSystem preview.6 - 1.0.0
  • XBoxOneコントローラ(有線接続)
  • PS4コントローラ(有線接続)

InputSystemにはUnity2019.1以上と。NET4ランタイムが必要とのことです。

インストール

InputSystemのインストール

PackageManagerからインストールします。
preview版なので注意してください。
f:id:hakonebox:20200329142120p:plain

InputBackendを有効にする

Edit > Project Settings > Player

先にApiCompatibillityLevelを確認し、".NET 4.x"に設定します。
ActiveInputHandlingを"Input System Paclage(New)"に設定します。 すると自動でUnityが再起動すると思います。
f:id:hakonebox:20200329142837p:plain この設定を有効にするためには、UnityEditorを再起動する必要があるため、
自動で再起動が行われなかった場合には自身で再起動してください。

入力デバイスから直接入力を取得

まずは入力デバイスからの現在の入力状況を直接読み取りをしてみます。

using UnityEngine;
using UnityEngine.InputSystem;

public class CurrentInputTest : MonoBehaviour
{
    void Update()
    {
        var gamepad = Gamepad.current;
        if (gamepad == null)
            return;    // No gamepad connected.

        if (gamepad.rightTrigger.wasPressedThisFrame)
        {
            Debug.Log($"rightTrigger:{gamepad}");
        }  
    }
}

PCに接続しているXboxコントローラとPS4コントローラのRトリガーを引いてみます。
f:id:hakonebox:20200329144959p:plain
どちらも認識できているようです。 しかもどのコントローラから入力があったのかも判別できているようですね。

下記URLを参考にほかの入力を取得することができました。 docs.unity3d.com

前回InputManagerでLRトリガーの同時押しがうまくいかなかったのですが、 InputSystemでは簡単に取得できそうです。

InputActionを介して間接的に入力を取得

PlayerInputコンポーネントの追加

AddComponentからPlayerInputコンポーネントを追加します
f:id:hakonebox:20200329162430p:plain

Actionsを作成する

CreateActions..を押すことで作成できます。
f:id:hakonebox:20200329165624p:plain

このActionsのRightTriggerを取得してみます。
f:id:hakonebox:20200329163100p:plain

InputActionからスクリプトで取得

using UnityEngine;
using UnityEngine.InputSystem;

[RequireComponent(typeof(PlayerInput))]
public class InputActionTest : MonoBehaviour
{
    private InputAction m_fire;
    private void Awake()
    {
        var actionMap = GetComponent<PlayerInput>().currentActionMap;
        m_fire = actionMap["Fire"];
    }

    private void Update()
    {
        if (m_fire.triggered)
        {
            Debug.Log($"fire: {m_fire}");
        }
    }
}

f:id:hakonebox:20200329164452p:plain

今回はCreate Actionsを押してInputActionを作成しましたが、
Projectウィンドウからの右クリックから新規作成できます。 f:id:hakonebox:20200329164853p:plain

補足

Listenを使うことで、押したボタンが候補として出てくるので、 登録は簡単みたいです。

f:id:hakonebox:20200329165105p:plain

参考

learning.unity3d.jp

Unity1週間ゲームジャム[逆]"逆上がりJUMPERS"をHingeJoint2DとUniRxを使って作った話

はじめに

今回も作りました。
イラスト:はいき丸さん
f:id:hakonebox:20200303231059g:plain
unityroom.com

逆上がりで回転して遠心力でできるだけ遠くに飛ぶゲームです。
逆上がりするのに手が短すぎるのでつり革を持たせています。
これじゃ逆上がりに見えないね。

このはこねこの動きはHingeJoint2Dを採用しています。
また、何か新しいこと学びたいなと思って、
使おう使おうと思いながら全く使ってなかったUniRxを使ってみることにしました。

こちらは着地の様子。
かわいいので実際に遊んでみてほしいです。
f:id:hakonebox:20200304002007p:plain

そして遊んだ後にきっと思うと思います。 ”逆じゃん...” と。

HingeJoint2D

はこねこの動きはアニメーションを作るのではなく、
物理演算に身を任せた動きのほうが見てて楽しいし、
遊ぶうえで楽しい要素になると思い、体のパーツをHingeJoint2Dを採用しました。

特に曲がる角度に制限を設けないことにしました。
動かすとこんな感じです。
f:id:hakonebox:20200304001611g:plain

はこねことポール接続の接続は以下のようになってます。
f:id:hakonebox:20200304000612p:plain

ばらしてみるとこんな感じ
f:id:hakonebox:20200304001341p:plain

ポールの固定について

ConnectedRigitBodyをNoneとすることで
Connected Anchor 設定で定義した空間上の点に固定しています。
f:id:hakonebox:20200304000829p:plain

はこねこの接続について

こちらはポールに固定したつり革部分を設定しています。 同じようにはこねこの体におさげ、両足、しっぽを接続しています。 f:id:hakonebox:20200304001108p:plain

UniRx

github.com

ついでにMV(R)Pパターンを意識して開発しました。
ここではスコア表示の部分の紹介です。(一部抜粋)

View

気持ち程度のラベル初期化を行い、
ラベル更新用の関数を用意。

using UnityEngine;
using TMPro;

public class ScoreView : MonoBehaviour
{
    [SerializeField] private TextMeshProUGUI _scoreText;

    // Start is called before the first frame update
    void Start()
    {
        _scoreText.text = 0.ToString("#,#0");
    }

    // 値が更新されたときにラベル更新
    public void OnScoreChanged(int score)
    {
        _scoreText.text = score.ToString("#,#0");
    }
}

Model

ReactivePropertyでストリームソースの準備。

using UnityEngine;
using UniRx;

public class GameModel : MonoBehaviour
{
    private static ReactiveProperty<int> _score = new ReactiveProperty<int>(0);
    
    public IReadOnlyReactiveProperty<int> Score => _score;

    public static void SetScore(int score)
    {
        _score.Value = score;
    }
}

Presenter

値が変更になった時にラベルを変更するように設定。

using UnityEngine;
using UniRx;

public class MenuPresenter : MonoBehaviour
{
    // View
    [SerializeField] private ScoreView _scoreView;
    
    // Model
    [SerializeField] private GameModel _gameModel;
    
    void Awake()
    {
        Bind();
    }

    private void Bind()
    {
        _gameModel.Score
            .Subscribe(_scoreView.OnScoreChanged)
            .AddTo(gameObject);
    }
}

まだ自信をもって記述できてないので、
少しずつ触っていこうと思います。

1週間振り返り

2/24

今回こそはスキージャンプ台を逆走するゲームでオンライン対戦ありにしようとしてました。
意気揚々とオンライン対戦ボタンを準備。
また、PUN2の動作確認を進める。

しかし、今回もオンライン要素は見送りとなりました。
だってデバッグものすごい面倒なんだもん。

3/1

しばらく時間が空いて3/1。 このゲーム面白いのか?病が発症。
ゲームデザインの再考をし、悩んだ挙句変更を決意。

3/2

締め切り日20:00には間に合わず、翌日深夜4時までかけて開発しきりました。

びっくりするくらい進捗報告してませんでした。

さいごに

私としては、この作品はとてもよくできたと思っています。
物理演算を活かした動きは見ててかわいらしいし、
結果が出るまでの時間が短く、何度もリトライしやすいデザイン。
ここ最近、難しいことをしようとして複雑で最後まで遊びにくいものばかりでした。

かわいいイラストを描いてくれたはいき丸さんと
ゲーム内容の相談に乗ってくれた友人に感謝。

MacのCLionで#include <bits/stdc++.h>を使えるようにする。

はじめに

前回、MacのCLionでコンパイラの設定をしていました。 しかし、いざ使ってみると、

#include <bits/stdc++.h>

が読み込み得ずに下記のエラーがでてしまっていました。 その解決策です。

fatal error: 'bits/stdc++.h' file not found
#include <bits/stdc++.h>
         ^~~~~~~~~~~~~~~
1 error generated.

hakonebox.hatenablog.com 前回の設定ではインストールしたコンパイラは使えていなかったみたいですね。

解決策

c++ComPilerに下記のパスを記入。

/usr/local/opt/gcc/bin/g++-9

f:id:hakonebox:20200221083842p:plain

これで無事ビルドできました。

MacでもCLionを動かそうとしたらmissing xcrun at: /Library/Developer/CommandLineTools/usr/bin/xcrunと言われた話

はじめに

タイトルの通りです。 MacbookでもCLion使いたいので環境整えようとしました。
そしたらタイトルのエラーがでてあわあわしてました。

確認手順

Clion→Preferences→Toolchains コンパイラ見つかんないって怒られているみたい。 f:id:hakonebox:20200220225441p:plain

確認してみる。

gcc --version
xcrun: error: invalid active developer path (/Library/Developer/CommandLineTools), missing xcrun at: /Library/Developer/CommandLineTools/usr/bin/xcrun

エラーでてきた。
コマンドラインツールは入れてたと思ったのですが...
調べてみるとmacOSのアップデートが原因で発生するみたいです。 下記コマンドで

xcode-select --install

f:id:hakonebox:20200220231027p:plain

インストール完了後CLionで確認したら無事認識できました。

f:id:hakonebox:20200220232804p:plain

ついでにアップデートもしておきます。

brew install gcc

無事ビルドできるようになりました。

追記

しかしこれではインストールしたコンパイラは使えていなかったみたいです。 ↓↓ hakonebox.hatenablog.com

CLionの実行結果の文字化けを直す

はじめに

CLion入れました。 www.jetbrains.com

文字化けが起きてしまったのでその解決方法。

環境

  • Windows10

結論

文字コードの設定をUTF-8に合わせました。 f:id:hakonebox:20200219005149p:plain chcpで切り替えてもダメみたいだった(起動時に戻ってしまう。)ので 断腸の思いでベータの機能を採用。

ベータ:ワールドワイド言語サポートでUnicode UTF-8を使用
にチェックをつける。

検証コード

#include <bits/stdc++.h>
using namespace std;

int main() {
    cout << "競プロ" << endl;
    cout << "Hello CLion" << endl;
}