任天堂 “驚き”を生む方程式
DS・Wiiの成功体験、その裏でどういう思考・試行がなされたか。
モノを作る中でどいういったことを考えて進んでいったかという物語は、読んでいて楽しく、刺激になる。
why→what→how
本自体で記載されていたわけではないけれど、Wiiができるまでの経過は、「検討→キーコンセプト設定→具体化」というサイクルになっているように見えた。
- 議論
- 「何で人はゲーム機に触らないのかな、何で人は逃げちゃうのかな」
- 「本当に据え置き型っているのか→Wiiはテレビにチャンネルを増やすような機械にしたい」
- キーコンセプト
- 「性能を追わない」
- 「お母さんに嫌われない」
- 「毎日何かが新しい」
- 実現
- 怖がられないワイヤレスリモコン
- ファミコンよりも小さな筐体
- 低電力の眠らないマシン
- 面積18.9mmの極小CPU
- 電力消費量9ワット/時間のWiiConnect24
何故なのかという点を議論し、キーコンセプトで方向性を切りだし、そして、どう実現するかという点でtry&errorを繰り返す。
描かれる風景は、「Why→What→how」と絵に描いたようなきれいなサイクルに見えた。
このサイクルに「とことんまで考える」というスタンスが補助線として引かれ、個々のフェーズがどれだけの深度で実現されているか、想起できるようになっている。
「私は、ゲーム作りそのものに、奥深さ、凄さみたいなものを感じるんです。ある1つのゲームを組み立てるということは、操作と遊びの構造を一体化させながら、何かのテーマ、コンセプトを貫いて延々と試行錯誤を繰り返すということ。膨大な可能性を追求して、究めるように収束させていく。そんな風に作れるものって、他にあまりないんじゃないかっと感じるんです。」
「1つのテーマについて、長くしつこく考え続けることが大切で、考え続けていることの蓄積の量が、ヒットを生んでいる部分というのもあるんだなと、私は思っています」
試作を積み重ね、時に捨て、また重ねる。ちゃぶ台返しとは、宮本の愚直に丁寧にソフトを作っていく姿勢を端的に映したもの。その精神は、結果として「ダメソフト」を排除し、世に質の高いソフトを送り続ける体制を築いたのである。
モチベーションの根幹
岩田社長のモチベーションの根幹が「喜んでもらいたい」という点にあると、しかもその起源が高校時代の友人という点が印象深かった。
岩田 人間はやっぱり、自分のやったことを褒めてくれたり喜んでくれたりする人がいないと木には登らないと思うんです。
この点、後段で示される、「うごメモ」で投稿を続けている小学生のメンタリティと、底で通じているのかなと思った。
「娯楽至上主義」のための物語
本自体は、任天堂の歴史を等間隔に俯瞰するというよりは、「ソフト体質」「娯楽至上主義」というコンセプトありきで物語が構築され、それを補強するための資料が積極的に採用されたという印象だった。
例えばDS・Wiiの物語を補強する横井という物語をクローズアップする一方、ファミコンについての記述はほんの触り程度しか紹介されていない、等。
余談
個人的には、マリオが当初「おっさん」と呼ばれていたというのがツボだった。
関数
ポイント
- defステートメント
- ネスト可能
- 実行時に決定する(代入と同じ)
if x <= 5: def foo(): print(x + x) else: def foo(): print(x * x)
- リファレンス共有
- 呼出元・呼出先でリファレンスを共有している
- 引数が可変性のオブジェクトである場合、引数操作が呼出元に影響する。
- 呼出元・呼出先でリファレンスを共有している
>>> def foo(lst): ... lst.append("x") ... >>> lst = ["y"] >>> foo(lst) >>> lst ['y', 'x']
- どんなインターフェースが対応するかを意識して関数定義する
- 関数名は変数と同じ扱い
>>> def foo(): print("FOO") ... >>> foo() FOO >>> x = foo >>> x() FOO
- None
- returnなしの際に戻される
ジェネレータ
>>> def foo(): ... yield "Hello" ... >>> f = foo() >>> print(next(f), "World") Hello World
applyのような関数呼び出し
>>> def foo(x, y): print("%d:%d" % (x,y)) >>> lst = [1,2] >>> foo(*lst) 1:2
ネストスコープのループ
内側の変数を代入しただけだと、その変数自体が次々に変化していくため、期待した動作が得られない。
>>> def foo(x): ... result = [] ... for i in range(x): ... result.append(lambda : print(i)) ... return result ... >>> lst = foo(3) >>> for l in lst: l() ... 2 2 2
上記の場合、012となってほしいところが、printされた値は全て最後に代入された2になっている。
これを回避する方法として、デフォルト値を利用するやり方がある。
>>> def foo(x): ... result = [] ... for i in range(x): ... result.append(lambda y=i: print(y) ) ... return result ... >>> lst = foo(3) >>> for l in lst: l() ... 0 1 2
javascriptにおけるクロージャによる解決
似たような話を、JavaScriptでも読んだ。(「JavaScript The Good Parts」)
var add_clickEvent = function(ns){ var i; for(i = 0; i < nodes.length; i++){ nodes[i].onclick = function(){ alert(i); }; } }; add_clickEvent(document.getElementsByTagName("button"));
全てのボタンのonclickに、ボタンの順序(インデックス)に従ったメッセージを出すことを意図している。
しかし結果としては、全てのonclickはボタンの総数をメッセージ表示する。
これは、ハンドラ関数は変数iを処理しているのであって、その時点のインデックスの値を処理しているわけではないから。
扱おうと試みた時点では、その変数は期待した状態になっていないという点で似ている。
回避策として、クロージャの応用で、ハンドラ関数を返す無名関数を即時実行する方法が記載されていた。
var add_clickEvent = function(nodes){ var i; for(i = 0; i < nodes.length; i++){ nodes[i].onclick = function(j){ return function(e){ alert(j); }; }(i); } }; add_clickEvent(document.getElementsByTagName("button"));
無名関数が扱うパラメータjは、add_ClickEventで定義されたiとは異なる変数になり、この無名関数のjを参照したハンドラ関数がonclickに設定される。
Pythonでクロージャの方法を試してみる
これなら、同じようなことをPythonでもできるかなと試してみたら、できた。
>>> def foo(x): ... result = [] ... for i in range(x): ... result.append( ... (lambda j: ... lambda: print(j))(i)) ... return result ... >>> lst = foo(3) >>> for l in lst: l() ... 0 1 2
うーん…手元で動くというだけで、自信がない。
やりたいこと自体は「時点の変数の値を保持する」だけなので、デフォルト引数の特性を知っているならあえてそれを使わない手もないな、と思った。
デフォルト値が可変性オブジェクトなら上書きできてしまう
関数はオブジェクトで、デフォルト値は関数オブジェクトに対応するため。
>>> def foo(x=[10]): ... for i in x: print(i) ... x.append(sum(x)) ... >>> foo() 10 >>> foo() 10 10 >>> foo() 10 10 20
Python3でreloadは廃止→imp.reloadに
>>> import trial hello >>> import imp >>> imp.reload(trial) hello! <module 'trial' from 'trial.py'>