System.Collections.IEnumerator CoGorillaTest() { // https://www.jstatsoft.org/article/view/v007i03/tuftests.pdf // まず必要な回数乱数を呼んで溜める const int Shortening = 0; const int stringLength = 26 - Shortening; // 生成する「文字列」のビット長 const int idealMean = 24687971 >> Shortening; // 論文から。自分で計算していない(2^26/e) const int idealStandardDeviation = 4170 >> Shortening; // 論文から。自分で計算していない。 const int bitsPerValue = 16; const int stringCount = 1 << stringLength; // 2^26通りの文字列が生成されうるので、そのうちどれだけ出てこないかを調べる。 const int stringMask = stringCount - 1; // 乱数だけ先に別スレで呼んで並列化して高速化 var randValueCount = stringCount + stringLength - 1; var values = new int[randValueCount]; var unit = randValueCount / ThreadCount; var offset = 0; for (int i = 0; i < ThreadCount; i++) { int threadIndexCaptured = i; int countCaptured = (i == ThreadCount - 1) ? randValueCount : unit; int offsetCaptured = offset; _threadPool.AddJob(() => { for (int j = 0; j < countCaptured; j++) { values[offsetCaptured + j] = _randoms[threadIndexCaptured].Next(); } }); randValueCount -= countCaptured; offset += countCaptured; } // 終了待ち while (!_threadPool.IsComplete()) { yield return(null); } // ビットごとに並列させる var counts = new int[bitsPerValue]; int completeCount = 0; for (int bitIndex = 0; bitIndex < bitsPerValue; bitIndex++) { int bitIndexCaptured = bitIndex; _threadPool.AddJob(() => { int str = 0; // プロローグ(文字列長-1ビット生成) for (int position = 0; position < (stringLength - 1); position++) { var value = values[position]; str <<= 1; str |= (value >> bitIndexCaptured) & 0x1; } // 文字列生成ループ。生成された文字列にtrueをつけて回る var appearFlags = new bool[stringCount]; for (int stringIndex = 0; stringIndex < stringCount; stringIndex++) { var value = values[stringIndex + stringLength - 1]; str <<= 1; // 1ビット送って str |= (value >> bitIndexCaptured) & 0x1; // 新しいビットを足し str &= stringMask; // 範囲外を消す appearFlags[str] = true; } // 集計 int count = 0; for (int stringIndex = 0; stringIndex < stringCount; stringIndex++) { if (appearFlags[stringIndex]) { count++; } } lock (counts) // 配列の要素アクセスがメモリ壊すんじゃないかと心配なので同期 { counts[bitIndexCaptured] = count; completeCount++; Debug.Log("Gorilla test ... " + completeCount + "/" + bitsPerValue); } }); } // 終了待ち while (!_threadPool.IsComplete()) { yield return(null); } // 数えて色塗る int yCount = Height / 4; int xCount = Width / 4; for (int bitIndex = 0; bitIndex < bitsPerValue; bitIndex++) { int count = counts[bitIndex]; int yStart = (bitIndex / 4) * yCount; int xStart = (bitIndex % 4) * xCount; count = stringCount - count; // 現れなかった数に変換 float sdRatio = (float)(count - idealMean) / (float)idealStandardDeviation; Debug.Log("[gorilla test result] bitIndex: " + bitIndex + " count: " + count + "/" + stringCount + " sd: " + sdRatio); var color = new Color(0.5f, 0.5f, 0.5f, 1f); color.r += sdRatio / 8f; color.g -= sdRatio / 8f; for (int pixelY = 0; pixelY < yCount; pixelY++) { for (int pixelX = 0; pixelX < xCount; pixelX++) { _texture.SetPixel(pixelX + xStart, pixelY + yStart, color); } } } _texture.Apply(); }
public void Start() { stopped = false; mappingStrategy.Load(); pool = new ThreadPool("AGIServer", poolSize); #if LOGGER logger.Info("Thread pool started."); #endif try { var ipAddress = IPAddress.Parse(address); serverSocket = new ServerSocket(port, ipAddress, SocketEncoding); } catch (IOException ex) { #if LOGGER logger.Error("Unable start AGI Server: cannot to bind to " + address + ":" + port + ".", ex); #endif throw ex; } finally { if (serverSocket != null) { serverSocket.Close(); serverSocket = null; } pool.Shutdown(); #if LOGGER logger.Info("AGIServer shut down."); #endif } #if LOGGER logger.Info("Listening on " + address + ":" + port + "."); #endif try { SocketConnection socket; while ((socket = serverSocket.Accept()) != null) { #if LOGGER logger.Info("Received connection."); #endif var connectionHandler = new AGIConnectionHandler(socket, mappingStrategy, SC511_CAUSES_EXCEPTION, SCHANGUP_CAUSES_EXCEPTION); pool.AddJob(connectionHandler); } } catch (IOException ex) { if (!stopped) { #if LOGGER logger.Error("IOException while waiting for connections (1).", ex); #endif throw ex; } } finally { if (serverSocket != null) { try { serverSocket.Close(); } #if LOGGER catch (IOException ex) { logger.Error("IOException while waiting for connections (2).", ex); } #else catch { } #endif } serverSocket = null; pool.Shutdown(); #if LOGGER logger.Info("AGIServer shut down."); #endif } }
void Update() { float dt = Time.deltaTime; debugUi.ManualUpdate(dt); if (Input.GetKeyDown(KeyCode.Space)) { Fire(); } // テキトーに的を動かす var p = target.transform.localPosition; var dp = p - targetOrigin; targetVelocity *= 1f - targetDamping; targetVelocity -= dp * targetStiffness * dt; p += targetVelocity * dt; target.transform.localPosition = p; gunPoint.LookAt(p); for (int i = 0; i < beams.Length; i++) { if (beams[i].time >= 0) { UpdateBeam(beams[i]); } } UnityEngine.Profiling.Profiler.BeginSample("Main.Update.UpdateParticles"); var transform = mainCamera.gameObject.transform; var forwardVector = transform.forward; var upVector = transform.up; // TODO: 右ベクタ、上ベクタは前計算可能 // 右ベクタ、上ベクタを生成 axisX = cross(axisY, axisZ) Vector3 right = Vector3.Cross(upVector, forwardVector); right.Normalize(); // ビルボード空間の上ベクタを計算 Vector3 up = Vector3.Cross(forwardVector, right); int rest = particles.Length; int unit = rest / jobs.Length; if ((rest - (unit * jobs.Length)) > 0) { unit += 1; } int begin = 0; for (int i = 0; i < jobs.Length; i++) { int count = (rest >= unit) ? unit : rest; jobs[i].Set(begin, count, dt, ref up, ref right); particleRenderers[i].Mesh.SetTexture(texture); if (threadEnabled) { threadPool.AddJob(jobs[i]); } else { jobs[i].Execute(); } rest -= count; begin += count; } UnityEngine.Profiling.Profiler.EndSample(); var tp = target.transform.position; var gp = gunPoint.position; cameraController.FitByMove2PointVertical( gp, tp, Vector3.up, cameraPositionParameter, cameraMargin); cameraController.Stiffness = cameraStiffness; cameraController.ManualUpdate(dt); }