CodeIQ MAGAZINECodeIQ MAGAZINE

大人気ダンジョンシリーズ!そろばんのダンジョンLV1~LV2の解説+最短コード発表 #javascript

2014.12.26 Category:CodeIQ問題解説・リーダーボード Tag:

  • 18
  • このエントリーをはてなブックマークに追加
soroban_badge

大人気ダンジョンシリーズ!!
今回は「そろばんのダンジョン」でした。
問題の出題者である柳井政和さんによるL1~LV2の解説記事です。

上位者(ベスト20)のコードのご紹介もあります。
by CodeIQ運営事務局

■ そろばんのダンジョン

出題者の柳井政和です。「そろばんのダンジョン」問題にたくさんの方に挑戦いただき、ありがとうございます。今回は、以下のような問題でした。

【問題】

正の整数iが与えられます。この数値を以下の表のような形式で変換します。

数字の1桁ごとに、0~9の値は「00, 01, 02, 03, 04, 10, 11, 12, 13, 14」の2桁の値に変換しなければなりません。

元の値 変換後の値
0 00
1 01
2 02
3 03
4 04
5 10
6 11
7 12
8 13
9 14
10 0100
11 0101
12 0102
13 0103
14 0104
15 0110
: :
99 1414
100 010000

【問題のコード】

function yourCode() {
    // windowおよびそのプロパティのいくつかを自動ノックアウト
    /* @knockoutWindow */

    // 問題のコード
    var arr = [];
    for (var i = 0; i < 1000; i ++) {
        arr.push(
            (function() {
                var $, jQuery, eval;
                var yourCode, arr;
                arguments.callee = null;

                // 答えを変数「r」に入れて戻す
                var r;
                【 入力欄(複数行可能) 】
                return r;
            }).apply({})
        );
    }
    return arr;
}

この問題は、レベルごとに禁止事項が増えていきます。そのポイントと、解答コードを、以下に掲載します。

■ レベル1解説

レベル1の禁止文字は、「$ jQuery eval this window top parent self frames document Function repeat caller \ 」です。多いように見えますが、それほど制限はありません。これらは、基本的に「eval」を封じるためのものです。普通にコードを書けば大丈夫です。

それでは、このレベル1の問題を解くには、どういった処理を行えばよいのでしょうか? 大まかな方針を以下に書きます。

方針A)
1. 与えられた数値から、各桁の数値を計算で取り出す。
2. 各桁の数値から、各桁の変換結果を求める。
3. 各桁の変換結果を文字列に結合する。

方針B)
1. 数値を文字列化して、先頭から1文字ずつ取り出す。
2. 取り出した1文字から、各桁の変換結果を求める。
3. 各桁の変換結果を文字列に結合する。

方針AとBの2種類を書きましたが、Bの方がコード量は圧倒的に短くなります。そして、Bの場合でも、1文字ずつの取り出し方によって、コード量が大幅に増減します。

というわけで、いくつかのパターンのコードを書いてみましょう。

方針A)数値から各桁を取り出す

何種類か書いてみます。基本の構造は全て同じですが、計算方法で文字数が増減します。do while 文のループは、変数「j」の計算結果(10で割って整数にする)が、0 になると終了します。

do while 文を利用しているのは、i の値が1桁の場合も処理を行なうためです。

// toStringを使い、5進数にする方法
// 先頭に「"0"」を足し、後ろ2文字を取り出す
r = "";
j = i;
do {
    k = j % 10;
    r = ("0" + k.toString(5)).substr(-2) + r;
} while (j = j / 10 | 0)
// 条件演算子を使い、分岐させる方法
r = "";
j = i;
do {
    k = j % 10;
    r = (k >= 5 ? "1" : "0") + (k % 5) + r;
} while (j = j / 10 | 0)
// 真偽値を数値に変換する方法
r = "";
j = i;
do {
    k = j % 10;
    r = "" + (k > 4) * 1 + (k % 5) + r;
} while (j = j / 10 | 0)
// 要素数1の配列を、他の値と結合すると文字列化する仕様を使った方法
r = "";
j = i;
do {
    k = j % 10;
    r = [+(k > 4)] + (k % 5) + r;
} while (j = j / 10 | 0)
// さらに演算子の優先順位を使用して短くする
r = "";
j = i;
do {
    k = j % 10;
    r = [k / 5 & 1] + k % 5 + r;
} while (j = j / 10 | 0)

方針B)先に文字列化:表を用意する

0から9までの数値を変換する表を用意しておき、配列の参照位置で、対応する値に変換します。

とてもシンプルな方法です。コードは非常に分かりやすく、すっきりとします。

下のコードでは、「00010203041011121314」を「match」を使い、2文字ずつの配列「[“00”, “01”, “02”, “03”, “04”, “10”, “11”, “12”, “13”, “14”]」に変換しています。

// 先に文字列化:表を用意する
r = "";
s = "" + i;
t = "00010203041011121314".match(/../g);
for (j = 0; j < s.length; j ++) {
    r += t[s[j]];
}

方針B)先に文字列化:「split」+「map」

「split」と「map」を使い、配列化して1文字ずつ処理します。最後に「join」で結合します。

このタイプの仲間として、「map」の代わりに「forEach」や「reduce」を使うコードもありました。

// 先に文字列化:「split」+「map」
r = ("" + i).split("").map(function(e) {
    return [e / 5 & 1] + e % 5;
}).join("");

方針B)先に文字列化:「replace」

文字列を1文字ずつ置換する方式です。こちらも、ロジック自体は、「split」+「map」と同じです。

// 先に文字列化:「split」+「map」
r = ("" + i).replace(/./g, function(s) {
    return [s / 5 & 1] + s % 5;
});

方針B)先に文字列化:for 文

for 文で、1文字ずつ取り出して計算していく方法です。for を使った形式では、一番オーソドックスな方法だと思います。この仲間には、while 文や、do while 文を使ったコードも含まれます。

// 先に文字列化:for 文
r = "";
s = "" + i;
for (j = 0; j < s.length; j ++) {
    c = s[j];
    r += [c / 5 & 1] + c % 5;
}

以下は、少し変則的な方法です。

存在しない文字列位置を参照した際に「undefined」になることを利用しています。文字列「”1″~”9″」だけでなく「”0″」も、空文字ではないので条件式内で真として扱われます(検証コード:console.log(“0″?”o”:”x”);)。

// 先に文字列化:for 文 2
r = "";
for (j = 0; b = ("" + i)[j++];) {
    r += [b / 5 & 1] + b % 5;
}

「j」を空文字で初期化すれば、さらに短くなります。空文字は、数値変数として加算すると「0」と見なされる仕様を使う方法です。そして、「i」を文字列化することで、処理を縮めます。

ついでに、for 文の波括弧も取ることで、さらに短くできます。スペースも取ってしまいましょう。こういった方法でも、短くできます。

// 先に文字列化:for 文(38文字)
for(i+=r=j="";b=i[j++];)r+=[b/5&1]+b%5

 また、for文を使った方法では、tails 様のコードが37文字と、最短でした。こちらは、「r」が初期化されていない場合は、「~+[r]」で空文字になる仕様を利用しています。

// tails 様(37文字)
for(x=i;r=[x/5&1]+x%5+[r],x=x/10|0;);

方針B)先に文字列化:for in 文

for in 文を使っても、1文字ずつ取り出すことが可能です。この場合は、for 文を使うよりも、若干短くなります。

for in 文では、「0, 1, 2, ……」といった、文字のどの位置を取り出すかの値が取れます。そのため、変数を初期化したり、インクリメントしたりする文字数が省けます。

// 先に文字列化:for in 文
r = "";
s = "" + i;
for (k in s) {
    c = s[k];
    r += [c / 5 & 1] + c % 5;
}

方針B)先に文字列化:for of 文

さらに、for of 文を使っても、1文字ずつ取り出すことが可能です。この場合は、for in 文を使うよりも、さらに若干短くなります。

for of 文では、「0文字目の文字, 1文字目の文字, 2文字目の文字, ……」といった、文字そのものの値が取れます。そのため、文字の位置を得るための変数を使わずに済み、文字数が節約できます。

問題には「解答の確認は Google Chrome で行います」と書いてありました。最新のChromeでは、この構文が通ります。

// for of 文
r = "";
for (c of "" + i) {
    r += [c / 5 & 1] + c % 5;
}

それ以外ですごかったコード

antimon2 様のコードが、すごかったです。

// antimon2 様
r=parseInt("1"+i,25).toString(5).slice(1)

■ 今回の問題の補足

今回の問題では、CodeIQのサイト上のライブラリの影響で、一部ブラウザで、for in文が動作しない問題が当初あり、急遽対策を取り、最終的にiframeで切り離す版を作ったという経緯があります(ライブラリが、prototypeに処理を追加していた影響で、for in文が期待通りの動きをしないという問題)。

そのため、最初の方に解答した方の中には、その方法を避けたせいで、文字数が増えてしまった方もいると思います。ご迷惑をおかけしてしまい、申し訳ありませんでした。改良した案内を問題ページに掲示していたのですが、気付かなかった方も多かったかと思います。

今後は、問題部分をprototype汚染から切り離した、iframe形式でいきたいと思います。

■ レベル1の上位者コード(20位~11位)

以下、20位から11位の方のコードです。いろんなコードが見たいと思いますので、同じ方のコードでも、順位に当てはめて掲載しています。

20位のコード(58文字)

// todaemon 様
for(r='',s=i+r,j=0;j<s.length;){r+=(0|s[j]/5)+''+s[j++]%5}

19位のコード(56文字)

// rotary-o 様
r='';(r+i).replace(/./g,function(c){r+=c<5?0+c:'1'+c%5})
// Mu 様
r=(i+'').replace(/./g,function(m){return m<5?0+m:m- -5})
// ymknjugg 様
r='';for(j=(m=r+i).length;j;r=''+(k>4|0)+k%5+r)k=m[--j];

18位のコード(55文字)

// しゃろ 様
r=([]+i).replace(/./g,function(a){return[a/5|0]+[a%5]})

17位のコード(53文字)

// しゃろ 様
r=([]+i).replace(/./g,function(a){return[a/5|0]+a%5})
// キャロットフレーク 様
r=i?"":"00";j=i;while(j)r=""+~~(j/5%2)+j%5+r,j=j/10|0
// spoa 様
r="";(r+i).replace(/./g,function(a){r=r+(a>4|0)+a%5})

16位のコード(51文字)

// キャロットフレーク 様
r=i?"":"00";for(j=i;j;j=j/10|0)r=""+~~(j/5%2)+j%5+r

15位のコード(50文字)

// おじけん 様
r="";a=i;do{r=""+(a/5|0)%2+a%5+r;a=a/10|0}while(a)

14位のコード(49文字)

// suppy193 様
r=i?"":"00";for(n=i;n;n=n/10|0)r=[n%10/5|0]+n%5+r
// alluser 様
for(r="",j=[i];j;r=[j%10/5|0]+j%10%5+r,j=j/10|0);
// orisano 様
for(c in s=(r="")+i)r+=[s[c]/5|0,s[c]%5].join("")
// Theodore 様
for(r='',n=i;!r||n;n=n/10|0)r=(0|n%10/5)+''+n%5+r

13位のコード(46文字)

// ciel 様
for(j=i,r=i?'':'00';j;j=j/10^0)r=[j/5&1]+j%5+r
// gmk 様
for(j=0,s=(r="")+i;k=s[j++];)r+=""+~~(k/5)+k%5

12位のコード(45文字)

// みけCAT 様
for(r="",b=i;r=""+~~(b/5)%2+b%5+r,b=b/10|0;);

11位のコード(44文字)

// kr7 様
a=[i];while(a)r=+(a%10>4)+[a%5]+[r],a=a/10|0
// gmk 様
for(j=0,s=(r="")+i;k=s[j++];)r=r+~~(k/5)+k%5
// silver789 様
r=""
for(s of i+"".split(""))r=r+[s/5|0]+s%5
// y azshe   様
r='';for(a in s=''+i)r=r+(s[a]/5|0)+(s[a]%5)

■ レベル1の上位者コード(10位~1位)

以下、10位から1位の方のコードです。いろんなコードが見たいと思いますので、同じ方のコードでも、順位に当てはめて掲載しています。

10位のコード(43文字)

// naoki_kp 様
j=i;for(r="";r=""+(j/5&1)+j%5+r,j=j/10|0;);
// しゃろ 様
r=[],d=r+i;for(n=0;a=d[n++];)r+=[a/5|0]+a%5

9位のコード(42文字)

// antimon2 様
r=parseInt("1"+i,25).toString(5).slice(1);
// tails 様
for(x=i,r="";r=(x/5&1)+(x%5+r),x=x/10|0;);

8位のコード(41文字)

// antimon2 様
r=parseInt("1"+i,25).toString(5).slice(1)
// k.hamada 様
for(r=j='';n=(i+'')[j++];)r=r+ +(n>4)+n%5
// alluser 様
for(r="",j=[i];j;j=j/10|0)r=[j/5&1]+j%5+r

7位のコード(40文字)

// naoki_kp 様
j=i;for(r="";r=[j/5&1]+j%5+r,j=j/10|0;);
// kr7 様
for(a=i;r=[a%10>4&1]+a%5+[r],a=a/10|0;);
// gmk 様
for(c in s=(r="")+i)r+=[s[c]/5|0]+s[c]%5
// Azicore 様
for(j=i,r='';r=[j/5&1]+j%5+r,j=j/10|0;);

6位のコード(39文字)

// ciel 様
i+=r='';for(x in i)r+=[i[x]/5&1]+i[x]%5
// rotary-o 様
for(i+=j=r='';c=i[j++];r+=c%5)r+=+(c>4)

5位のコード(38文字)

// rotary-o 様
for(i+=j=r='';c=i[j++];r+=c%5)r+=c>4|0

4位のコード(37文字)

// tails 様
for(x=i;r=[x/5&1]+x%5+[r],x=x/10|0;);
// ciel 様
for(x in i+=r='')r+=[i[x]/5&1]+i[x]%5

3位のコード(36文字)

// @iwamoto_takaaki 様
r='';for(j of ''+i)r+=''+(4<j)*1+j%5

2位のコード(33文字)

// silver789 様
r=""
for(n of i+"")r+=[n/5|0]+n%5
// こぅ 様
r="";for(a of i+r)r=r+(a/5|0)+a%5

1位のコード(30文字)

// kr7 様(最初に最短にたどり着きました)
for(a of""+i)r=[r]+(a>4&1)+a%5
// tails 様
for(d of''+i)r=[r]+[d/5&1]+d%5

■ レベル2解説

レベル2では新たに、「( ) { } 」の禁止文字が追加されています。これはループ文や関数の使用を禁止するという制限です。

そのため、ループで行なっていた計算を展開して書かなければなりません。各桁の処理の短さや、次の桁の計算のために値をどう格納するかで、コードの長さが決まります。

ちなみに、桁は3桁しかないので、べらぼうに長いコードにはなりません。

こちらは、コードをどう折りたたむかといった、細かいテクニックを競う内容になります。そのため、上位者のコードを直接見ていただくことにします。

■ レベル2の上位者コード(20位~11位)

以下、20位から11位の方のコードです。いろんなコードが見たいと思いますので、同じ方のコードでも、順位に当てはめて掲載しています。

20位のコード(91文字)

// みけCAT 様
s="01234";b=i/10|0;r=b>9?s[b/50|0]+s[b/10%5|0]:"";b?r+=s[b%10/5|0]+b%5:0;r+=s[i%10/5|0]+i%5

19位のコード(90文字)

// ciel 様
j=i
r=''+[j/5^0]%2+j%5
j=j/10^0
r=j?''+[j/5^0]%2+j%5+r:r
j=j/10^0
r=j?''+[j/5^0]%2+j%5+r:r

18位のコード(87文字)

// moveccr 様
var s=i+"";
r=[s[0]/5&1]+s[0]%5+[i>9?[s[1]/5&1]+s[1]%5+[i>99?[s[2]/5&1]+s[2]%5:""]:""];

17位のコード(86文字)

// iehn 様
j=i/100|0;k=j/5&1;r=j<1?"":k+""+j%5;j=i/10|0;k=j/5&1;r+=j<1?r:k+""+j%5;r+=i/5&1;r+=i%5

16位のコード(85文字)

// silver789 様
a=i/100|0
b=i%100/10|0
r=a>0?[a/5|0]+a%5:""
r+=i>9?[b/5|0]+b%5:r
r+=[i%10/5|0]+i%10%5

15位のコード(84文字)

// しゃろ 様
d=[]+i,r=[d[0]/5|0]+d[0]%5;r+=d[1]?[d[1]/5|0]+d[1]%5:"";r+=d[2]?[d[2]/5|0]+d[2]%5:""
// gmk 様
s=""+i;k=s[0];r=""+[k/5&1]+k%5;k=s[1];r=k?r+[k/5&1]+k%5:r;k=s[2];r=k?r+[k/5&1]+k%5:r

14位のコード(82文字)

// naoki_kp 様
j=i;r=""+[j/5&1]+j%5,j=j/10|0;j?[r=[j/5&1]+j%5+r,j=j/10|0]:0;j?[r=[j/5&1]+j%5+r]:0
// tails 様
a=i/5|0;b=a>>1;c=b/5|0;d=c>>1;e=d/5|0;r=d?""+e+d%5:"";r=b?r+c%2+b%5:r;r=r+a%2+i%5;

13位のコード(79文字)

// y azshe 様
s=''+i;a=s[0];b=s[1];c=s[2];r=[a/5|0]+a%5;b?r+=[b/5|0]+b%5:0;c?r+=[c/5|0]+c%5:0

12位のコード(78文字)

// しゃろ 様
d=[]+i,b=d[1],c=d[2],r=[d[0]/5|0]+d[0]%5+[b?[b/5|0]+b%5:""]+[c?[c/5|0]+c%5:""]

11位のコード(77文字)

// antimon2 様
s=""+i;b=s[1];r=[s[0]/5&1]+s[0]%5+[b?[b/5&1]+b%5+[s[2]?[s[2]/5&1]+i%5:""]:""]
// suppy193 様
b=i/10|0;a=b/10|0;r=a?[a/5|0]+a%5:"";r+=b?[b%10/5|0]+b%5:"";r+=[i%10/5|0]+i%5

■ レベル2の上位者コード(10位~1位)

以下、10位から1位の方のコードです。いろんなコードが見たいと思いますので、同じ方のコードでも、順位に当てはめて掲載しています。

というか、tails 様 無双です。1~5位までのコードが、tails 様です。

10位のコード(74文字)

// naoki_kp 様
r=[i>99?[i/500&1]+[i/100%5|0]:""]+[i>9?[i/50&1]+[i/10%5|0]:""]+[i/5&1]+i%5
// alluser 様
r=[i>99?[i/500&1]+[i/100%5|0]:""]+[i>9?[i/50&1]+[i/10%5|0]:""]+[i/5&1]+i%5

9位のコード(73文字)

// Azicore 様
i+='';a=i[1];b=i[2];r=[i[0]/5|0]+i[0]%5+[a&&[a/5|0]+a%5]+[b&&[b/5|0]+b%5]

8位のコード(71文字)

// ciel 様
r=[i/5&1]+i%5
j=i/10^0
r=j?[j/5&1]+j%5+r:r
j=j/10^0
r=j?[j/5&1]+j%5+r:r

7位のコード(69文字)

// rotary-o 様
i+='';c=i[1];r=[i[0]>4|0]+i[0]%5+[c&&[c>4|0]+c%5+[i[2]&&[i/5&1]+i%5]]

6位のコード(67文字)

// rotary-o様
j=i/10|0;k=j/10|0;r=[k?[k/5&1]+k%5:r]+[j?[j/5&1]+j%5:r]+[i/5&1]+i%5

5位のコード(64文字)

// tails 様
r=i*200-i%500*100-i%100*80-i%50*10-i%10*8-i%5;r='.'+i<.5?"0"+r:r

4位のコード(63文字)

// tails 様
r='.'+i<.5?'0':0;r+=i*200-i%500*100-i%100*80-i%50*10-i%10*8-i%5

3位のコード(62文字)

// tails 様
r='.'+i<.5&&'0';r+=i*200-i%500*100-i%100*80-i%50*10-i%10*8-i%5

2位のコード(61文字)

// tails 様
r=[i]<'5'&&'0';r+=i*200-i%500*100-i%100*80-i%50*10-i%10*8-i%5

1位のコード(59文字)

// tails 様
r=[[i]<[5]?0:r]+[[[i*2-i%500]+0-i%100*8-i%50]+0-i%10*8-i%5]

「[i]<[5]」で、文字列化して辞書順に比較しています。つまり、文字列化した1文字目のアスキーコード順なので、最初の1文字目が4以下なら true になります。その際は先頭に「”0″」を足しています。

その後の計算はややこしいので、数値の推移を確認する用のコードを掲載します。コンソールなどで実行すると、数値の推移が分かります。

for (var i = 0; i < 1000; i ++) {
    var a = i*2-i%500;  // 「0~499, 1000~1499」と推移
    var b = i%100*8;    // 「i」100周期で8ずつ上がり「0~792」
    var c = i%50;       // 「i」50周期で「0~49」を繰り返す
    var d = [a]+0-b-c;
        // 「[~]+0」で文字列結合(桁を1つ上げる)
        // 「[1]+0」なら「"10"」になる
        // 「0~49, 100~149, 1000~1049, 1100~1149,…」と推移


    var e = i%10*8;     // 「i」10周期で8ずつ上がり「0~72」
    var f = i%5;        // 「i」5周期で「0~4」を繰り返す
    var g = [[d]+0-e-f];
        // 「[~]+0」で文字列結合(桁を1つ上げる)
        // 「0~4, 10~14, 100~104, 110~114, 200~204,…」と推移

    console.log(i
        ,"d = [a]+0-b-c = [[" + a + "]+0" + "-" + b + "-" + c + "]"
        ,"→"
        ,"[[d]+0-e-f] = [[" + d + "]+0" + "-" + e + "-" + f + "]"
        ,"→"
        ,g);
}

■ 文字数の分布

今回の問題の文字数の分布をまとめておきます。

レベル1では、40~50の間に1つ、90~100の間に1つ山があります。解答を確認したところ、60文字以内であれば、かなりの上位者という感じでした。

レベル2では、100~110の間に山がありました。解答を確認したところ、100文字以内であれば、かなりの上位者という感じでした。

■ 最後に

CodeIQ運営事務局です。今後も、柳井さんの問題を掲載予定です。

ぜひご挑戦ください!
柳井さんの問題一覧

  • 18
  • このエントリーをはてなブックマークに追加

■関連記事

【謎解きプログラム】解像度に対応せよ!【dpi】解答と解説... 【謎解きプログラム】解像度に対応せよ!【dpi】 本問題は、「解像度に対応せよ!」というテーマで、プログラムにちなんだ謎を解くというものでした。 それでは以下、各問題とその解答を見ていきましょう。 問題のオープニング ある日、出社すると、あなたのPCのログイン画面に、謎の挑戦状が表示されてい...
【選択式問題】JavaScript検定RPG Array編 問題解説 #javascript... 今回の問題 今回の『JavaScript検定RPG』は『Array編』ということで、JavaScript のArrayについての問題が出題されました。 それでは以下、各問題とその解答を見ていきましょう。 問題1 配列を作る方法として適切でないのはどれ? new Array(0, 1, 2)...
【選択式問題】JavaScript検定RPG String編 問題解説 #javascript... 今回の問題 今回の『JavaScript検定RPG』は『String編』ということで、JavaScriptのStringについての問題が出題されました。 それでは以下、各問題とその解答を見ていきましょう。 問題1 文字列の特定の位置の文字を得る方法として、適切でないのはどれ? "ねこみみ"...
【選択式問題】JavaScript検定RPG ループ処理編 問題解説 #javascript... 今回の問題 今回の『JavaScript検定RPG』は『ループ処理編』ということで、JavaScript のループ処理についての問題が出題されました。 それでは以下、各問題とその解答を見ていきましょう。 問題1 for (var i = 0, s = ""; i < 5; i++) s +=...
【選択式問題】JavaScript検定RPG 条件分岐編──問題解説 #javascript... 今回の問題 今回の『JavaScript検定RPG』は『条件分岐編』ということで、JavaScript の条件分岐についての問題が出題されました。 それでは以下、各問題とその解答を見ていきましょう。 問題1 ifのあとに書き、条件に一致しない場合の処理を行う構文は何? elf dwarf ...
大人気ダンジョンシリーズ!IQのダンジョンの解説+最短コード発表 #javascript... IQのダンジョン 今回の ダンジョンは、以下のような問題でした。 【問題】 標準入力から得られる値は「」のような文字列です。この文字列を、配列として解釈した配列の各要素には、36進数(0,1,2~,x,y,z)の数値を表す文字列が入っています。 この配列の各要素を、36進数の数字として解釈し...

今週のPickUPレポート

新着記事

週間ランキング

CodeIQとは

CodeIQ(コードアイキュー)とは、自分の実力を知りたいITエンジニア向けの、実務スキル評価サービスです。

CodeIQご利用にあたって
関連サイト
codeiq

リクルートグループサイトへ