読者です 読者をやめる 読者になる 読者になる

スペクトルバスター Spectrum Buster

"恥ずかしさをかなぐり捨てろ!!"

"Don't be shy!!"

経緯 Proccess

サークルの合宿でアイデアソン, ハッカソンをしました. 我々はSiv3DのFFTの機能を利用して簡単なゲームを作成しました.

We held an ideathon and a hackathon. With FFT of Siv3D, we developed a simple game.

紹介 Description

音声をフーリエ変換して, 周波数スペクトルを敵に当てるゲームです. プレイヤは220Hz~880Hzの声を出してください. 左の敵には低音, 右の敵には高音を出しましょう. また, 上の敵には大きな声を出しましょう. 制限時間は30[s]です.

恥ずかしさをかなぐり捨ててできるだけ沢山の敵を倒してください.

Shoot enemies with frequency spectrum of your voice. Input your 220Hz~880Hz voice. To buster left enemy, input low-pitch sound. To buster right enemy, input high-pitch sound. To buster above enemy, input megavolume sound. Time limit is 30[s].

Don't be shy and buster many enemies!!!

ゲーム情報

  • タイトル : スペクトルバスター
  • 作者 : MPC (室蘭プログラミングクラブ) 合宿DE合宿 2016 チーム3
  • ジャンル : FFTシューティング
  • プレイ時間 : 30s程度
  • プラットフォーム : Windows
  • リリース : 2016年 9月 18日
  • 言語 : 日本語
  • 利用ライブラリ : Siv3D

Information

  • Title : Spectrum Buster
  • Developer : MPC (Muroran Programming Club) "合宿DE合宿 2016 Team 3"
  • Genle: FFTSTG
  • Playtime : 30s
  • Platform : Windows
  • Released on : 2016年 9月 18日
  • language : Japanese
  • Library : Siv3D

リンク Links

JavaFX 3 Canvas

Canvasクラス Canvas class

JavaFXCanvasクラスはProcessingやJavaScriptcanvasと同じ様に使う事ができます.

Canvas class of JavaFX can be used the same as Processing or canvas of JavaScript.

GraphicContext

まずCanvasクラスが持っているGraphicContextを取得します.

First, get GraphicContext of Canvas class.

GraphicsContext ctx = canvas.getGraphicsContext2D();

fill, stroke

図形の輪郭を描く時はGraphicContextクラスの"stroke"で始まるメソッドを使用します. また図形の塗り潰す時はGraphicContextクラスの"fill"で始まるメソッドを使用します.

To draw outline of shape, use GraphicContext class's methods starts with "stroke". To paint all over a shape, use GraphicContext class's methods starts with "fill".

ctx.strokeOval(p.getX() - 5, p.getY() - 5, 10, 10)

path

パスを描く時はまずGraphicContextクラスのbeginPathメソッドでパスを開始します. そしてmoveTo, lineTo, quadraticCurveTo, bezierCurveTo, arc, arcTo, appendSVGPath, rect, closePathなどのメソッドでパスを作ります. パスの内側を塗り潰す時はGraphicContextクラスのfillメソッド, パスの輪郭を描く時はstrokeメソッドを使用します.

To generate path, firstly use beginPath method of GraphicContext class. After that, construct path with moveTo, lineTo, quadraticCurveTo, bezierCurveTo, arc, arcTo, appendSVGPath, rect or closePath methods. Finally, if you want to paint all over the region inside the path, use fill method of GraphicContext class. If you want to draw a outline of the path, use stroke method.

ctx.beginPath();
ctx.moveTo(points.get(0).getX(), points.get(0).getY());
points.stream().skip(1).forEach(p -> ctx.lineTo(p.getX(), p.getY()));
ctx.stroke();

clear

キャンバスをクリアする時はGraphicContextクラスのclearRectメソッドを使用します.

To clear the canvas, use clearRect method of GraphicContext.

ctx.clearRect(0, 0, canvas.getWidth(), canvas.getHeight());

サンプル Sample

クリックされた点を直線で繋ぐプログラムです.

The following program draws lines between clicked points.

f:id:Jumpaku:20160729145906p:plain

View.fxml

<?xml version="1.0" encoding="UTF-8"?>

<?import javafx.scene.canvas.*?>
<?import java.lang.*?>
<?import java.util.*?>
<?import javafx.scene.*?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>

<AnchorPane id="AnchorPane" prefHeight="200" prefWidth="320" xmlns:fx="http://javafx.com/fxml/1" xmlns="http://javafx.com/javafx/8" fx:controller="canvassample.ViewController">
   <children>
      <Canvas fx:id="canvas" height="200.0" onMouseClicked="#handleClick" width="320.0" />
   </children>
</AnchorPane>

Main.java

package canvassample;

import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.stage.Stage;

public class Main extends Application {
    @Override
    public void start(Stage stage) throws Exception {
        Parent root = FXMLLoader.load(getClass().getResource("View.fxml"));
        stage.setScene(new Scene(root));
        stage.show();
    }

    public static void main(String[] args) {
        launch(args);
    }
}

ViewController.java

package canvassample;

import java.net.URL;
import java.util.LinkedList;
import java.util.List;
import java.util.ResourceBundle;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.geometry.Point2D;
import javafx.scene.canvas.Canvas;
import javafx.scene.canvas.GraphicsContext;
import javafx.scene.input.MouseEvent;

public class ViewController implements Initializable {
    private final List<Point2D> points = new LinkedList<>();
    
    @FXML
    private Canvas canvas;
    
    @FXML
    synchronized private void handleClick(MouseEvent e) {
        points.add(new Point2D(e.getX(), e.getY()));
        GraphicsContext ctx = canvas.getGraphicsContext2D();
        ctx.clearRect(0, 0, canvas.getWidth(), canvas.getHeight());
        
        points.forEach(p -> ctx.strokeOval(p.getX() - 5, p.getY() - 5, 10, 10));
        
        ctx.beginPath();
        ctx.moveTo(points.get(0).getX(), points.get(0).getY());
        points.stream().skip(1).forEach(p -> ctx.lineTo(p.getX(), p.getY()));
        ctx.stroke();
    }
    
    @Override
    public void initialize(URL url, ResourceBundle rb) {
    }    
    
}

恋と友情の常識(No Fight, No Relationship)

"クラスメイトが殺されたの"
私は友人と捜査を始めた.
極端な信条, 矛盾した証言.
真実に辿り着いた時...
交差した思想が1本の線となる.

"One of my class mates was merdered..."
I started investigation with my friend.
Suspects have contradictory statements and strong faiths.
When the truth is out,
their thoughts are integrated.

ゲーム情報

  • タイトル : 恋と友情の常識
  • 読み : こいとゆうじょうのふぁいと
  • 作者 : Jumpaku
  • ジャンル : 説法系推理アドベンチャ
  • プレイ時間 : 30分程度
  • プラットフォーム : Windows
  • リリース : 2016年 7月 24日
  • 言語 : 日本語
  • 開発環境 : WOLF RPGエディター

Detail

  • Title : 恋と友情の常識(No Fight, No Relationship)
  • Pronunciation : Koi to yujo no fight
  • Written by : Jumpaku
  • Genre : Adventure or Mystery with sermons
  • How long : About 30 minutes
  • Platform : Windows
  • Released : July 24, 2016
  • Language : Japanese
  • Tool : Wolf RPG Editor

遊び方 How to play

ゲームを始めるには"Game.exe"を実行して下さい. 詳しい操作方法は"README.txt"を読んで下さい.

Execute Game.exe to start the game. Read README.txt to see detail.

ウディコンにエントリ

このゲームをウディコン2016に提出しました.

Applied to Wodicon

I applied this game to Wodicon 2016.

ヴァージョン Version

  • v1.4 : README.txtの誤字を修正 Fixed a misprint in README.txt.
  • v1.3 : 誤植の修正 Fixed a misprint
  • v1.2 : 致命的な矛盾を修正 Fixed the fatal contradiction.
  • v1.1 : ウディコンに提出する前にサイズを軽量化 Lightening the data size before sending to Wodicon
  • v1.0 : 最初の完成品 Initial product

リンク Links

Visal Studioでコマンドライン引数を使う Use command line argumants on Visual Studio

はじめに Introduction

プログラム実行時にコマンドライン引数を付ける事があります. コマンドライン引数を使うとmain関数に引数を渡す事ができます. また, リダイレクトで標準入出力をキーボードからファイルへと切り換える事ができます.

Visual Studioコマンドライン引数を設定する方法を紹介します.

You can execute a program with some command line arguments. With command line arguments, you can give parameters to the main function and change standard input/output into file from keyboard, in other words, redirection.

This article explains how to set command line arguments on Visual Studio.

問題 What's the problem ?

Visual Studioでプログラムをコンパイルし, 実行する時, 多くの場合実行ボタンや"ctrl"+"F5", "F5"で行うと思います. コマンドライン引数を設定したい場合どこに入力すれば良いのか, 最初私は分かりませんでした.

To compile and execute, usually we use execution button, or press "ctrl"+"F5", or "F5". When you must set command line arguments, where do you set them?

解決策 The Solution

Visual Studioコマンドライン引数を設定する方法は次の通りです.

  1. "プロジェクト"メニュー --> "プロパティ"を開く
  2. "構成プロパティ" --> "デバッグ"を選択
  3. "コマンドライン引数"の項目にプログラムに渡すコマンドライン引数やリダイレクションを追加する

The following is how to set command line arguments on Visual Studio.

  1. Open "Project" --> "Properties"
  2. Select "Configuration Properties" --> "Debug"
  3. Enter command line arguments or redirection you want to add into "Command line arguments".

Visual Studio 2015で確認 Test the above on Visual Studio 2015

標準入力をSampleInput.txtへ, 標準出力をOutputForSampleInputへと切り換えます. SampleInput.txtの内容とmain関数に渡されたコマンドライン引数をOutputForSampleInput.txtに出力します.

Command line arguments to add changes standard input to SampleInput.txt from keyboard and changes standard output to OutputForSampleInput.txt. Program outputs contens of SampleInput.txt and given command line arguments.

追加するコマンドライン引数 Command line arguments to add

What I want to give to main <"SampleInput.txt" >"OutputForSampleInput.txt"

プログラムのソースコード Source code of the program

#include<iostream>
using namespace std;

int main(int argc, char *argv[]){

    cout << "command line arguments : ";
    for (int i = 0; i < argc; ++i) {
        cout << argv[i] << " ";
    }
    cout << endl;

    int a, b;
    cin >> a >> b;
    cout << "sample input : " << a << " " << b;
}

SampleInput.txt

10 89

OutputForSampleInput.txt

command line arguments : C:\YourProjectFolder\x64\Debug\ProgramName.exe What I want to give to main 
sample input : 10 89

OutputForSampleInput.txtを見ると成功していることが確認できます. OutputForSampleInput.txt shows success.

感想 Thoughts

Visual Studio競技プログラミングの問題を解く時などに標準入出力をファイルに切り換えるとデバッグが楽になると思いました.

I thought that changing standard I/O to files makes debugging the source code of programming contest easy.

参考 Bibliography

便利なSTL Useful STL

概要 Abstract

ACM-ICPCに向けて練習する中で便利だった, 又は便利そうだったSTLをまとめました. STLC++の標準ライブラリで様々な機能が詰め込まれております. 今回まとめたのはその中でも特に便利だと思ったものです.

I sammarized useful STL for programming contest like ACM-ICPC. STL is C++ standard template library which contains valiable functions. In this article, the most useful things of them are summerized.

目次

Lambda, Container, Algorithm

ラムダ式は関数です. 次のように書きます.

[](引数の型 引数名){ 処理; }

Lambda is a function. You can write as follows.

[](Type arg){ doSomething; }

ラムダ式は関数内で定義することができます. 変数に代入することができます. 呼び出しは()を使用し, 引数があれば()に入れます.

You can write Lambda in any function. You can assign Lambda to argument. To call Lambda function, use () with arguments.

#include<iostream>
#include<string>
using namespace std;

int main(void){
    auto greeting = [](string name){
        cout << "My name is " + name + "." << endl;
    };
    greeting("Jumpaku");
    // My name is Jumpaku.

    double average = [](double a, double b) {
        return (a + b) / 2.0;
    }(28.3, 10.89);
    cout << average << endl;
    // 19.595
}

コンテナとは要素の集まりです. list, vector, array, map, set, ...などがあります.

アルゴリズムはコンテナに対する様々な便利関数です. アルゴリズムの関数はイテレータを通してコンテナを操作します. アルゴリズムで使用する条件や処理, 比較などはラムダ式などを使って指定します.

Container is collection of elements like list, vector, array, map, set...

Algorithm is operations for containers. Algorithm functions operate container with iterator. Specifying conditions, operations, or comparators by Lambda, you can use algorithm functions.

入出力 Input and Output

cin, cout

cinを使うと入力が楽です. また簡単な出力はcoutが楽です.

With cin, you can get any input easily. cout is for simple output.

#include<iostream>
using namespace std;

int main(void){
    int n;
    double x;
    char c;
    cin >> n >> x >> c; // 3 1.66 A
    cout << n << " " << x << " " << c << endl; // 3 1.66 A 
}

printf

出力形式が複雑な場合はcoutよりprintfの方が使い易いかもしれません.

If output format is complex, printf is easier than cout.

#include<iostream>
using namespace std;

int main(void){
    printf("%-15s : %02d%02d", "4 digits time", 14, 9);
    // 4 digits time   : 1409
    printf("%-15s : %04x", "hexadecimal", 1089);
    // hexadecimal     : 0441
    printf("%-15s : %+.3lf %+.3lf", "decimal point", 10.89, -2.837870822);
    // decimal point   : +10.890  -2.837
}

コンテナ Container

vector, list

素数が予め決まっているならvectorの方が良いです. vectorは[]で添字を使って要素にアクセスできます.

If the number of elements is decided, you should use vector.

#include<iostream>
#include<vector>
using namespace std;

int main(void){
    int n;
    cin >> n;
    vector<int> is(n);
    for(int i = 0; i < n; ++i){
        cin >> is[i]
    }
}

素数が不明ならlistの方が良いです.

If the number of elements is unknown, you should use list.

#include<iostream>
#include<list>
using namespace std;

int main(void){
    list<int> is;
    int tmp;
    while(cin >> tmp){
        is.push_back(tmp);
    }
}

for_each, sort, reverse

for_eachはコンテナの要素に同じ処理を施します.処理はlambdaなどで渡します.

sortはデフォルトで昇順でソートします.ソート順はlambdaなどで指定できます.

reverseはコンテナの要素の並びを逆にします.

for_each executes specified action for each element of container. You can specify the action with lambda.

sort sorts elements by specified order. You can specify the order with lambda. Default order is ascending order.

reverse reverses elements of the container.

#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;

int main(void){
    vector<int> is = { 1, 0, 8, 9, 2, 8, 3 };

    for_each(is.begin(), is.end(), [](int const &i){
        cout << i << ",";
    });
    cout << endl;
    // 1,0,8,9,2,8,3,

    sort(is.begin(), is.end(), [](int const &a, int const &b){ return a > b; });
    for_each(is.begin(), is.end(), [](int const &i){
        cout << i << ",";
    });
    cout << endl;
    // 9,8,8,3,2,1,0,

    reverse(is.begin(), is.end());
    for_each(is.begin(), is.end(), [](int const &i){
        cout << i << ",";
    });
    cout << endl;
    // 0,1,2,3,8,8,9,
}

iota, transform, copy_if

iotaは指定された値からインクリメントしながら連続した値を生成し, コンテナに入れます.つまりrangeの生成です.

transformはコンテナの各要素を指定された法則で変換します. 変換法則はlambdaなどで指定します.

copy_ifは入力コンテナに含まれる要素の中で指定された条件を満たす要素のみを出力コンテナにコピーします. 条件はlambdaなどで指定します.コピー後は出力コンテナをリサイズしましょう.

iota generates range. From specified start value, incrementing repeatedly, iota generates values.

transform transforms values of input container by specified function and copies them to output container. Transformation function can be specified by lambda.

copy_if copies elements of input container which satisfy specified condition to output container. The condition can be specified by lambda. You should resize output container after copying.

#include<iostream>
#include<vector>
#include<algorithm>
#include<numeric>
using namespace std;

int main(void){
    vector<int> range(10);

    iota(range.begin(), range.end(), 0);
    for_each(range.begin(), range.end(), [](int const &i){
        cout << i << ",";
    });
    cout << endl; // 0,1,2,3,4,5,6,7,8,9,

    vector<int> squared(range.size());
    transform(range.begin(), range.end(), squared.begin(), [](int cost &i){
        return i * i;
    });
    for_each(squared.begin(), squared.end(), [](int const &i){
        cout << i << ",";
    });
    cout << endl; // 0,1,4,9,16,25,36,49,64,81,

    vector<int> evens(squared.size());
    auto copiedEnd = copy_if(squared.begin(), squared.end(), evens.begin(), [](int const &i){
        return i%2 == 0;
    });
    evens.resize(distance(evens.begin(), copiedEnd));
    for_each(evens.begin(), evens.end(), [](int const &i){
        cout << i << ",";
    });
    cout << endl; // 0,4,16,36,64,
}

find_if, max_element, min_element

find_ifはコンテナに含まれる要素の中で最初の条件を満たす要素のイテレータを返します.条件はlambdaなどで指定します.

max_elementはコンテナに含まれる要素の中で最後の最大の要素のイテレータを返します.

min_elementはコンテナに含まれる要素の中で最後の最小の要素のイテレータを返します.

find_if returns the iterator of the first element which satisfies specified condition. The condition can be specified by lambda.

max_element returns the iterator of the last maximum element of the container.

min_element returns the iterator of the last minimum element of the container.

#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;

int main(void){
    vector<int> is = { 1, 0, 8, 9, 2, 8, 3 };

    auto firstEven = find_if(is.begin(), is.end(), [](int const &i) {
        return i % 2 == 0;
    });
    cout << *firstEven << endl; // 0

    auto max = max_element(is.begin(), is.end());
    cout << *max << endl; // 9

    auto min = min_element(is.begin(), is.end());
    cout << *min << endl; // 0 
}

all_of, any_of, none_of, count_if

all_ofはコンテナの要素の全てが指定された条件を満たす場合真を返します. 条件はlambdaなどで指定します.

any_ofはコンテナの要素のどれか1つ以上が指定された条件を満たす場合真を返します. 条件はlambdaなどで指定します.

none_ofはコンテナの要素のどれもが指定された条件を満たさない場合真を返します. 条件はlambdaなどで指定します.

cout_ifはコンテナに含まれる要素の中で指定された条件を満たす要素を数え上げます. 条件はlambdaなどで指定します.

all_of returns true if all elements of the container satisfy specified condition. The condition can be specified by lambda.

any_of returns true if any elements of the container satisfy specified condition. The condition can be specified by lambda.

none_of returns true if none elements of the container satisfy specified condition. The condition can be specified by lambda.

count_if counts the number of elements which satisfy specified condition. The condition can be specified by lambda.

#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;

int main(void){
    vector<int> is = { 1, 0, 8, 9, 2, 8, 3 };
    auto isEven = [](int const &i) {
        return i%2 == 0;
    };
    bool any =  any_of(is.begin(), is.end(), isEven);
    cout << any << endl; // 1

    bool all = all_of(is.begin(), is.end(), isEven);
    cout << all << endl; // 0

    bool none = none_of(is.begin(), is.end(), isEven);
    cout << none << endl; // 0

    int count = count_if(is.begin(), is.end(), isEven);
    cout << count << endl; // 4
}

remove_if

remove_ifは指定された条件を満たす要素をコンテナの後ろに集め, 集めた要素の最初のイテレータを返します. コンテナから完全に取り除くにはeraseを使います. 条件はlambdaなどで指定します.

remove_if collects elements which satisfy specified condition, puts them to back of the container, and returns the iterator of first element of them. To erase them, you must use erase. The condition can be specified by lambda.

#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;

int main(void){
    vector<int> odds = { 1, 0, 8, 9, 2, 8, 3 };
    for_each(odds.begin(), odds.end(), [](int const &odd) {
        cout << odd << endl;
    });
    // 1,0,8,9,2,8,3,

    auto removedEnd = remove_if(odds.begin(), odds.end(), [](int const &i) {
        return i%2 == 0;
    });
    odds.erase(removedEnd, odds.end());

    for_each(odds.begin(), odds.end(), [](int const &odd) {
        cout << odd << endl;
    });
    // 1,9,3,
}

文字列 String

string

stringのコンストラクタで文字列リテラルからstringを生成できます.

findでテキスト文字列に含まれるパターン文字列の検索ができます.findはパターン文字列が見つかった場合そのパターン文字列の先頭文字のテキスト文字列内での添字を返し, 見つからなかった場合string::noposを返します.

[ ]で添字を使った文字へのアクセスができます.

substrで部分文字列を取得できます.1つ目の引数が部分文字列の先頭の添字, 2つ目の引数が部分文字列の長さです.

+, +=で文字列の結合, 追加ができます.

c_strでchar配列の文字列を取得できます.

sizeで文字列の要素数を取得できます.

<, <=, >, >=, ==, !=などで辞書順の比較ができます.

With constructor of string, you can make string from string literal.

With find, you can find pattern in the text. find returns index of first element of pattern if pattern exists; otherwise find returns string::nopos.

With [], you can access to a character with index.

With c_str, you can get string of char array.

With size, you can get size of the string.

With <, <=, >, >=, ==, or !=, you can compare strings by lexical order.

#include<iostream>
#include<string>
using namespace std;

int main(void){
    string s = "Jumpaku's blog";

    auto beginOfPaku = s.find("paku");
    cout << s[0] << s[1] << s[2] << s.substr(beginOfPaku, 4) << endl;
    // Jumpaku

    s += " is interesting.";
    printf("%s\nsize : %u\n", s.c_str(), s.size());
    // Jumpaku's blog is interesting.
    // size : 30

    string s1 = "aaa", s2 = "aaaa", s3 = "aba", s4 = "abb" , s5 = "abb";
    cout << (s1 < s2 && s2 < s3  && s3 < s4 && s4 == s5) << endl;
    // 1
}

to_string, stoi, stod

to_stringは数値を文字列に変換します.

stoi, stodは文字列をintやdoubleの数値に変換します.

to_string converts numerical value into string.

stoi or stod converts string into int or double value.

#include<iostream>
#include<string>
using namespace std;

int main(void){
    string s1 = to_string(1089);
    string s2 = to_string(-283);
    cout << "1089 - 283 = " << (stoi(s1) + stoi(s2)) << endl;
    // 1372

    double d1 = stod("-123.456");
    double d2 = stod("987.654");
    cout << "d1 + d2 = " + to_string(d1 + d2) << endl;
    // 864.198000
}

stringstream

sstreamを使うとcinやcoutと同じような使い方で文字列と数値の変換ができます.

With stringstream, you can canvert between numerical value and string like cin or cout.

#include<iostream>
#include<string>
#include<sstream>
using namespace std;

int main(void){
    double a, b;
    stringstream("1089.283 283.1089") >> a >> b;
    cout << a + b << endl;
    // 1372.39

    stringstream ss2;
    string s1, s2, s3;

    ss2 << 123 << " " << 456 << " " << 789;
    ss2 >> s1 >> s2 >> s3;
    cout << s1 + s2 + s3 << endl;
    // 123456789
}

順列

next_permutation

要素が昇順に並んだコンテナに対して, falseが返るまで繰り返しnext_permutationを呼ぶと, 全ての順列を列挙することができます.

To enumerate all permutation, apply naxt_permutation to sorted container by ascending order until next_permutation return false.

#include<iostream>
#include<string>
#include<vector>
#include<algorithm>
using namespace std;

int main(void){
    string s = "abc";
    do {
        cout << s << endl;
    } while (next_permutation(s.begin(), s.end()));
    // abc
    // acb
    // bac
    // bca
    // cab
    // cba

    vector<int> is = { 1, 2, 3 };
    do {
        cout << is[0] << is[1] << is[2] << endl;
    } while (next_permutation(is.begin(), is.end()));
    // 123
    // 132
    // 213
    // 231
    // 312
    // 321
}