2013年04月30日

海賊とよばれた男

こんにちは、松下です。

先日、本屋大賞が発表されました。
本屋大賞は数ある文学賞の中でも、一番ユーザー(読者)に近い大賞とも言われている賞で
「全国書店員が選んだ いちばん!売りたい本」をキャッチコピーとして掲げているそうです。

過去の本屋大賞は、映画化されているのも多く、
タイトル名を耳にしたことがある人も多いかと思います。

■過去の本屋大賞作品
 2012年「舟を編む」
 2011年「『謎解きはディナーのあとで』」
 2010年「天地明察」


さて、今年2013年の本屋大賞は、
「海賊とよばれた男」 百田 尚樹 (著)
でした。

ここまで本屋大賞の事をさも訳知り顔で書きましたが、
今まで本屋大賞の本、というものを読んではいませんでした。
先日たまたまTVで本屋大賞のニュースを見ていた際に、
「海賊とよばれた男」が史実を元にした小説、ということに興味を覚え、調べたのです。

「海賊とよばれた男」は、出光興産の創業者である出光佐三をモデルにした小説です。
勿論、小説なので脚色はあると思いますが、
自分が生まれる以前に、大きな組織を作って、様々な荒波を乗り越えた起業家の話、
というものに強く惹かれました。

ヘキサドライブも50名を超えてきて、少しずつ『組織』を意識せざるを得なくなってきています。
ですので、最近、先達(せんだつ)はどうしているのか、という所に私も非常に興味があるのです。

勿論、小説を全てまるっと参考にするわけにはいきませんが、
スタッフに対する想いや、仕事に対する姿勢、誇りなどは、色々な事を考えるきっかけになります。

「海賊とよばれた男」は、私の予想以上に熱い話で、
出張中の新幹線の中で小説を読んでいたのですが、その生き様に、思わず目頭が熱くなりました。もうやだ〜(悲しい顔)


勿論、組織を〜というだけでなく、戦後日本を牽引した私たちの上の年代の方々がどう頑張ったか、という事を知ることで、
私たちが目の前の困難に立ち向かうパワーを貰える本かと思いますので、皆さんも是非読んでみては如何でしょうか。


posted by 管理人 at 18:48 | 書籍紹介

2013年04月26日

インバスケット思考

お久しぶりです、ナカムラです。
突然ですが、インバスケットという言葉をご存じでしょうか?


インバスケットとは、限られた時間内でより多くの成果を出すための考え方を養うトレーニングです手(グー)
インバスケットのトレーニングでは、架空の立場になりきり、制限時間内に多くの案件を高い精度で処理する事を課題とした問題が用意されています。
具体的には、ある切羽詰まったビジネスシーンの設定が説明され、その状況での最適な判断を選択肢から選ぶ形式で進んでいきます。

元々は、アメリカ空軍飛行機で活用されていた教育ツールがルーツ、との事です。
士官学校で得た知識を、実際に応用できるかどうかをテストするツールとして活用されていました。

先日、これについて書かれた本を読みましたので、紹介したいと思います本


20130426_book2.png



みなさん、職場や学校の中で何らかの判断をする時、次のような事が原因で判断ミスをした経験は無いでしょうか?

・情報を充分集めずに判断してしまう
・とにかく判断を急ぐ
・対策を1つしか用意しない
・周りへの根回しや配慮が足りない

あるいは、何かを決断するとき「とりあえず」とか「一応」という言葉を沿えて行動に移す事はないですか?
その言葉と共に行った決断は、充分な検討がなされていない判断である可能性が大きいですふらふら


インバスケット問題を解いていく事により、自分の判断プロセスには何が不足しているのか?という事がわかるようになってきます手(グー)
具体的には、判断の際に必要とされる以下の力が充分発揮できているかどうかを測ることができます。
・優先順位設定力
・問題発見力
・問題分析力
・創造力
・意志決定力
・洞察力
・組織活用力
・当事者意識
・ヒューマンスキル(他人への配慮)

例えば、10分しか時間の無い状況で、10通の未読メールがある場合、あなたならどう処理しますか?
締め切りギリギリの企画書にミスを発見した場合、どのように対応しますか?


一般的なインバスケット問題は、設定と判断状況がもっと詳細に説明された形式で出題されています。
本書はそれに加え、登場人物のキャラクターが一貫して設定されているので、よりその状況をイメージしやすく、実際の判断に近い選択が出来るのではないかと思いますぴかぴか(新しい)
また、インバスケットの問題に対する、他のユーザーの回答率をネットで閲覧出来るサービスが用意されています。
実は、インバスケット問題の回答には、絶対的な正解というものはありません。
模範解答は用意されていますが、むしろその結論に至るプロセスを重視します目
たとえ正答を選んでいても、その答えに至る経緯に誤りがあれば、正解とは言えないのです。
ですので、回答率の低い答えを出した人の意見は、それはそれで参考になったりもするのですグッド(上向き矢印)


2010-10-14-0.png


私自身、実際に本に載っていた40問の出題を解いてみました。
判断が容易なものもあれば、なかなか答えが出ないものもありましたあせあせ(飛び散る汗)
判断に時間が掛かる問題のジャンルから、自分が苦手とする判断の傾向が掴めてきます。

本格的にインバスケットのトレーニングを積んだ人は…
・仕事の優先順位を付けることができ、時間に余裕が生まれた。
・表面的ではなく、本質的な問題を解決出来るようになった。
・目先のことや、自分のことだけでなく、全体的な立場で俯瞰的な判断が出来るようになった。
・判断の精度が上がり、自分の判断に自信が付くようになった。

という感想を持つようになるそうです。

多くの作業を抱えて、一日をあたふたと終えてしまうような方、是非ご一読下さい手(パー)
私も、もう一度読み返してみますexclamation×2


posted by 管理人 at 15:44 | 書籍紹介

2013年04月25日

月日が経つのは

おはようございます。平尾ですわーい(嬉しい顔)
突如寒い日があったりしますが、少しずつ暖かくなって来ましたね晴れ
暖かい日は近所の靭公園に行って散歩、なんていうのも気持ちがいいものですかわいい
20130425_06.JPG

***


それにしても本当に月日が経つのは早いsoonもので、
もう今年の3分の1が終わろうとしています時計
以前はこんな状態↓だった本棚も
E69CACE6A39A.jpg


今やこんな状態にexclamation
20130425_01.jpg  20130425_00.jpg

もう入りきらなくなるふらふらと思ったら
20130425_02.jpg

一気に拡張!
こうして設備が大きくなっていくと、
日々成長しているヘキサドライブを感じられて実に嬉しいものですわーい(嬉しい顔)ぴかぴか(新しい)


ちなみに、もう本ですらないこんなものから
20130425_04.jpg

こんなものまで
20130425_03.jpg

コーヒーガムを食べているボストン・テリア犬
20130425_05.jpg



ゲームで遊ぶことも、マンガを読むことも、面白いものを研究するためexclamation×2
面白いものを作り、ユーザーの皆さんに楽しんでいただくと同時に、
自身も、ヘキサドライブも成長させていきたいと思いますわーい(嬉しい顔)

posted by 管理人 at 10:00 | about ヘキサ

2013年04月24日

コードレビュー。そして、Phabricator

こんにちは、タマキです。

ソフトウェアの品質を高めるために、開発にコードレビューを取り入れている話はよく耳にします 耳

コードレビューを簡単に言えば、『あるソースコードに対して、作者とは別の人(and/or ツール)がチェックを行うこと』、になるでしょうか。

形態としても様々あり、
 ・新人のソースコードに絞って、会議室などで先輩が集まって、レビュー
 ・VCSで、コード内にコメントを挿入しコミット。対象者はそのコメントを見て修正しコミット
など。

また、ペアプログラミングをしているというところもあるかと思います。


以前では、このコードレビューを行うために、多くのリソースが消費されていました ふらふら

例えば、以前のMicrosoftでは必ず
 1.コードを書き、単体テスト
 2.旧ソースとのdiffをチームメンバーに配り,メールベースでレビュー
 3.レビューは1行1行細かく行う
 4.全員がOKと判断したら、再度テストを行いコミット
といったことを行なっていたとのこと。

「レビューを必ず行う」というところは、とても見習うべき点ですね わーい(嬉しい顔)

ですが、『diffを配り、メールベースでレビュー』というところが、今では効率的でない感じがします。


これを効率的に行う目的で、コードレビューツールといったものがあります ひらめき

現在では、有名な会社はもちろん、OSSも含めた多くの開発でコードレビューツールが導入され、品質の向上と効率化が図られています。
(有名なところでは、Google, Microsoft, Facebook, Twitter, VMware, Dropbox, Quora, ...など)

ツールも、『Web上でレビューを行う』といったものが増えてきました。

ヘキサドライブでも、レビュー自体の恩恵を受けつつ、レビュー時間の削減や効率化を狙い、コードレビューツールを利用しています パンチ

このツールを用いたコードレビューの基本的な流れは、
 1.ソースコードを追加・修正・削除(複数のソースファイルもok)
 2.コードレビューツールにアップ
  ソースコードで変更があった部分が色付けでわかりやすく表示される
 3.設定したレビュワー(複数人ok)が添削し、OK/NGなどを設定。コメント(行単位でも可)なども追記
  もちろん、ツール上だけでなく、口頭などでも相談や提案などが行われます。
  レビュワー以外の人がコメントなどをするのもok。
 4.OKならコミットし、クローズ



そして、ヘキサのいくつかのプロジェクトでは、Phabricator(http://phabricator.org/)を使用しています。 手(チョキ)

Phabricatorを選択した理由を、いくつか挙げると、
 ・主要なVCSに対応している(Git, Subversion, Mercurial)
 ・主要なクライアントに対応している(Mac, Linux, Windows)
 ・導入時にPhabricator自身のソースコードをあまりいじらなくても良い
  初めに検証したものは、ソースコード内部をいろいろ書き換えてやっと動いたという状態。。。
  機能的にも不満ではあったが、それを抜きにしても、バージョンアップなどで追いかけるにはメンテナンスコストが高かった。。。
 ・レビューをブラウザで行うことができ、差分の箇所がわかりやすい。ソース一行に対しコメントを挿入することできる
 ・レビュー履歴が残る(レビューされるコードを修正しアップしなおしても、以前のものも残りつつ、アップしなおしたものも確認できる)
 ・UTF-8対応されている
でしょうか。

もちろん気になる点もありましたが。。


Phabricatorだけでなく、様々なコードレビューツールが存在しますので、要件・導入コスト・習得コスト、そして好みも含め、合うものを選択すれば良いと思います。

個人的には、GitHubのPull Requestは好みです わーい(嬉しい顔)

posted by 管理人 at 17:40 | 研究・開発

2013年04月23日

四次元世界?

GWは長野への家族旅行を計画しているえーきちです新幹線

最近の大阪では、休みの日になると
天気が崩れる雨ことが多いような気がしていましたが
今週末は全国的に良い天気で、お出かけ日和のようですね晴れ

部屋では積みゲーが恨めしく睨みつけている様な気がしないでもないですが
気にしないようにしておきますダッシュ(走り出すさま)

***

さて、今回は最近見つけた要チェックなPCゲームをご紹介したいと思います。


Steamにて販売中の「Antichamber」というタイトルなのですが
独特のビジュアルと高難易度のパズル要素をうまく織り合わせてあり
海外のレビューでも絶賛されている作品ですぴかぴか(新しい)


特にストーリーというものはないのですが
各所にイラストが書かれた黒いパネルが配置されており
それを調べることで読めるヒントとひらめきひらめきを頼りに
複雑怪奇な迷路を突き進みます。


このゲームの特徴の一つであるビジュアルは
白と黒をベースとしつつ、要所には赤や青など鮮やかに彩られたポイントがあり
明確に「何かがあるぞexclamation」と思わざるを得ないシンプルな配色になっていますが
そのシンプルなビジュアルを活かした「トリックアートのような世界」が
プレイヤーを混乱の渦に巻き込んでいきます台風

「特定の方向から覗かないと現れない通路」や
「同じところを何回も回り続けないと現れない出口」など
常識に囚われていては気付けないような
不思議なギミックが随所にちりばめられていますがく〜(落胆した顔)


これらの要素に加え、所々に出てくる「目」を模したシンボルや
無機質な画面なのに、まるで森の中にいるかのような環境音が
ミステリアスな雰囲気に拍車をかけてきて
知らず知らずの内に、マウスを持つ手が汗ばんでくること必至exclamation×2


回りくどく詩的とも取れるヒントと共に
「あーでもないこーでもない」とこねくり回しているうち
ふっと解法が降りてきた瞬間には、誰しも「ドヤァッ」という顔をしていることでしょう。

様々な「常識」を超えたギミックが取り入れられたこの作品に。
ゲームはもっと自由である」ということを改めて教えられたような感覚でした手(チョキ)

***

日に日にゲーム製作におけるハードルが低くなり
「Antichamber」のような「尖った」タイトルもたくさんリリースされる昨今ですが
私も負けないように、新しい遊びを提供していきたいと思いますexclamation×2

posted by 管理人 at 19:06 | ゲーム

2013年04月22日

ご明察!

えーきちから「天地明察」の原作小説を借りていたのですが読み終わる前にDVDの方を観てしまいました…シラッチです。

先人の知恵や好奇心に驚かされた作品でした。目
算額絵馬(江戸時代の日本で、額や絵馬に数学の問題や解法を記して、神社や仏閣に奉納したもの)の存在をこの作品で初めて知ったのですが、なんと、1900年代のノーベル賞受賞科学者の研究と同じことが約100年も前の江戸時代に算額として書かれていたりしていたそうです。


さて、知恵や好奇心、と言えばクイズですよねexclamation&question(無理やりか…)
最近プレーしている、クイズがテーマとなっているスマホアプリを紹介したいと思います。


『クイズRPG 魔法使いと黒猫のウィズ』
iOS版:https://itunes.apple.com/jp/app/id621106129
Android版:https://play.google.com/store/apps/details?id=jp.colopl.quizwiz

クイズに答えて敵を倒し、カードを育成していくRPGゲームです。
敵モンスターへの攻撃(クイズ)毎に、敵味方の属性の相性を考慮して攻撃対象を選択したり、クイズのジャンル自体を選択するため、毎ターンどう攻めるべきか長考しがちになってしまいます。
また、他のプレイヤーとのトーナメント戦も楽しめます。
レベルの低いうちは勝ち抜けやすいのですが次第に周りのプレイヤーのレベルも上がっていくのでなかなか歯ごたえがあります。パンチ


『冒険クイズキングダム』
iOS版:https://itunes.apple.com/jp/app/mao-xiankuizukingudamu-han/id560442729?mt=8
Android版:https://play.google.com/store/apps/details?id=com.kayac.quizkingdom

もうひとつは冒険クイズキングダム、こちらもクイズに答えてモンスターを倒し、冒険を進めていくクイズRPGです。
択一の問題だけでなく、複数正解が存在する問題があるのが特徴的かと思いました。
単純にクイズの正解率だけでなく、複数正解の存在する問題を織り交ぜる事で難易度のバリエーションが広がっていると思います。ぴかぴか(新しい)


それぞれ通勤の合間等に少しずつプレーして楽しんでいますが周りに出題できるくらいやりこんでみたいと思いますexclamation
興味のある方は試されてみては如何でしょうか。
それではまた〜手(パー)

posted by 管理人 at 21:43 | ゲーム

2013年04月19日

経路探索アルゴリズム

なんと ドラゴンが おきあがり
なかまに なりたそうに こちらをみている!
なかまに してあげますか?

>はい
 いいえ

ドラゴンが なかまに くわわった!

・・・

そんなこんながありまして、ヘキサドライブの一員となりましたるんるん
はじめまして、ドラゴンですグッド(上向き矢印)

ヘキサドライブは志の高い人が多く、それに刺激されて僕も負けじとレベルアップを目指す毎日です手(グー)
より良いコンテンツを作っていけるよう、頑張っていきたいと思います。


さて、少し前に大阪メンバーで集まってお花見をしていましたが、同時期に東京メンバーもお花見をしましたかわいい
それの場所取りで皆を待っている時間に「Rasende Roboter」というボードゲームをしたのですが、一言で言うとゴールまでの最短経路を探すゲームで、プログラマ3人でプレイしたために本気の戦いを繰り広げてしまいましたexclamation
とても面白いボードゲームなので、興味を持たれた方は是非プレイしてみて下さい。

経路探索といえば、ゲームでも敵キャラのAIなどで実装されますねひらめき
今回は探索アルゴリズムの中でも割とポピュラーな A* を紹介しようと思います。

A*の概要に関してはこちらを参照して下さい。
A*の特徴としては、単純に全ての経路を調べていくのではなく、よりゴールに近いと推測される方を優先して調べることにより、評価回数を減らすことができる点ですね。
以下の条件下でA*を実装してみました。

・移動は上下左右のみ
・隣接ノード間の移動コストは常に1
・マップの左上端のノードをスタートとし、右下端のノードをゴールとする


マップデータ(MapData.h)

namespace Map
{
// マップデータ(0:壁、1:通路)
static const int DATA[] = {
1,0,1,1,1,1,1,1,0,1,
1,0,1,0,1,0,1,1,1,1,
1,1,1,0,1,0,1,0,0,1,
1,0,0,1,1,1,1,1,0,1,
1,0,1,1,0,0,1,1,0,1,
1,1,0,1,1,1,1,1,0,1,
0,1,0,1,0,1,0,0,0,0,
0,1,0,1,1,0,1,1,1,1,
0,1,0,1,1,1,1,1,0,1,
1,1,0,0,1,0,1,1,0,1,
};

// マップサイズ
static const int WIDTH = 10; // 幅
static const int HEIGHT = 10; // 高さ

// スタート地点
static const int START_X = 0;
static const int START_Y = 0;

// ゴール地点
static const int GOAL_X = WIDTH - 1;
static const int GOAL_Y = HEIGHT - 1;
}

…ちょっとわかりにくいですね。
マップはこんな感じです。

■■■■■■■■■■■■


■■
■■
■■

■■■■■■■
■■
■■
■■
■■■■■■■■■■■■

main.cpp

#include <functional>
#include <iostream>
#include <vector>
#include <queue>
#include <memory>
#include "MapData.h"

//===========================================================================
// ノードクラス
//===========================================================================
class Node
{
public:
//-----------------------------------------------------------
//! @name 初期化
//-----------------------------------------------------------
//@{

Node(int posX, int posY)
: _pParentNode(nullptr)
, _posX(posX)
, _posY(posY)
, _costFromStartNode(0)
, _costToGoalNode(0)
{}

//@}
//-----------------------------------------------------------
//! @name setter/getter
//-----------------------------------------------------------
//@{

Node& SetParentNode(Node* pNode) { _pParentNode = pNode; return *this; }
Node* GetParentNode(void) const { return _pParentNode; }

Node& SetPosX(int posX) { _posX = posX; return *this; }
int GetPosX(void) const { return _posX; }

Node& SetPosY(int posY) { _posY = posY; return *this; }
int GetPosY(void) const { return _posY; }

Node& SetCostFromStartNode(int costFromStartNode) { _costFromStartNode = costFromStartNode; return *this; }
int GetCostFromStartNode(void) const { return _costFromStartNode; }

Node& SetCostToGoalNode(int costToGoalNode) { _costToGoalNode = costToGoalNode; return *this; }
int GetCostToGoalNode(void) const { return _costToGoalNode; }

int GetTotalCost(void) const { return _costFromStartNode + _costToGoalNode; }

//@}
//-----------------------------------------------------------
//! @name operator
//-----------------------------------------------------------
//@{

bool operator == (Node node)
{
return (this->_posX == node._posX && this->_posY == node._posY);
}

void operator = (Node node)
{
this->_pParentNode = node._pParentNode;
this->_posX = node._posX;
this->_posY = node._posY;
this->_costFromStartNode = node._costFromStartNode;
this->_costToGoalNode = node._costToGoalNode;
}

//@}

private:
Node* _pParentNode; // 親ノード
int _posX; // X座標
int _posY; // Y座標
int _costFromStartNode; // スタートノードからの最小コスト
int _costToGoalNode; // ゴールノードまでの最小コスト
};

typedef std::shared_ptr<Node> NodePtr;
typedef std::vector<NodePtr> NodePtrVector;

namespace {
//---------------------------------------------------------------------------
// 壁判定
//! @param [in] posX X座標
//! @param [in] posY Y座標
//! @return 壁ならtrue
//---------------------------------------------------------------------------
bool IsWall(int posX, int posY)
{
if (posX < 0 || Map::WIDTH <= posX) return true;
if (posY < 0 || Map::HEIGHT <= posY) return true;
return (Map::DATA[posX + posY * Map::WIDTH] == 0);
}

//---------------------------------------------------------------------------
// ゴールまでの推定コストを計算
//! @param [in] posX X座標
//! @param [in] posY Y座標
//! @return ゴールまでの距離
//---------------------------------------------------------------------------
int CalcCostToGoalNode(int posX, int posY)
{
return std::abs(Map::GOAL_X - posX) + std::abs(Map::GOAL_Y - posY);
}

//---------------------------------------------------------------------------
// ゴールまでの推定コストを計算
//! @param [in] node ノード
//! @return ゴールまでの距離
//---------------------------------------------------------------------------
int CalcCostToGoalNode(const Node& node)
{
return CalcCostToGoalNode(node.GetPosX(), node.GetPosY());
}
}

//---------------------------------------------------------------------------
// スタートアップ
//---------------------------------------------------------------------------
int main()
{
//------------------------------------------------------------
// 変数定義
//------------------------------------------------------------

NodePtrVector openList;
NodePtrVector closeList;

//------------------------------------------------------------
// ラムダ式を用いた関数定義
//------------------------------------------------------------

// Node位置比較用関数
auto compareNodeByTotalCost = [](NodePtr pNode1, NodePtr pNode2) -> int
{
return pNode1->GetTotalCost() > pNode2->GetTotalCost();
};

// リスト内に含まれているかどうかの判定用関数
auto isInNodeList = [](NodePtrVector& list, const NodePtr& node) -> NodePtr
{
for (NodePtrVector::iterator it = list.begin(); it != list.end(); ++it)
{
NodePtr nodeItem = (*it);
if (*node == *nodeItem)
{
return nodeItem;
}
}
return nullptr;
};

//------------------------------------------------------------
// A*のアルゴリズム
//------------------------------------------------------------

// スタートノード
NodePtr pStartNode(new Node(Map::START_X, Map::START_Y));
int startNodeCostToGoalNode = CalcCostToGoalNode(*pStartNode);
pStartNode->SetCostToGoalNode(startNodeCostToGoalNode);

// ゴールノード
NodePtr pGoalNode(new Node(Map::GOAL_X, Map::GOAL_Y));

// オープンリストから取り出す
openList.push_back(pStartNode);

while (true)
{
// オープンリストが空なら検索失敗
if (openList.empty())
{
std::cout << "探索失敗" << std::endl;
exit(1);
}

// 最小コストのノードをオープンリストから取り出す
std::sort(openList.begin(), openList.end(), compareNodeByTotalCost);
NodePtr pBaseNode = openList.back();
openList.pop_back();

// ゴールノードと一致したら検索終了
if (*pBaseNode == *pGoalNode)
{
*pGoalNode = *pBaseNode;
break;
}

// 取り出したノードをクローズリストに移す
closeList.push_back(pBaseNode);

// 隣接ノードをチェック
// 今回は上下左右のみ
for (int dy = -1; dy <= 1; ++dy)
{
for (int dx = -1; dx <= 1; ++dx)
{
// 同位置判定
if (dx == 0 && dy == 0) continue;

// 斜めを考慮しない
if (dx != 0 && dy != 0) continue;

// 隣接ノード位置
int pAdjacentNodePosX = pBaseNode->GetPosX() + dx;
int pAdjacentNodePosY = pBaseNode->GetPosY() + dy;

// 壁判定
if (IsWall(pAdjacentNodePosX, pAdjacentNodePosY)) continue;

// 隣接ノードの各コスト
int adjacentNodeCostFromStart = pBaseNode->GetCostFromStartNode() + 1; // 親から子への移動コストは1
int adjacentNodeCostToGoalNode = CalcCostToGoalNode(pAdjacentNodePosX, pAdjacentNodePosY);

// 隣接ノード
NodePtr pAdjacentNode(new Node(pAdjacentNodePosX, pAdjacentNodePosY));
pAdjacentNode->SetParentNode(pBaseNode.get())
.SetCostFromStartNode(adjacentNodeCostFromStart)
.SetCostToGoalNode(adjacentNodeCostToGoalNode);

NodePtr pSearchedNode = nullptr;

// オープンリストに含まれているか
pSearchedNode = isInNodeList(openList, pAdjacentNode);
if (pSearchedNode)
{
// オープンリストにあったノードより隣接ノードのコストが小さければ、オープンリストのノードを上書き
if (pAdjacentNode->GetTotalCost() < pSearchedNode->GetTotalCost())
{
*pSearchedNode = *pAdjacentNode;
}
continue;
}

// クローズリストに含まれているか
pSearchedNode = isInNodeList(closeList, pAdjacentNode);
if (pSearchedNode)
{
// クローズリストにあったノードより隣接ノードのコストが小さければ、クローズリストから削除してオープンリストに追加
if (pAdjacentNode->GetTotalCost() < pSearchedNode->GetTotalCost())
{
std::remove(closeList.begin(), closeList.end(), pSearchedNode);
openList.push_back(pAdjacentNode);
}
continue;
}

// どちらにも含まれていなければオープンリストに追加
openList.push_back(pAdjacentNode);
}
}
}

//------------------------------------------------------------
// 結果
//------------------------------------------------------------

// ゴールノードから親ノードを辿ることで、スタートノードまでの経路が算出される
Node* pNode = pGoalNode.get();
while (true)
{
std::cout << "X:" << pNode->GetPosX() << ", Y:" << pNode->GetPosY() << std::endl;

if ((pNode = pNode->GetParentNode()) == nullptr)
{
break;
}
}
}

結果は以下の通りになりました。
無事に最短経路を通ることができてますね手(チョキ)

■■■■■■■■■■■■
■*■***
■*■*■*■
■***■*■■■
■■**
*■■
■*
■■■*■■■■■■
■■■****■
■■■*****■*■
■■■*■
■■■■■■■■■■■■


それではまた次回に晴れ

posted by 管理人 at 14:03 | プログラミング

2013年04月18日

ヘキサ・フットサル部 発足!

今年の花粉は3〜7ばいィィィダッシュ(走り出すさま)



今の所、花粉症とは無縁の

う〜ふ〜ふ〜、ぼ〜く、オサえもんですドコモポイント

さて、デスクワークをするにも、ゲームを作るにも、ゲームをやるにも、
何をしようにもまず始めに用意しないといけないのが、自分のこれ!カラダですパンチ
何といってもカラダが資本ですダッシュ(走り出すさま)

というわけで、日頃の運動不足を解消すべく、発足させました。

ヘキサドライブ・フットサル部サッカー

現在の所属部員数は、なんと4人

まだ1チームを編成することが出来ません…ふらふら
なので、現在は部員のお知り合いのフットサルにお邪魔させてもらってる状態ですあせあせ(飛び散る汗)

20130418_sal.jpg


私の球技の経験といえば学生時代のバスケットのみでサッカーは未経験でしたが

ウイニングイレブンを死ぬほどやっていた時期があり、イメージは完璧ですぴかぴか(新しい)

活動回数は今の所2回ですが、やってみると心にもカラダにも、そしてお仕事にもいいことずくめグッド(上向き矢印)

心身の健康の促進はもちろん

お邪魔している集まりが別のゲーム会社の方々ということもあり、ゲームのいろんな話をさせてもらって別の刺激にもなっていますゲーム
業界にお知り合いが増えることは自分にとってもすごくプラスです。
一つ一つの出会いを大切にしたいと思いますぴかぴか(新しい)

またチームスポーツなのでコミニケーションが活発になります。
部員の隠れた一面をみれたり、積極的に会話をするように!
先日は職場内での師弟関係による、アシスト&ゴールなんて漫画のような展開も!!

師匠「いけ、シュートだ!」
弟子「はい!うおおお!」
ゴール手(チョキ)
注:この会話は妄想です

これからもっと部員も増やして
活動の輪を広げていきたいと思いますexclamation
そのチームワークをプラスしていいゲーム作りにも生かしたいところです手(グー)

しかし個人的にはフットサルもすごく楽しいですが、
バスケ部も作りたいところですバスケットボール

「安西先生、バスケもしたいです…」
欲張りですか?そうですか…たらーっ(汗)

posted by 管理人 at 10:43 | 日記

2013年04月17日

ひとつひとつ着実に、意識を高くもちながら…

こんにちは!
最近、社内でよく心配されているイノウエですあせあせ(飛び散る汗)

というのも、先月から腰をひどく痛めてしまいふらふら
「よっこらしょ」の掛け声と共に立ったり座ったり、
腰に手を当てながら歩いていたりなど、
かなり痛々しい状態なので、みんな気遣ってくれます。。
優しい会社ですいい気分(温泉)


お医者さんにみてもらったところ、
最初は「椎間板症」と診断されました。
かなりの激痛で、常にイタタタと言っていた気がしますバッド(下向き矢印)

そして、しばらく経過した後、
腰の激痛はおさまってきたものの、
左半分の足が痛いというかしびれるというか…
そんな症状が出始めました。
こうなると、よく聞く「椎間板ヘルニア」の症状らしいです爆弾

幸いにもまだ症状は軽めなほうで、
お薬を飲んだりトレーニングをしながら様子を見ていく予定です。

トレーニング法に関して聞いたところ、
腹筋や背筋などではなく、
背筋をグーッと伸ばしたりグッド(上向き矢印)
おなかを丸めたりすればよいとの事でしたいい気分(温泉)
なんだか年齢とのギャップを感じずにはいられないのですがたらーっ(汗)
小さなことからコツコツと…が大事なのだと思います。


さて、ここで無理矢理ゲーム開発につなげますが・・・ひらめき

ゲーム開発でも、個人が対応する小さな部分は、
あまり大きな影響はないかもしれません。
自分が担当する箇所を使いやすくしたとしても、
他の所で不足していたら問題は解決しませんもうやだ〜(悲しい顔)
でも、全員が同じ方向に積み重ねていけば、
やがては大きな成果となっていきますグッド(上向き矢印)
少しの調整が集まる事で、大きな改善につながりますぴかぴか(新しい)

負担がかかって痛みにならないように気をつけつつ、
のびのびと良い方向に進んでいければと思いますわーい(嬉しい顔)

身体にも気をつけます…

posted by 管理人 at 18:59 | 日記

2013年04月16日

ネイティブコードとマネージドコードを同時に利用する方法

こんにちは。店長ですわーい(嬉しい顔)
暑い日と寒い日が繰り返してますが、
皆様は体調を崩してないでしょうか?

今日は、
ネイティブコードとマネージドコードを同時に使うテクニック
を紹介致します。

例えば、
C++でゲーム用の描画ライブラリを作ったあと、
”この描画ライブラリを使ってグラフィカルなツール作りたいなぁ・・・”
と思ったことは無いでしょうか?
そして実践してみると、
・WIN32APIが使いにくい。
・もっとリッチなGUIを使いたい。
・ツール部分だけはC#使いたい。

など頭を悩ませた人も少なくないと思いますもうやだ〜(悲しい顔)

そういう時に役に立つかもしれないテクニックです手(チョキ)
あんまり詳細なこと書くと大変量になるので、要点以外省くことをご了承ください。

例として
・Windows環境
・VisualStudioでの開発
・C++で描画ライブラリ(graphics.dll)を作成(ネイティブコード)
・C#とxamlでクライアントウィンドウ部分を作成(マネージドコード)
・描画結果は青い背景と白い四角形のポリゴン

をやってみます。


C++描画ライブラリ側の設定
1,dllを作る
2,C#から機能を使うための関数を用意する
3,モジュール定義ファイル(.def)を用意する


1,ついて
ライブラリとして出力する形式をdllにしてください。

2,について
以下のような描画ライブラリのヘッダファイルがあり、
その機能をC#側で使ってみようと思います。

/**
* @brief レンダラークラス
*/
class CRenderer
{
public:
// コンストラクタ
CRenderer();
// デストラクタ
~CRenderer();

// 初期化
bool Initialize();
// 終了処理
void Finalize();

// 活性化
bool Activate();
// 非活性
void Deactivate();

// ウィンドウの設定
void SetWindow( HWND i_wnd );
// 描画
void Render();

private:
HWND m_hwnd; // ウィンドウ
HDC m_hdc; // デバイスコンテキスト
HGLRC m_hglrc;
};


ところが、このままではC#からC++クラス内の関数を使うことができません。

そこで、このクラスの機能を呼び出すための関数を用意いたします。
ヘッダファイル

#ifdef __cplusplus
extern "C"
{
#endif __cplusplus

// インスタンスの生成
CRenderer* NewRenderer();

// インスタンスの削除
void DeleteRenderer(CRenderer* p);

// 初期化
bool InitializeRenderer(CRenderer* p);

// 終了処理
void FinalizeRenderer(CRenderer* p);

// ウィンドウの設定
void SetWindowRenderer(CRenderer* p,HWND i_hwnd);

// 描画処理
void RenderRenderer(CRenderer* p);

#ifdef __cplusplus
}
#endif __cplusplus


ソースファイル

CRenderer* NewRenderer(){
return new CRenderer();
}

void DeleteRenderer(CRenderer* p){
delete p;
}

bool InitializeRenderer(CRenderer* p){
return p->Initialize();
}

void FinalizeRenderer(CRenderer* p){
p->Finalize();
}

void SetWindowRenderer(CRenderer* p,HWND i_hwnd) {
p->SetWindow( i_hwnd );
}

void RenderRenderer(CRenderer* p) {
p->Render();
}

機能としてはクラスのインスタンスを渡して、
各関数を呼び出すだけです。
このようにクッションを置くことで
C#側から呼び出すことができるようになります。
手(グー)

3,について
dllの関数をエクスポートするためのモジュール定義ファイルを用意します。

; graphics.def : DLL のモジュール パラメータを宣言します。

LIBRARY "graphics"

EXPORTS
; 明示的なエクスポートはここへ記述できます

NewRenderer ;インスタンス生成
DeleteRenderer ;インスタンス破棄

InitializeRenderer ;初期化
FinalizeRenderer ;終了

SetWindowRenderer ;ウィンドウの設定

RenderRenderer ;描画


__declspecキーワードを使う方法でも同じ事ができますが、
個人的な好みで別ファイルとしております。

このファイルをプロジェクトのプロパティ→リンカー→入力→モジュール定義ファイル
に設定しておきます。拡張子は.defです。

これでビルドが完了したら、C++ライブラリ側の準備は完了ですグッド(上向き矢印)


C#クライアントウィンドウ側の準備
1,C++のCRendererの機能を呼び出す用意
2,ウィンドウのハンドルを設定


1,について
まず、graphiscs.dllの関数を呼び出せるようにします。
C#側のCRendererクラス

/**
* レンダラー
*/
class CRenderer
{
[DllImport("./dll/graphics.dll", CallingConvention = CallingConvention.Cdecl)]
private static extern IntPtr NewRenderer();
[DllImport("./dll/graphics.dll", CallingConvention = CallingConvention.Cdecl)]
private static extern void DeleteRenderer(IntPtr p);
[DllImport("./dll/graphics.dll", CallingConvention = CallingConvention.Cdecl)]
private static extern bool InitializeRenderer(IntPtr p);
[DllImport("./dll/graphics.dll", CallingConvention = CallingConvention.Cdecl)]
private static extern void FinalizeRenderer(IntPtr p);
[DllImport("./dll/graphics.dll", CallingConvention = CallingConvention.Cdecl)]
private static extern void SetWindowRenderer(IntPtr p, IntPtr hwnd );
[DllImport("./dll/graphics.dll", CallingConvention = CallingConvention.Cdecl)]
private static extern void RenderRenderer(IntPtr p);
// コンストラクタ
public CRenderer()
{
}

// 生成
public void New()
{
m_renderer = NewRenderer();
}

// 破棄
public void Delete()
{
DeleteRenderer( m_renderer );
}

// 初期化
public bool Initialize()
{
return InitializeRenderer( m_renderer );
}

// 終了
public void Finalize()
{
FinalizeRenderer(m_renderer);
}

// ウィンドウの設定
public void SetWindow(IntPtr hwnd)
{
SetWindowRenderer(m_renderer, hwnd);
}

// ウィンドウの設定
public void Render()
{
RenderRenderer(m_renderer);
}

private IntPtr m_renderer = IntPtr.Zero;
}


2,について
描画を行うウィンドウのハンドルを取得し、CRendererクラスに設定します。
タイマーイベントを使っての描画の呼び出しも例として記載しておきます。
ウィンドウのサイズなどの定義はMainWindow.xamlに記載されているものとします。

// MainWindow.xaml の相互作用ロジック
public partial class MainWindow : Window
{
private CRenderer renderer;
private DispatcherTimer timer;

// コンストラクタ
public MainWindow()
{
InitializeComponent();
}

// 初期化処理
private void WindowSourceInitialized(object sender, EventArgs e)
{
// ウィンドウハンドル取得
IntPtr hWnd = new WindowInteropHelper(this).Handle;

// レンダラーの生成
renderer = new CRenderer();
renderer.New();
renderer.SetWindow(hWnd);
renderer.Initialize();

//タイマー
timer = new DispatcherTimer();
timer.Tick += new EventHandler(DispatcherTimerTick);
timer.Interval = new TimeSpan(0, 0, 0, 0, 16); // 16msecで描画
timer.Start();
}

// タイマーイベント
private void DispatcherTimerTick(object sender, EventArgs e)
{
if (renderer != null)
renderer.Render();
}

// サイズ変更処理
private void WindowSizeChanged(object sender, SizeChangedEventArgs e)
{
// if (renderer != null)
// renderer.SizeChanged(e.NewSize);
}

// 後片付け
private void WindowClosed(object sender, EventArgs e)
{
renderer.Finalize();
renderer.Delete();

if (renderer != null)
// {
// renderer.Dispose();
renderer = null;
// }
}
}


WindowSourceInitialized関数内で
・ウィンドウハンドルの取得。
・CRendererクラスの準備。
・タイマーの準備を行なっております。

また、描画はタイマーイベントで、
DispatcherTimerTick関数内で行なっております。


一応MainWindow.xamlも記載しておきます。








今回はあまり大事な部分ではありませんが、
このファイルを編集するだけで簡単にウィンドウの設定ができます。


これでC#側も準備が整いましたグッド(上向き矢印)


実行結果は以下のようになります。

20130416_native_and_managed.jpg

上記のような手順を踏むことで、
C++などのネイティブコードで作ったライブラリを利用しつつ、
マネージドコードの強みを生かしてGUIを作ることなどができます。


最後に、
現在でも速度が求められるコアな部分はネイティブコードが主流です。
ただ、マネージドコードの強みを利用することでツールなどの開発効率は非常に良くなります。
プログラム言語も適材適所で使っていけるようになるとことが大事ですねるんるん

上記サンプルの実行ファイルとdllファイルを置いておきますので、おためしください。
サンプル



posted by 管理人 at 16:21 | プログラミング