2010年1月25日月曜日

履歴書の書き方2

前回の続き。東京で就活を行っている時に滞在した友人宅で聞いたアドバイスまとめ。

結論は先に書く。「あなたの得意科目について書いてください」とあるなら「私の得意科目は○○です」と先に書いてしまうこと。何百枚も履歴書見てると、飽きるわ疲れるわでダラダラした文章を見ても何も伝わってこないそうな。何より履歴書書く本人が楽な気がしてきた。

履歴書を友人に見てもらい、疑問点を挙げてもらう。履歴書の精度も上がるし、面接対策になるそうです。客観的な視点って重要よね。

社会人に見てもらう。学生の視点と社会人の視点は全く違う。学生の視点だと色々「甘いなぁ」と思ってしまうそうだ。

仕事に対する前向きな気持ちが文章に表れているかチェック。どんなに大学や専門学校で勉強してきたからって、所詮は学生レベル。そんなことは会社もわかっている。今後の成長の見込みがあるかどうかを、履歴書でチェックする。安定志向とか言っちゃ駄目よ。

上京したらまずSuicaを作ろう

初めて東京行ってきました。人が多すぎて頭痛くなりましたが、交通網が発達しているところは本当に羨ましい。特にJRは、ほとんどの街にいけるんじゃねえかというくらい便利なので、電子マネーのSuicaは作っておくと良いでしょう。移動が格段に楽になります。




緑の窓口で2000円出せば、デポジット料500円+電子マネー1500円分が最初から入った状態で購入可能。毎回切符を買うわずらわしさと、行き先にあわせて料金を確認したりする手間から開放されます。

ちなみに不必要になった時には、カードを返せばデポジット金の500円は返却してもらえて安心。

JR九州のSUGOCA(Suicaのパチモン)と連携できればもっといいのですが、現在はそのような仕様にはなっていないようです。ちなみに関西にはICOCAというカードもあります。こういうのはなるべく統一してほしいんですがねぇ…。

2010年1月14日木曜日

wxWidgets事始め

いよいよレイトレーサをGUIアプリケーションとしてまとめることになった。どうせやるならクロスプラットフォームということで、開発にはwxWidgetsを使うことに。

とりあえず導入までに参考にしたサイトを列挙。
以上を参考にして作成したのが以下のアプリケーションだ。


中身は空のハリボテだが、C++でここまで楽にGUIアプリケーションが構築できるのには正直驚いた。オブジェクト指向を取り入れてあるのでJavaのSwingよろしく組みやすい。

2010年1月13日水曜日

C++で経路探索

事の始まりは某所のC#スレで見かけたこの記事。ちょこっと引用すると、
内容は、壁とスペースで構成された迷路が与えられたとき、スタート地点からゴール地点に至る最短経路を求めよ、というものです。
たとえば、S:スタート G:ゴール *:壁 $:解答の経路 としたとき、
**************************
*S* *                    *
* * *  *  *************  *
* *   *    ************  *
*    *                   *
************** ***********
*                        *
** ***********************
*      *              G  *
*  *      *********** *  *
*    *        ******* *  *
*       *                *
**************************
とのこと。ふむ、なかなか面白そうじゃない! 独りでやるのも寂しいので、学校の先生と競争してみることに。
001#include <iostream>
002#include <string>
003#include <fstream>
004#include <vector>
005 
006typedef unsigned char byte;
007typedef unsigned int uint;
008typedef std::vector<std::string> StringList;
009 
010using namespace std;
011 
012/**
013* 2次元配列の位置などを表す構造体
014*/
015struct POS{
016    uint x, y;
017};
018 
019//定数
020const char *fname = "dat.txt";//ファイルデータパス
021const byte WALL = -1;//壁を表す定数
022 
023//
024// 再帰的にスタートからゴールへ向かって最短距離を求める
025// @param now 現在位置
026// @param from 一つ前の位置
027// @param dat 書き換えるデータ配列
028// @param width データ配列幅
029// @param start スタート地点
030// @param goal ゴール地点
031// @return none
032//
033void SearchPath(
034                uint count,
035                const POS &now,
036                const POS &from,
037                byte *dat,
038                uint width,
039                const POS &start,
040                const POS &goal
041                )
042{
043    //再帰の終了をチェック
044    if(now.x == goal.x && now.y == goal.y){
045        dat[now.x+now.y*width] = count+1;
046    }
047 
048    //次に移動する座標を決定する
049    POS next[4] ={
050        {now.x, now.y-1},//上
051        {now.x, now.y+1},//下
052        {now.x-1, now.y},//左
053        {now.x+1, now.y},//右
054    };
055    for(uint i=0; i<4; ++i){
056        uint idx = next[i].x + next[i].y*width;//次に調べる位置
057 
058        //次の位置が壁なら調べない
059        if(dat[idx] == WALL){
060            continue;
061        }
062 
063        //次に調べる位置が既に調べてあり
064        //かつ、すでに最短パスが出ていたらこれ以上調べない
065        if(dat[idx] > 0 && dat[idx] < count){
066            continue;
067        }
068 
069        //現在の位置にこれまでの歩数を記録する
070        dat[now.x+now.y*width] = count;
071 
072        //次の経路を再帰的に調べる
073        SearchPath(count+1, next[i], now, dat, width, start, goal);
074    }
075}
076 
077//
078// ゴール地点からスタート地点へ向かって最短経路を描画する
079// @param sl 書き出す文字列リスト
080// @param now 現在位置への参照
081// @param start スタート地点
082// @param goal ゴール地点
083// @param dat ステップ数が記述されたデータ配列(壁は0xff)
084// @param width データ配列幅
085//
086void FindPath(
087              StringList *sl,
088              const POS &now,
089              const POS &start,
090              const POS &goal,
091              const byte *dat,
092              uint width
093              )
094{
095    //再帰打ち切りの条件
096    //すなわち、現在地がスタート地点なら終了
097    if(now.x == start.x && now.y == start.y){
098        return;
099    }
100 
101    //次に移動する座標を決定する
102    POS next[4] ={
103        {now.x, now.y-1},//上
104        {now.x, now.y+1},//下
105        {now.x-1, now.y},//左
106        {now.x+1, now.y},//右
107    };
108 
109    //現在のステップ数
110    uint nowStep = dat[now.x+now.y*width];
111 
112    for(uint i=0; i<4; ++i){
113        uint idx = next[i].x + next[i].y*width;//次に調べる位置
114 
115        //次の位置が壁なら調べない
116        if(dat[idx] == WALL){
117            continue;
118        }
119 
120        //次の位置が現在のステップ数より小さいときは
121        //再帰的に調べる
122        if(dat[idx] == nowStep-1){
123            //経路マークをつける
124            char mark = '$';
125            if(now.x == goal.x && now.y == goal.y){
126                mark = 'G';
127            }
128            sl->at(now.y).at(now.x) = mark;
129 
130            //次の経路を再帰的に調べる
131            FindPath(sl, next[i], start, goal, dat, width);
132            return;
133        }
134    }
135}
136 
137//
138//エントリポイント
139//
140int main(){
141    //
142    // テキストからデータを読み込んで配列に格納
143    //
144    std::fstream fs(fname);
145    StringList sl;
146    while(!fs.eof()){
147        string tmp;
148        getline(fs, tmp, '\n');
149        sl.push_back(tmp);
150    }
151 
152    //数値に変換して配列に格納
153    uint height = sl.size();//配列高さ
154    uint width = sl[0].size();//配列幅
155    byte *dat = new byte [width*height];//作業用配列
156 
157    POS start = {0,0};//スタート
158    POS goal = {0,0};//ゴール
159    POS now = {0,0};//現在地
160 
161    for(uint y=0; y<height; ++y){
162        for(uint x=0; x<width; ++x){
163            uint idx = x+y*width;
164            dat[idx] = 0;
165            switch(sl[y][x]){
166                case '*':
167                    dat[idx] = WALL;
168                    break;
169                case 'G':
170                    goal.x = x;
171                    goal.y = y;
172                    break;
173                case 'S':
174                    start.x = now.x = x;
175                    start.y = now.y = y;
176                    break;
177            }
178        }
179    }
180 
181    //
182    // 経路探索
183    // 上下左右に対して再帰的に検索をかける
184    //
185    SearchPath(0, start, start, dat, width, start, goal);
186 
187    //探索したパスを元に最短経路を描画する
188    FindPath(&sl, goal, start, goal, dat, width);
189 
190    //
191    //デバグ用表示
192    //
193    for(uint y=0; y<sl.size(); ++y){
194        cout << sl[y] << endl;
195    }
196 
197    //
198    //ファイル書き出し
199    //
200    ofstream ofs("out.txt");
201    for(uint y=0; y<sl.size(); ++y){
202        ofs << sl[y] << endl;
203    }
204    ofs.close();
205 
206    //あとしまつ
207    delete [] dat;
208    dat = 0;
209 
210    return 0;
211}
結果は惨敗。相手は1時間ちょっとで終わっていたのに対して、私は4時間かけてようやくといったところ。先生はPythonを使われていいたようです。てかこの手の問題でC++を使う時点でダメだろ俺…。Pythonなどの高級言語や、関数型言語ならもっともっと美しく簡潔に書けたでしょうね。とにかく自分の無能さが身に染みてわかった。くやしい!

自分のアホさにげんなりした問題でした。さて、寝よう(:D)┼─┤

2010年1月7日木曜日

履歴書の書き方

自分で調べたもの+学校の先生に指導していただいたものをまとめておく。参考程度に。

解説サイト
西暦と元号の対応
資格
略称
履歴書への記入
TOEIC
TOEIC公開テスト○○○点
C言語検定
サーティファイ主催 C言語プログラミング能力検定試験○級合格
AP
経済産業省 応用情報技術者試験合格
CGエンジニア検定
CG-ARTS協会主催 CGエンジニア検定試験○級合格

改ざんがないことを示すために無駄な隙間は作らない
×→   平成○○年  ○月   ○○市立    ○○中学校   卒業
○→平成○○年○月 ○○市立○○中学校卒業
住所について
現住所と帰省先が同じ場合でも、「同上」などと略さずにきちんと書くこと。

得意科目について
国語・数学などのいわゆる5教科以外でも、情報系の学校でプログラムの実習などがあればそちらを書いても問題ない(例:C言語)。
むしろIT系の業界を志望するならそこがアピールになる、とのこと。

趣味について
業種にもよるが、パチンコなどのギャンブル関係は避けたほうが吉。
面接で聞かれたときにちゃんと答えられるようなものを書く(まあ当然か)。読書と書いておきながら、本をほとんど読まない人などが多いそうだ。

下書きと清書
レイアウトなどは定規を使って丁寧に下書きを行うこと。
清書は細めの水性ボールペンを使用するほうがいい。
清書後の下書きを消しゴムで消すときは念のため1日はあける(失敗して悲惨な目にあった)。
個人的にお勧めなのはイラスト用のドローイングペン

std::fstreamでファイルサイズを取得

メタセコイア読み込みに関連して、std::fstreamからデータを読み込む際に必要なことのまとめ。
01#include <iostream>
02#include <fstream>
03 
04typedef unsigned int uint;
05const char *fname = "C:/hoge/piyo.txt";//ファイルパス
06 
07int main()
08{
09    using namespace std;
10 
11    ifstream fs(fname);//ファイルオープン。読み込み形式は指定なしのときはテキストモードになる。
12 
13    fs.seekg(0, fstream::end);//ファイル末尾を探す
14    uint eofPos = fs.tellg();//ファイル末尾インデクスを取得
15 
16    fs.clear();//先頭にもどるために一度clear()をかける。これをしないと次のseekg()でコケるときがある。
17 
18    fs.seekg(0, fstream::beg);//ファイル先頭に戻る
19    uint begPos = fs.tellg();//ファイル先頭インデクスを取得
20 
21    uint size = eofPos - begPos;//末尾-先頭でファイルサイズを計算
22 
23    char *buf = new char [ size ];//サイズ分の領域を確保
24    memset(buf, 0, size);//0クリアしておく
25 
26    fs.read(buf, size);//ファイル先頭からバッファへコピー
27 
28    fs.close();//ファイルを明示的に閉じてみる
29 
30    cout << buf << endl;//確認のため出力
31 
32    SAFE_DELETE_ARRAY(buf);//バッファを削除
33    return 0;
34}
基本は上記のとおり。

例外処理も入れるべきだが、使い方を間違えると正しく読み込めているのに例外が送出されてしまうので注意。
下記のリストに挙げた『std::ifstream::read()の使い方がツライ』の記事を参考されたい。
参考

新年の抱負など

いよいよ就職本番の年。悔いのない一年(実質半年もないわけだが)を過ごして次へのステップにつなげたい。

今月は中旬より会社説明会のために東京へ。 一次選考を行ってくれる会社もあるので、まずはその突破を図る。
ゲーム関連を受けつつ、IT企業へもエントリーしているので受ける。総合して6月までに内定が出れば上出来としよう。

資格はCG-ARTS協会主催のCGエンジニア検定1級合格を目指す。先月めでたく2級合格を果たせたので、今度は1級だ。
試験内容もこれまでの選択式から記述式へ移行するので、これまでのようにあいまいな理解では合格は難しいだろう。
同時に、実装経験の量がますます重要になってくると思われる。

依然不景気ということで暗い1年になりそうだが、気持ちだけでも明るく生きていきたいものだ。