iCollatzの提案 #2 iCollatz演算ツール ブラウザ(BigInt)版 iCCBE

ツール
スポンサーリンク
スポンサーリンク

概要

iCollatz/無限化コラッツの数列を求めることができます。
また、前回公開の「コラッツ予想演算ツール」は、9…9(1000桁)などを指定して演算実行するとフリーズしたように見えていましたが、今回、随時演算状況を表示するようにしました。
今後投稿予定の記事でプログラムソースコードの内容を解説する予定です。

ツール

制限や特徴などは後回しにしてツールから公開します。

iCollatz演算 ブラウザ(BigInt)版

iCCBE:Infinite Collatz Calculator BigInt Editionツールはこちら(別タブが開きます)

ご意見、ご要望、不具合などのご連絡

ご意見、ご要望、不具合などのご連絡は次からお願いします。

  • コメント
    本投稿へ下部の コメントを書き込む からご連絡ください。
    コメントは承認方式となっており、当方が承認しないと公開表示されません。
    公開表示を希望されない方はその旨コメントに記述ください。
  • Twitter
    ご連絡は @dratech2020 https://twitter.com/dratech2020 の該当ツイートに返信するか、ハッシュタグ「#プログラミングの深淵を求めて」を付けてツイートしてください。 (すぐに気が付かない場合がありますので、ご了承ください)

変更来歴

  • Rev. 1.0 2023/06/23
    新規公開

制限や特徴

  • 本ツールは、[演算開始]ボタンを押しても通信は発生せず(サーバーアクセスなし)、 ブラウザ(クライアント)内部だけで演算します。
    このため、ご利用の環境(ブラウザの種類、マシンのスペックなど)によって、 処理できる桁数の制限が違います。
    非常に大きい数値では処理時間と消費メモリが大きくなる(ただし前ツールより省メモリ化)ため、 正しく動作しない場合がありますのでご了承ください。
  • 開始時のnを非常に大きい値にしても、演算実行時に逐次状況を表示し、フリーズしたように見えなくなりました。
  • 表示形式を色付きテーブルにしたとき、100STEP毎のページ切り替えにすることにより、メモリ使用量を削減しました。
    ex. MS Edgeで、r=2, k=3(コラッツ予想と同じ)で、n=9…9(9を1000桁)で演算すると前回ツールでは完走しませんでしたが、今回は完走可能なことを確認しています。
    (注:テキスト(CSVまたはTSV)時はその限りではありません)
  • r=2~9,11~36までは、r進数の表示をすることで、直感的に数列の変化を見ることが可能です。
  • 同じ演算結果が3回(開始時STEP0のnの値は除く)出現したら演算を停止します。
    これは、例えばr=2, k=3(コラッツ予想と同じ)のとき、n=3でf(n)=3*3+1=10と、n=20でf(n)=20/2=10で同じ10になるのに2通りの演算があるため、3回の出現を監視することで、確実にループになったことを確認できるようにします。
  • 演算式の途中式を表示可能で、値の検証がやりやすくなりました。

関連情報

詳細は、「iCollatzの提案 #1 iCollatzの式」を参照ください。

iCollatzの式

iCollatz[矯正:Correct]の式

関連投稿

実行例

r=2,k=3,n=27の実行例

ソースコード

本ソースコードはオープン(透明性のある)/無料で参照/利用できますが、自由にして良いわけではありません。
It’s open and free source code, but it’s not freedom.

icollatz_bigint.html

<!DOCTYPE html>
<html lang="ja">
<!-- iCollatz演算ブラウザ(BigInt)版(iCCBE) -->
<!-- $Id$ -->
<!-- (C)2021-2023 プログラミングの深淵を求めて https://www.seekabypro.com/ -->
<!-- (C)2021-2023 どらテク(どらぐ~んテクノロジー) https://twitter.com/dratech2020 -->

<head>
<meta charset="UTF-8" />
<meta name="robots" content="noindex" />
<title>iCollatz演算ブラウザ(BigInt)版</title>
<link rel="stylesheet" type="text/css" href="./css/icollatz.css">
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.6.4/jquery.min.js" type="text/javascript"></script>
<script src="./js/icollatz.js" type="text/javascript"></script>
</head>
<body>

<div id="icollatz">
    <h1>iCollatz演算 ブラウザ(BigInt)版<br />(iCCBE:Infinite Collatz Calculator BigInt Edition)</h1>
    <a href="/2023/06/23/icollatz_no2/">ツールの概要などはこちら</a>
    <hr />
    <span id="ic_sponsor1" class="ic_item_hide_span">
        スポンサーリンク[-]
    </span>
    <span id="ic_sponsor1_content">
        <br />
        
    </span>
    <hr />
    <div class="ic_formula">
        <span id="ic_formula" class="ic_item_hide_span">
            計算式[-]
        </span>
        <span id="ic_formula_content">
            <!-- 計算式 -->
            <br />
            <a href="img/icollatz_v05_mid.png">    
                <img src="img/icollatz_v05_mid.png" alt="iCollatz式" style="width:640px;" />
            </a>
            <br />
            <a href="img/icollatz_v05_cor_mid.png">
                <img src="img/icollatz_v05_cor_mid.png" alt="iCollatz式[矯正:Correct]" style="width:540px;" />
            </a>
        </span>
    </div>
    <hr />
    <div id="ic_start_input">
        各入力テキストは、10進数、先頭に 0b を付けると2進数、同様に 0o で8進数、0x で16進数として扱います(他の基数での入力は非対応)。<br />
        <span><font color="RED">※10進数は'0'~'9'、2進数は'0','1'、8進数は'0'~'7'、16進数は'0'~'9'と'a'~'f'(大文字小文字は区別なし)以外の文字は削除します。</font></span>
        <br />
        r:基数(Radix)<br />
        <input id="ic_radix" name="ic_radix" type="text" value=2 onkeypress="return HtVw.input_onkeypress();">
        <br />
        k:係数<br />
        <input id="ic_k" name="ic_k" type="text" value=3 onkeypress="return HtVw.input_onkeypress();">
        <span>k>rおよびk<r<sup>2</sup>の<font color="RED">範囲以外の場合</font>は警告のみで演算可能です。</span>
        <br />
        n:開始の数値<br />
        <input id="ic_input" name="ic_input" type="text" value=27 onkeypress="return HtVw.input_onkeypress();">
        <span id="ic_input_length">0</span>桁
        <br />
        <input id="ic_start" name="ic_start" type="button" value="演算開始">
        <input id="ic_pause" name="ic_pause" type="button" value="一時停止" disabled="">
        <input id="ic_stop"  name="ic_stop"  type="button" value="演算終了" disabled="">
        <br />
        <span>
            <font color="RED">
                ※同じ数字が<span id="ic_same_after">3</span>回発生したとき、または、[演算終了]ボタンを押すまで実行します。<br />
                ※[演算開始]ボタンを押しても通信は発生せず(サーバーアクセスなし)、 ブラウザ(クライアント)内部だけで演算します。
            </font>
        </span>
    </div>
    <hr />
    <div class="ic_status">
        <span>
            Status       :
            <span id="ic_status">未実行</span>
        </span>
    </div>
    <div class="ic_goal_step">
        <span>
            GOAL-STEP    :
            <span id="ic_goal_step">?</span>
            <span>(最初にn=1となったSTEP)</span>
        </span>
    </div>
    <div class="ic_count_mzr">
        <span>
            COUNT-MZR    :
            <span id="ic_count_mzr">0</span>
            回(Modulo ZeRo:剰余==0:STEP=0分は含まず、最初にn=1なるまで)
        </span>
    </div>
    <div class="ic_count_mnz">
        <span>
            COUNT-MNZ    :
            <span id="ic_count_mnz">0</span>
            回(Modulo Non Zero:剰余!=0:STEP=0分は含まず、最初にn=1なるまで)
        </span>
    </div>
    <div class="ic_max_n_step">
        <span>
            <span>MAX-n-STEP   :</span>
            <span id="ic_max_n_step">0</span>
            <span>(最初にn=最大となったSTEP)</span>
        </span>
    </div>
    <div class="ic_max_n">
        <span>
            <span>MAX-n        :</span>
            <span id="ic_max_n">0</span>
        </span>
    </div>
    <div class="ic_goal_n_dash">
        <span>
            GOAL-n'      :
            <span id="ic_goal_n_dash_radix">r</span><sup  id="ic_goal_n_dash_exp">?</sup>=
            <span id="ic_goal_n_dash_dec">?</span>
        </span>
    </div>
    <div class="ic_proc_time">
        <span>
            Processing Time:
            <span id="ic_proc_time">0(ms)</span>
            <br />
        </span>
    </div>
    <hr />
    <div class="ic_display">
        <span id="ic_display" class="ic_item_hide_span">
            表示指定[-]
        </span>
        <br />
        <span id="ic_display_content">
            <font color="RED">
                ※オフにしたものは必要最低限しか演算しません(消費メモリの節約になります)<br />
                ※r進数の表示はr=2~9,11~36(10は除く)のときに有効です。
            </font>
            <br />
            <div class="ic_display_icollatz">
                <span>iCollatzの列</span>
                <input id="ic_display_all_on" name="ic_display_all_on" type="button" value="全表示">
                <input id="ic_display_all_of" name="ic_display_all_of" type="button" value="全非表示">
                <br />
                <label class="ic_label"><input id="ic_view_step"       name="ic_view_step"       type="checkbox" checked         >STEP</label>
                <label class="ic_label"><input id="ic_view_n"          name="ic_view_n"          type="checkbox" checked disabled>n(10進数:解除不可)</label>
                <label class="ic_label"><input id="ic_view_n_radix"    name="ic_view_n_radix"    type="checkbox" checked         >n(r進数)</label>
                <label class="ic_label"><input id="ic_view_calc"       name="ic_view_calc"       type="checkbox"                 >演算式(10進数)</label>
                <label class="ic_label"><input id="ic_view_calc_radix" name="ic_view_calc_radix" type="checkbox"                 >演算式(r進数)</label>
            </div>
            <div class="ic_display_icollatz_dash">
                <span>iCollatz[矯正:Correct]の列</span>
                <input id="ic_display_dash_all_on" name="ic_display_dash_all_on" type="button" value="全表示">
                <input id="ic_display_dash_all_of" name="ic_display_dash_all_of" type="button" value="全非表示">
                <br />
                <label class="ic_label"><input id="ic_view_n_dash"       name="ic_view_n_dash"       type="checkbox" checked>n'(10進数)</label>
                <label class="ic_label"><input id="ic_view_d"            name="ic_view_d"            type="checkbox" checked>d(10進数)</label>
                <label class="ic_label"><input id="ic_view_n_dash_radix" name="ic_view_n_dash_radix" type="checkbox" checked>n'(r進数)</label>
                <label class="ic_label"><input id="ic_view_d_radix"      name="ic_view_d_radix"      type="checkbox" checked>d(r進数)</label>
            </div>
            <div class="ic_display_text_type">
                <span>表示形式:</span>
                <label class="ic_label"><input id="ic_display_text_color" name="ic_display_text_type" type="radio" value="color" checked>色付きテーブル</label>
                <label class="ic_label"><input id="ic_display_text_csv"   name="ic_display_text_type" type="radio" value="csv" >テキスト(CSV)</label>
                <label class="ic_label"><input id="ic_display_text_tsv"   name="ic_display_text_type" type="radio" value="tsv" >テキスト(TSV)</label>
                <!-- Rev1.0では見送 <font color="RED">※実行中でも変更を反映</font> -->
            </div>
            <div class="ic_display_item_width">
                <span>列幅指定:</span>
                <label class="ic_label"><input id="ic_display_item_width1" name="ic_display_item_width" type="radio" value="all" checked>制限なし</label>
                <label class="ic_label"><input id="ic_display_item_width2" name="ic_display_item_width" type="radio" value="scroll" >制限あり(内部スクロール表示)</label>
                <font color="RED">※実行中でも変更を反映</font>
            </div>
            <div class="ic_display_line">
                <span>行スクロール指定:</span>
                <label class="ic_label"><input id="ic_display_line1" name="ic_display_line" type="radio" value="scroll" checked>内部スクロール表示</label>
                <label class="ic_label"><input id="ic_display_line2" name="ic_display_line" type="radio" value="all" >全行表示</label>
                <font color="RED">※実行中でも変更を反映</font>
            </div>
        </span>
    </div>
    <hr />
    <div class="ic_list_header">
        <b>演算結果</b> 
        <input id="ic_text_copy" name="ic_text_copy" type="button" value="テキストをコピー">
        <input id="ic_clear" name="ic_clear" type="button" value="結果クリア">
    </div>
</div>

<div class="ic_list">
    ここに演算結果が入ります。
</div>

<hr />
<span id="ic_sponsor2" class="ic_item_hide_span">
    スポンサーリンク[-]
</span>
<span id="ic_sponsor2_content">
    <br />
    
</span>
<hr />
(C)2021-2023 プログラミングの深淵を求めて
<a href="https://www.seekabypro.com/">https://www.seekabypro.com/</a>
<br />
(C)2021-2023 どらテク(どらぐ~んテクノロジー)
Twitter:
<a href="https://twitter.com/dratech2020">@dratech2020</a>
<a href="https://twitter.com/dratech2020">https://twitter.com/dratech2020</a>
<br />
</body>
</html>

icollatz.js

// iCollatz演算ブラウザ(BigInt)版(iCCBE:Infinite Collatz Calculator BigInt Edition)
// $Id$
// (C)2021-2023 プログラミングの深淵を求めて https://www.seekabypro.com/
// (C)2021-2023 どらテク(どらぐ~んテクノロジー) https://twitter.com/dratech2020
// 本ソースはオープン/無料で参照/利用できますが、自由にして良いわけではありません。
// It's open and free source code, but it's not freedom.

//-----------------------------------------------------------------------------
//定数定義
//-----------------------------------------------------------------------------
const IC_DEFAULT_RADIX=2n;
const IC_DEFAULT_K=3n;
const IC_DEFAULT_N=27n;
const IC_DEFAULT_D=1n;
const IC_DEFAULT_SAME_COUNT=3;
const IC_DEFAULT_PAGE_COUNT_MAX=100;
const IC_DEFAULT_PAGER_MAX=5;
const IC_DEFAULT_INTERVAL_CALCULATE_TIME=1;	//(ms)
const IC_DEFAULT_INTERVAL_VIEW_TIME=200;	//(ms)
const IC_DEFAULT_VIEW_STOP_COUNT=3;
const IC_CLASS_NAME_ICOLLATZ        = "iCollatz";
const IC_CLASS_NAME_ICOLLATZCORRECT = "iCollatzCorrect";
const IC_TEXT_MODE_COLOR = "color";
const IC_TEXT_MODE_CSV   = ",";
const IC_TEXT_MODE_TSV   = "\t";
const IC_STATUS_NO_PROC    = "IC_STATUS_NO_PROC";		//未実行
const IC_STATUS_EXEC_PROC  = "IC_STATUS_EXEC_PROC";		//実行中
const IC_STATUS_PAUSE      = "IC_STATUS_PAUSE";			//一時停止中
const IC_STATUS_COUNT_OVER = "IC_STATUS_COUNT_OVER";	//同じ数値がIC_DEFAULT_SAME_COUNT回発生
const IC_STATUS_USER       = "IC_STATUS_USER";			//ユーザーによる停止
const IC_STATUS_FATAL_ERROR= "IC_STATUS_FATAL_ERROR";	//致命的エラー
const IC_MOD_ZERO     = "MZR";	//Modulo ZeRo:剰余==0
const IC_MOD_NON_ZERO = "MNZ";	//Modulo Non Zero:剰余!=0
const IC_COLOR_HEAD ="#BDD7EE";
const IC_COLOR_MZR  ="#DDEBF7";
const IC_COLOR_MNZ  ="#FFF2CC";
const IC_COLOR_N_MAX="#C6E0B4";
const IC_COLOR_GOAL ="#C7A1E3";
const IC_COLOR_SAME ="#FF7F50";

//-----------------------------------------------------------------------------
//グローバル(ファイル内)変数
//-----------------------------------------------------------------------------
let iCRM = undefined;
let HtVw = undefined;

//-----------------------------------------------------------------------------
//クラス定義
//-----------------------------------------------------------------------------
//SuperICollatzクラス
class SuperICollatz {
	constructor(radix = IC_DEFAULT_RADIX,k = IC_DEFAULT_K,d = IC_DEFAULT_D) {
		this.radix = radix;
		this.k = k;
		this.d = d;
		this.f = undefined;
		this.n = 0n;
		this.mod = 0n;
	}
	
	calculate(number = IC_DEFAULT_N) {}

	calculate_zero() {}

	calculate_non_zero() {}
	
	clone() {
		return Object.assign(Object.create(Object.getPrototypeOf(this)), this);
	}
}

//iCollatzクラス
class iCollatz extends SuperICollatz {
	calculate(number = IC_DEFAULT_N) {
		this.n = number;
		let m = this.n % this.radix;
		if ( m == 0n ) {
			this.calculate_zero();
		} else {
			this.calculate_non_zero();
		}
		this.mod = this.f % this.radix;
		return this;
	}

	calculate_zero() {
		this.f = this.n / this.radix;
		this.d = this.radix * this.d;
		return this.f;
	}

	calculate_non_zero() {
		let h = this.k * this.n;
		this.f = h + (this.radix - ( h % this.radix));
		return this.f;
	}
}

//iCollatzCorrectクラス
class iCollatzCorrect extends SuperICollatz {
	calculate(number = IC_DEFAULT_N) {
		this.n = number;
		let m = (this.n/this.d) % this.radix;
		if ( m == 0n ) {
			this.calculate_zero();
		} else {
			this.calculate_non_zero();
		}
		this.mod = (this.f/this.d) % this.radix;
		return this;
	}

	calculate_zero() {
		this.f = this.n;
		this.d = this.radix * this.d;
		return this.f;
	}

	calculate_non_zero() {
		let h = this.k * this.n;
		this.f = h + this.d * (this.radix - ( (h/this.d) % this.radix));
		return this.f;
	}
}

//ResultStoreクラス
class ResultStore {
	constructor(key,number,same_count,icollatz) {
		let obj = this;
		obj.key = key;
		obj.store = [];
		obj.number_store = [];
		obj.same_count = same_count;
		icollatz.f = number;
		icollatz.mod = number % icollatz.radix;
		obj.icollatz = icollatz;
		obj.set(0,icollatz);
		//
		obj.goal_step=0;
		obj.count_mzr=0;
		obj.count_mnz=0;
		obj.max_step=0;
	}

	set(step,icollatz) {
		let obj = this;
		obj.store[step] = icollatz;
		if ( obj.number_store[icollatz.f] == undefined ) {
			obj.number_store[icollatz.f] = { 
				"icollatz":icollatz,
				"step":[],
			};
		}
		if ( step > 0 ) {
			obj.number_store[icollatz.f]["step"].push(step);
		}
		if ( (obj.key == IC_CLASS_NAME_ICOLLATZ) && (obj.number_store[icollatz.f]["step"].length >= obj.same_count) ) {
			//同じものがobj.same_count回出現したので停止する
			HtVw.set_stop_flag(true);
			HtVw.set_status(IC_STATUS_COUNT_OVER);
		}
	}
}

//iCollatzResultManagerクラス
class iCollatzResultManager {
	constructor() {
		let obj = this;
		obj.store_hash = {};
		obj.radix      = undefined;
		obj.k          = undefined;
	}

	get_store_hash(h = IC_CLASS_NAME_ICOLLATZ) {
		let obj = this;
		return obj.store_hash[h];
	}

	init_store(n = IC_DEFAULT_N) {
		let obj = this;
		let array = [];
		//if ( 
		//    (HtVw.checked_item_view_step() == true) || 
		//    (HtVw.checked_item_view_n() == true) ||	//解除不可
		//    (HtVw.checked_item_view_n_radix() == true)
		//) {
			array.push(IC_CLASS_NAME_ICOLLATZ);
		//}
		if (
		    (HtVw.checked_item_view_n_dash() == true) || 
		    (HtVw.checked_item_view_n_dash_radix() == true) ||
		    (HtVw.checked_item_view_d() == true) ||
		    (HtVw.checked_item_view_d_radix() == true)
		) {
			array.push(IC_CLASS_NAME_ICOLLATZCORRECT);
		}
		array.forEach( //ここではjQuery.eachは使いたくない
			function(key) {
				//thisはforEachのものに置き換わるためobjと使い分ける
				let ic = undefined;
				if ( key == IC_CLASS_NAME_ICOLLATZ ) {
					ic = new iCollatz(obj.radix,obj.k);
				} else if( key == IC_CLASS_NAME_ICOLLATZCORRECT ) {
					ic = new iCollatzCorrect(obj.radix,obj.k);
				}
				obj.store_hash[key] = new ResultStore(key,n,HtVw.get_same_count(),ic);
			}
		);
	}

	caluculate_proc() {
		let obj = this;
		for (let key in obj.store_hash) { //ここではjQuery.eachは使いたくない
			let sh = obj.store_hash[key];
			let step = sh.store.length;
			let n = sh.store[step-1].f;
			let icollatz = sh.store[step-1].clone();
			icollatz.calculate(n);
			sh.set(step,icollatz);
			if ( key == IC_CLASS_NAME_ICOLLATZ ) {
				if ( sh.store[sh.max_step].f < icollatz.f ) {
					sh.max_step = step;
				}
				if ( sh.goal_step == 0) {
					if ( icollatz.mod == 0n ) {
						sh.count_mzr++;
					} else {
						sh.count_mnz++;
					}
					if (icollatz.f == 1n) {
						sh.goal_step = step;
					}
				}
			}
		}
	}
}

//HtmlViewクラス
class HtmlView {
	constructor() {
		let obj = this;
		obj.item_icollatz           = jQuery("#icollatz");
		obj.item_radix              = jQuery("#ic_radix");
		obj.item_k                  = jQuery("#ic_k");
		obj.item_input              = jQuery("#ic_input");
		obj.item_list               = jQuery(".ic_list");
		obj.same_count              = IC_DEFAULT_SAME_COUNT;
		obj.interval_calculate_time = IC_DEFAULT_INTERVAL_CALCULATE_TIME;
		obj.interval_calculate_id   = undefined;
		obj.interval_view_time      = IC_DEFAULT_INTERVAL_VIEW_TIME;
		obj.interval_view_id        = undefined;
		obj.view_stop_count         = 0;
		obj.stop_flag               = false;
		obj.pause_flag              = false;
		obj.proc_start_time         = 0;
		obj.proc_time               = 0;
		obj.pause_start_time        = 0;
		obj.pause_time              = 0;
		obj.view                    = undefined;
		obj.item_view_step          = jQuery("#ic_view_step");
		obj.item_view_n             = jQuery("#ic_view_n");
		obj.item_view_n_radix       = jQuery("#ic_view_n_radix");
		obj.item_view_calc          = jQuery("#ic_view_calc");
		obj.item_view_calc_radix    = jQuery("#ic_view_calc_radix");
		obj.item_view_n_dash        = jQuery("#ic_view_n_dash");
		obj.item_view_n_dash_radix  = jQuery("#ic_view_n_dash_radix");
		obj.item_view_d             = jQuery("#ic_view_d");
		obj.item_view_d_radix       = jQuery("#ic_view_d_radix");
		obj.item_display_text_type  = jQuery("input:radio[name = 'ic_display_text_type']");
		obj.item_display_item_width = jQuery("input:radio[name = 'ic_display_item_width']");
		obj.item_display_line       = jQuery("input:radio[name = 'ic_display_line']");
		obj.item_status             = jQuery("#ic_status");
		obj.item_goal_step          = jQuery("#ic_goal_step");
		obj.item_goal_n_dash_radix  = jQuery("#ic_goal_n_dash_radix");
		obj.item_goal_n_dash_exp    = jQuery("#ic_goal_n_dash_exp");
		obj.item_goal_n_dash_dec    = jQuery("#ic_goal_n_dash_dec");
		obj.item_count_mzr          = jQuery("#ic_count_mzr");
		obj.item_count_mnz          = jQuery("#ic_count_mnz");
		obj.item_max_n_step         = jQuery("#ic_max_n_step");
		obj.item_max_n              = jQuery("#ic_max_n");
		obj.item_proc_time          = jQuery("#ic_proc_time");
		obj.item_button_start       = jQuery("#ic_start");
		obj.item_button_pause       = jQuery("#ic_pause");
		obj.item_button_stop        = jQuery("#ic_stop");
		//
		obj.status               = IC_STATUS_NO_PROC;
		obj.status_message       = {
			IC_STATUS_NO_PROC    :"未実行",
			IC_STATUS_EXEC_PROC  :"実行中",
			IC_STATUS_PAUSE      :"一時停止中",
			IC_STATUS_COUNT_OVER :"同じ数値(n=IC_SAME_COUNT_N)がIC_DEFAULT_SAME_COUNT回発生",
			IC_STATUS_USER       :"ユーザーによる停止",
			IC_STATUS_FATAL_ERROR:"致命的エラーが発生",
		};
	}

	get_status() {
		return this.status;
	}

	set_status(status) {
		this.status = status;
		return ;
	}

	set_stop_flag(flag) {
		this.stop_flag = flag;
		return ;
	}
	
	get_same_count() {
		return this.same_count;
	}
	
	checked_item_view_step() {
		return this.item_view_step.is(":checked");
	}

	checked_item_view_n() {
		return this.item_view_n.is(":checked");
	}

	checked_item_view_n_radix() {
		return this.item_view_n_radix.is(":checked");
	}

	checked_item_view_n_dash() {
		return this.item_view_n_dash.is(":checked");
	}

	checked_item_view_n_dash_radix() {
		return this.item_view_n_dash_radix.is(":checked");
	}

	checked_item_view_d() {
		return this.item_view_d.is(":checked");
	}

	checked_item_view_d_radix() {
		return this.item_view_d_radix.is(":checked");
	}


	//キーコードを応答する
	get_keycode(e) {
		if (!e)  e = window.event;
		return e.keyCode;
	}

	//onkeypress向け
	input_onkeypress(obj,value,ev) {
		let c = this.get_keycode(ev);
		if (c == 13) {
			this.ic_start_onclike();
			return false;
		} else {
			return true;
		}
	}

	//入力テキストチェックstr
	input_check_str(str) {
		if ( (str.indexOf("0b") === 0) || (str.indexOf("0B") === 0) ) {
			//2進数
			str = "0b"+str.replace(/^0b/i,"").replace(/[^01]/g,"");
		} else if ( (str.indexOf("0o") === 0) || (str.indexOf("0O") === 0) ) {
			//8進数
			str = "0o"+str.replace(/^0o/i,"").replace(/[^0-7]/g,"");
		} else if ( (str.indexOf("0x") === 0) || (str.indexOf("0X") === 0) ) {
			//16進数
			str = "0x"+str.replace(/^0x/i,"").replace(/[^0-9a-f]/ig,"");
		} else {
			//10進数
			str = str.replace(/[^0-9]/g,"");
		}
		return str;
	}

	//入力テキストチェック
	input_check(hash) {
		let obj = this;
		let n = 0n;
		let str = hash["text"].val();
		str = obj.input_check_str(str);
		n=BigInt(str);
		if ( ( hash["mes"] != undefined )  && ( n == 0n ) ) {
			window.alert(hash["mes"]+"が0または数値以外です。");
			return 0n;
		}
		return n;
	}

	//入力桁数などの表示
	ic_oninput() {
		let obj = this;
		let inp = obj.input_check_str(obj.item_input.val());
		let len = inp.replace(/^0[box]/,"").length;
		jQuery("#ic_input_length").text(len);
	}

	//演算開始ボタン
	ic_start_onclike() {
		let obj = this;
		//
		let text_hash = { "text":obj.item_input, "mes":"n:開始の数値" };
		let n = obj.input_check(text_hash);
		if ( n == 0n ) {
			return false;
		}
		//
		text_hash = { "text":obj.item_radix, "mes":"r:基数" };
		iCRM.radix = obj.input_check(text_hash);
		if ( iCRM.radix == 0n ) {
			return false;
		}
		if ( iCRM.radix <= 1n ) {
			window.alert("rは2以上の数値を指定してください。");
			return false;
		}
		//
		text_hash = { "text":obj.item_k, "mes":"k:係数" };
		iCRM.k = obj.input_check(text_hash);
		if ( iCRM.k == 0n ) {
			return false;
		}
		if ( iCRM.k <= 1n ) {
			window.alert("kは2以上の数値を指定してください。");
			return false;
		}
		//
		if ( iCRM.k <= iCRM.radix ) {
			window.alert("kがrより大きい数値が指定されました。\n無限ループする場合は[演算停止]ボタンで停止してください。");
		}
		if ( iCRM.k >= (iCRM.radix*iCRM.radix) ) {
			window.alert("kがrの2乗以上の数値が指定されました。\n無限に増大する場合は[演算停止]ボタンで停止してください。");
		}
		if ( obj.interval_calculate_id != undefined ) {
			obj.stop_proc();
		}
		obj.status = IC_STATUS_EXEC_PROC;
		iCRM.init_store(n);
		obj.item_button_start.prop("disabled",true);
		obj.item_button_stop.prop("disabled",false);
		obj.item_button_pause.prop("disabled",false);
		obj.ic_view_status();
		if ( obj.item_list != undefined ) {
			obj.item_list.remove();
			obj.item_list = undefined;
		}
		obj.stop_flag=false;
		obj.pause_flag=false;
		obj.proc_start_time = performance.now();
		obj.pause_time = 0;
		obj.set_calculate_interval();
		obj.set_view_interval();
	}

	//一時停止/演算再開ボタン
	ic_pause_onclike() {
		let obj = this;
		if (obj.interval_calculate_id != undefined ) {
			//一時停止
			if ( obj.pause_flag == false ) {
				obj.status = IC_STATUS_PAUSE;
				obj.pause_flag=true;
				obj.pause_start_time = performance.now();
			} else {
				obj.status = IC_STATUS_EXEC_PROC;
				obj.pause_flag=false;
				obj.pause_time += performance.now() - obj.pause_start_time;
			}
		}
	}

	//演算中断処理
	stop_proc() {
		let obj = this;
		if ( obj.interval_calculate_id != undefined ) {
			clearInterval(obj.interval_calculate_id);
			obj.interval_calculate_id = undefined;
			obj.proc_time = performance.now() - obj.proc_start_time - obj.pause_time;
		}
		obj.stop_flag = true
	}

	//演算中断ボタン
	ic_stop_onclike() {
		let obj = this;
		obj.status = IC_STATUS_USER;
		obj.stop_proc();
	}

	//テキストコピーボタン
	ic_text_copy_onclike() {
		let obj = this;
		let rc = obj.view.text_copy();
		if ( rc == true ) {
			window.alert("クリップボードにコピーしました。");
		}
	}

	//結果クリアボタン
	ic_clear_onclike() {
		let obj = this;
		obj.ic_oninput();
		obj.item_list.remove();
		obj.item_list  = jQuery("<div>",{ class:"ic_list", text:"ここに演算結果が入ります。", });
		obj.item_icollatz.append(obj.item_list);
	}

	
	//演算処理(インターバルタイマー用)
	ic_calculate(obj) {	//インターバルにはthisが渡らないのでarg1=objとして渡す
		if ( obj.pause_flag == true ) {
			return;
		}
		try {
			iCRM.caluculate_proc();
		} catch ( error ) {
			window.alert("致命的エラーが発生しました。\n"
				+error+"\n"
				+error.fileName+":"+error.lineNumber+":"+error.message+"\n"
			);
			obj.status = IC_STATUS_FATAL_ERROR;
			obj.stop_flag = true;
		} finally {
			if ( obj.stop_flag == true ) {
				obj.stop_proc();
			}
			obj.proc_time = performance.now() - obj.proc_start_time - obj.pause_time;
		}
	}
	
	//演算処理インターバルタイマー設定
	set_calculate_interval() {
		let obj = this;
		if ( obj.interval_calculate_id != undefined ) {
			clearInterval(obj.interval_calculate_id);
			obj.interval_calculate_id = undefined;
		}
		obj.interval_calculate_id = setInterval(obj.ic_calculate, obj.interval_calculate_time,obj);
	}

	//描画処理(インターバルタイマー用)
	ic_view(obj) {	//インターバルにはthisが渡らないのでarg1=objとして渡す
		try {
			if ( obj.stop_flag == false ) {
				obj.item_button_start.prop("disabled",true);
				obj.item_button_stop.prop("disabled",false);
				obj.item_button_pause.prop("disabled",false);
			} else {
				obj.item_button_start.prop("disabled",false);
				obj.item_button_stop.prop("disabled",true);
				obj.item_button_pause.prop("disabled",true);
			}
			if ( obj.pause_flag == false ) {
				obj.item_button_pause.val("一時停止");
			} else {
				obj.item_button_pause.val("実行再開");
			}
			if ( obj.item_list == undefined ) {
				obj.item_list = jQuery("<div>",{ "class":"ic_list", });
				obj.item_icollatz.append(obj.item_list);
				obj.ic_display_row();
				let text_type = obj.item_display_text_type.filter(':checked').val();
				if ( text_type == "csv" ) {
					obj.view = new ViewText(IC_TEXT_MODE_CSV);
				} else if ( text_type == "tsv" ) {
					obj.view = new ViewText(IC_TEXT_MODE_TSV);
				} else {	//text_type == IC_TEXT_MODE_COLOR
					obj.view = new ViewColor();
				}
			}
			//#描画処理
			obj.view.append();
		} catch ( error ) {
			if ( obj.status != IC_STATUS_FATAL_ERROR ) {
				window.alert("致命的エラーが発生しました。\n"
					+error+"\n"
					+error.fileName+":"+error.lineNumber+":"+error.message+"\n"
				);
			}
			obj.status = IC_STATUS_FATAL_ERROR;
			obj.stop_flag = true;
		} finally {
			if ( obj.stop_flag == true ) {
				if ( obj.view_stop_count >= IC_DEFAULT_VIEW_STOP_COUNT ) {
					if ( obj.interval_view_id != undefined ) {
						clearInterval(obj.interval_view_id);
						obj.interval_view_id = undefined;
					}
				} else {
					obj.view_stop_count++;
				}
			}
			obj.ic_view_status();
		}
	}
	
	//描画処理インターバルタイマー設定
	set_view_interval() {
		let obj = this;
		if ( obj.interval_view_id != undefined ) {
			clearInterval(obj.interval_view_id);
			obj.interval_view_id = undefined;
		}
		obj.interval_view_id = setInterval(obj.ic_view, obj.interval_view_time,obj);
	}

	//実行状況表示
	ic_view_status() {
		let obj = this;
		let sh_ic      = iCRM.get_store_hash(IC_CLASS_NAME_ICOLLATZ);
		let sh_ic_dash = iCRM.get_store_hash(IC_CLASS_NAME_ICOLLATZCORRECT);
		let mes = obj.status_message[obj.status];
		if ( obj.status == IC_STATUS_COUNT_OVER ) {
			let store_ic         = sh_ic.store;
			let same_n = store_ic[store_ic.length-1].f;
			mes = mes.replace(/IC_DEFAULT_SAME_COUNT/g,IC_DEFAULT_SAME_COUNT)
			         .replace(/IC_SAME_COUNT_N/g,same_n);
		}
		obj.item_status.text(mes);
		//

		let goal_step = sh_ic.goal_step;
		let goal_step_str = "?";
		if ( goal_step > 0 ) {
			goal_step_str = goal_step.toLocaleString();
		}
		obj.item_goal_step.text(goal_step_str);

		obj.item_goal_n_dash_radix.text(sh_ic.store[sh_ic.max_step].radix.toLocaleString());
		if ( sh_ic_dash != undefined ) {
			let exp_str = "?";
			let dec_str = "?";
			if ( goal_step > 0 ) {
				exp_str = sh_ic.count_mzr.toLocaleString();
				dec_str = sh_ic_dash.store[goal_step].f.toLocaleString();
			}
			obj.item_goal_n_dash_exp.text(exp_str);
			obj.item_goal_n_dash_dec.text(dec_str);
		}
		obj.item_count_mzr.text(sh_ic.count_mzr.toLocaleString());
		obj.item_count_mnz.text(sh_ic.count_mnz.toLocaleString());
		obj.item_max_n_step.text(sh_ic.max_step.toLocaleString());
		obj.item_max_n.text(sh_ic.store[sh_ic.max_step].f.toLocaleString());
		obj.item_proc_time.text(obj.proc_time.toLocaleString()+"(ms)");
	}

	//列幅指定
	ic_display_item_width() {
		let obj  = this;
		let val  = obj.item_display_item_width.filter(':checked').val();
		let span = obj.item_list.find("span");
		if ( val == "all" ) {
			span.removeClass("ic_item_width_scroll");
		} else {
			span.addClass("ic_item_width_scroll");
		}
	}

	//行スクロール指定
	ic_display_row() {
		let obj = this;
		let val = obj.item_display_line.filter(':checked').val();
		if ( val == "all" ) {
			obj.item_list.css("max-height","");
		} else {
			obj.item_list.css("max-height","480px");
		}
	}

	//全表示/全非表示
	ic_display_checkbox(obj,flag) {
		let chk = jQuery(obj).closest("div").find("input:checkbox");
		chk.each(function(index) {
			let item = jQuery(this);
			if ( item.is(":disabled") == false ) {
				item.prop("checked",flag);
			}
		});
	}

	ic_display_redraw(text_type=IC_TEXT_MODE_COLOR,pg=undefined) {
		let obj = this;
		let mode = text_type;
		if ( mode == "csv" ) {
			mede = IC_TEXT_MODE_CSV;
		} else if ( mode == "tsv" ) {
			mede = IC_TEXT_MODE_TSV;
		}
		if ( (obj.view.mode == mode) && (mode != IC_TEXT_MODE_COLOR) ) {
			return;
		}
		let taget_page = undefined;
		if ( mode == IC_TEXT_MODE_COLOR ) {
			if ( pg != undefined ) {
				let pager = jQuery(pg);
				let cls = pager.attr("class");
				if ( cls == "ic_list_pager_sel" ) {
					taget_page = pager.val();
				} else {
					//ic_list_pager_a_start,ic_list_pager_a_previos,ic_list_pager_a_content,
					//ic_list_pager_a_next,ic_list_pager_a_end
					taget_page = pager.data("page");
				}
				if ( obj.view.page == taget_page ) {
					return;
				}
			}
		}
		obj.view.redraw(taget_page);
	}

	//表示を隠す
	ic_hide(obj,target) {
		let span = jQuery(obj);
		let text = span.text();
		let content = jQuery(target);
		if ( text.indexOf("[-]") >= 0 ) {
			text = text.replace(/-/g,"+");
			span.text(text);
			content.addClass("ic_item_hide_display");
		} else {
			text = text.replace(/\+/g,"-");
			span.text(text);
			content.removeClass("ic_item_hide_display");
		}
	}
}

//SuperViewクラス
class SuperView {
	constructor() {
		let obj = this;
		obj.count        = 0;
		obj.step         = HtVw.item_view_step.is(":checked");
		obj.n            = HtVw.item_view_n.is(":checked");
		obj.n_radix      = HtVw.item_view_n_radix.is(":checked");
		obj.calc         = HtVw.item_view_calc.is(":checked");
		obj.calc_radix   = HtVw.item_view_calc_radix.is(":checked");
		obj.n_dash       = HtVw.item_view_n_dash.is(":checked");
		obj.n_dash_radix = HtVw.item_view_n_dash_radix.is(":checked");
		obj.d            = HtVw.item_view_d.is(":checked");
		obj.d_radix      = HtVw.item_view_d_radix.is(":checked");
		obj.inner        = undefined;
	}
	
	append() {
		let obj = this;
		let sh_ic      = iCRM.get_store_hash(IC_CLASS_NAME_ICOLLATZ);
		let calculate_length = sh_ic.store.length;
		if ( obj.count <= calculate_length ) {
			obj.append_line(calculate_length);
		}
	}

	make_header(store_ic,store_ic_dash) {
		let obj = this;
		let ic      = store_ic[0];
		let ic_dash = undefined;
		if ( store_ic_dash != undefined ) {
			ic_dash = store_ic_dash[0];
		}
		let radix   = Number(ic.radix);
		let td_array = [];
		let item_array = [];
		let class_array = [];
		if ( obj.step == true ) {
			td_array.push("ic_th");
			item_array.push("STEP");
			class_array.push("ic_item_step");
		}
		if ( obj.n == true ) {
			td_array.push("ic_th");
			item_array.push("n(10進数)");
			class_array.push("ic_item_n");
		}
		if ( (obj.n_radix == true) && 
		     ( (2 <= radix) && (radix <= 36) && (radix != 10) ) ) {
			td_array.push("ic_th");
			item_array.push("n("+radix+"進数)");
			class_array.push("ic_item_n_radix");
		}
		if ( obj.calc == true ) {
			td_array.push("ic_th");
			item_array.push("演算式(10進数)");
			class_array.push("ic_item_calc");
		}
		if ( (obj.calc_radix == true) && 
		     ( (2 <= radix) && (radix <= 36) && (radix != 10) ) ) {
			td_array.push("ic_th");
			item_array.push("演算式("+radix+"進数)");
			class_array.push("ic_item_calc_radix");
		}
		if ( ic_dash != undefined ) {
			//以下のradixは正しくはic_dash.radixなのだが同じなので処理を省く
			if ( obj.n_dash == true ) {
				td_array.push("ic_th_dash");
				item_array.push("n'(10進数)");
				class_array.push("ic_item_n_dash");
			}
			if ( (obj.n_dash_radix == true) && 
			     ( (2 <= radix) && (radix <= 36) && (radix != 10) ) ) {
				td_array.push("ic_th_dash");
				item_array.push("n'("+radix+"進数)");
				class_array.push("ic_item_n_dash_radix");
			}
			if ( obj.d == true ) {
				td_array.push("ic_th_dash");
				item_array.push("d(10進数)");
				class_array.push("ic_item_d");
			}
			if ( (obj.d_radix == true) && 
			     ( (2 <= radix) && (radix <= 36) && (radix != 10) ) ) {
				td_array.push("ic_th_dash");
				item_array.push("d("+radix+"進数)");
				class_array.push("ic_item_d_radix");
			}
		}
		return {"mod":"HEAD","td":td_array,"item":item_array,"class":class_array};
	}

	make_line(count,store_ic,store_ic_dash) {
		let obj = this;
		let ic      = store_ic[count];
		let ic_dash = undefined;
		if ( store_ic_dash != undefined ) {
			ic_dash = store_ic_dash[count];
		}
		let radix   = Number(ic.radix);
		let td_array = [];
		let item_array = [];
		let class_array = [];
		let add_class = "";
		let width_val = HtVw.item_display_item_width.filter(':checked').val();
		if ( width_val != "all" ) {
			add_class = " ic_item_width_scroll";
		}
		if ( obj.step == true ) {
			td_array.push("ic_td");
			item_array.push(count);
			class_array.push("ic_item_step"+add_class);
		}
		if ( obj.n == true ) {
			td_array.push("ic_td");
			item_array.push(ic.f.toString(10));
			class_array.push("ic_item_n"+add_class);
		}
		if ( (obj.n_radix == true) && 
		     ( (2 <= radix) && (radix <= 36) && (radix != 10) ) ) {
			td_array.push("ic_td");
			item_array.push(ic.f.toString(radix));
			class_array.push("ic_item_n_radix"+add_class);
		}
		let mod = IC_MOD_ZERO;
		if ( ic.mod != 0n ) {
			mod = IC_MOD_NON_ZERO;
		}
		let h = undefined;
		let m = undefined;
		let f = undefined;
		if ( (obj.calc == true) || 
		     ((obj.calc_radix == true) && 
		      ((2 <= radix) && (radix <= 36) && (radix != 10)) ) ) {
			if ( mod == IC_MOD_ZERO ) {
				f = ic.f / BigInt(radix);
			} else {
				h = ic.k * ic.f;
				m = BigInt(radix) - (h % BigInt(radix));
				f = h + m;
			}
		}
		if ( obj.calc == true ) {
			td_array.push("ic_td");
			if ( mod == IC_MOD_ZERO ) {
				item_array.push(
					mod+":f="+ic.f.toString(10)+"/"+radix+"="+f.toString(10)+
				"");
			} else {
				item_array.push(
					mod+
					":h="+ic.k.toString(10)+"*"+ic.f.toString(10)+"="+h.toString(10)+
					":m="+radix+"-("+h.toString(10)+" mod "+radix+")="+m.toString(10)+
					":f="+h.toString(10)+"+"+m.toString(10)+"="+f.toString(10)+
				"");
			}
			class_array.push("ic_item_calc"+add_class);
		}
		if ( (obj.calc_radix == true) && 
		     ( (2 <= radix) && (radix <= 36) && (radix != 10) ) ) {
			td_array.push("ic_td");
			if ( mod == IC_MOD_ZERO ) {
				item_array.push(
					mod+":f="+ic.f.toString(radix)+"/"+radix.toString(radix)+"="+f.toString(radix)+
				"");
			} else {
				item_array.push(
					mod+
					":h="+ic.k.toString(radix)+"*"+ic.f.toString(radix)+"="+h.toString(radix)+
					":m="+radix.toString(radix)+"-("+h.toString(radix)+" mod "+radix.toString(radix)+")="+m.toString(radix)+
					":f="+h.toString(radix)+"+"+m.toString(radix)+"="+f.toString(radix)
				);
			}
			class_array.push("ic_item_calc_radix"+add_class);
		}
		if ( ic_dash != undefined ) {
			//以下のradixは正しくはic_dash.radixなのだが同じなので処理を省く
			if ( obj.n_dash == true ) {
				td_array.push("ic_td_dash");
				item_array.push(ic_dash.f.toString(10));
				class_array.push("ic_item_n_dash"+add_class);
			}
			if ( (obj.n_dash_radix == true) && 
			     ( (2 <= radix) && (radix <= 36) && (radix != 10) ) ) {
				td_array.push("ic_td_dash");
				item_array.push(ic_dash.f.toString(radix));
				class_array.push("ic_item_n_dash_radix"+add_class);
			}
			if ( obj.d == true ) {
				td_array.push("ic_td_dash");
				item_array.push(ic_dash.d.toString(10));
				class_array.push("ic_item_d"+add_class);
			}
			if ( (obj.d_radix == true) && 
			     ( (2 <= radix) && (radix <= 36) && (radix != 10) ) ) {
				td_array.push("ic_td_dash");
				item_array.push(ic_dash.d.toString(radix));
				class_array.push("ic_item_d_radix"+add_class);
			}
		}
		return {"mod":mod,"td":td_array,"item":item_array,"class":class_array};
	}

	append_line(calculate_length = 0) {}

	redraw(taget_page = undefined) {}
	
	text_copy() {};

}

//ViewColorクラス
class ViewColor extends SuperView {
	constructor(mode = IC_TEXT_MODE_COLOR, page = 1) {
		super();
		let obj = this;
		obj.mode = mode;
		obj.page           = page;
		obj.page_count     = 0;
		obj.page_count_max = IC_DEFAULT_PAGE_COUNT_MAX;
		obj.pager_up = jQuery("<table>",{ "class":"ic_list_pager", });
		obj.pager_dw = jQuery("<table>",{ "class":"ic_list_pager", });
		obj.inner = jQuery("<table>",{ "id":"ic_list_table","class":"ic_list_table", });
		obj.before_max_step = 0;
		HtVw.item_list.append(obj.pager_up);
		HtVw.item_list.append(obj.inner);
		HtVw.item_list.append(obj.pager_dw);
		//
		obj.pager = jQuery(".ic_list_pager");
		obj.pager_max = IC_DEFAULT_PAGER_MAX;
		let tr    = jQuery("<tr>",{ "class":"ic_list_pager_tr", });
		let td_pg = jQuery("<td>",{ "class":"ic_list_pager_td", "text":"ページ:", });
		tr.append(td_pg);
		//
		let td_st = jQuery("<td>",{ "class":"ic_list_pager_td", });
		let a_st = jQuery("<a>" ,{ 
			"class":"ic_list_pager_a_start"  ,
			"onclick":"HtVw.ic_display_redraw('color',this); return false;", 
			"text":"0<<最初",
			"data-page":"start",
		}, );
		td_st.append(a_st);
		tr.append(td_st);
		let td_pv = jQuery("<td>",{ "class":"ic_list_pager_td", });
		let a_pv = jQuery("<a>" ,{
			"class":"ic_list_pager_a_previos",
			"onclick":"HtVw.ic_display_redraw('color',this); return false;", 
			"text":"<前",
			"data-page":"previos",
		}, );
		td_pv.append(a_pv);
		tr.append(td_pv);
		//
		for(let i=0; i<obj.pager_max; i++) {
			let td = jQuery("<td>",{ "class":"ic_list_pager_td", });
			let a  = jQuery("<a>" ,{
				"class":"ic_list_pager_a_content",
				"onclick":"HtVw.ic_display_redraw('color',this); return false;", 
				"text":(i*obj.page_count_max)+"-"+(((i+1)*obj.page_count_max)-1),
				"data-page":(i+1),
			}, );
			td.append(a);
			tr.append(td);
		}
		//
		let td_nx = jQuery("<td>",{ "class":"ic_list_pager_td", });
		let a_nx = jQuery("<a>" ,{
			"class":"ic_list_pager_a_next",
			"onclick":"HtVw.ic_display_redraw('color',this); return false;", 
			"text":"次>",
			"data-page":"next",
		}, );
		td_nx.append(a_nx);
		tr.append(td_nx);
		let td_ed = jQuery("<td>",{ "class":"ic_list_pager_td", });
		let a_ed = jQuery("<a>" ,{ 
			"class":"ic_list_pager_a_end"  ,
			"onclick":"HtVw.ic_display_redraw('color',this); return false;", 
			"text":"最後>>n",
			"data-page":"end",
		}, );
		td_ed.append(a_ed);
		tr.append(td_ed);
		//
		let td_sel_text = jQuery("<td>",{ "class":"ic_list_pager_td", "text":"指定ページ:", });
		tr.append(td_sel_text);
		let select = jQuery("<select>",{ 
			"class":"ic_list_pager_sel", 
			"onchange":"HtVw.ic_display_redraw('color',this); return false;", 
		}, );
		let option = jQuery("<option>" ,{
			"class":"ic_list_pager_opt",
			"text":"0-0",
			"value":1,
			"data-page":1,
		}, );
		select.append(option);
		let td_sel = jQuery("<td>",{ "class":"ic_list_pager_td", });
		td_sel.append(select);
		tr.append(td_sel);
		//
		obj.pager.append(tr);
		//
		obj.pager_st = jQuery(".ic_list_pager_a_start");
		obj.pager_pv = jQuery(".ic_list_pager_a_previos");
		obj.pager_ct = jQuery(".ic_list_pager_a_content");
		obj.pager_nx = jQuery(".ic_list_pager_a_next");
		obj.pager_ed = jQuery(".ic_list_pager_a_end");
		obj.pager_sl = jQuery(".ic_list_pager_sel");
	}

	append_td(item_hash,tdh) {
		let obj = this;
		let tr = jQuery("<tr>",{ "class":"ic_tr", });
		jQuery.each(item_hash["item"], function(index,column) {
			let td = jQuery("<"+tdh+">",{ "class":item_hash["td"][index]+"_"+item_hash["mod"], });
			let cls = item_hash["class"][index];
			let item = jQuery("<span>",{
				"text" :column,
				"class":cls,
			});
			if ( cls.match(/ic_item_n/) && !cls.match(/_radix/) && (column == "1") ) {
				item.addClass("ic_item_GOAL");
			}
			td.append(item);
			tr.append(td);
		});
		obj.inner.append(tr);
	}

	append_line(calculate_length) {
		let obj = this;
		let sh        = iCRM.get_store_hash(IC_CLASS_NAME_ICOLLATZ);
		let store_ic  = sh.store;
		let store_ic_dash = undefined;
		if ( 
		    ( obj.n_dash == true ) ||
		    ( obj.n_dash_radix == true ) ||
		    ( obj.d == true ) ||
		    ( obj.d_radix == true ) 
		) {
			store_ic_dash = iCRM.get_store_hash(IC_CLASS_NAME_ICOLLATZCORRECT).store;
		}
		
		let count_start = (obj.page-1) * obj.page_count_max;
		let page_end    = obj.page_count_max;
		let count_end   = calculate_length - ((obj.page-1) * obj.page_count_max);
		if ( count_end < page_end ) {
			page_end = count_end;
		}
		for ( obj.page_count; obj.page_count<page_end; obj.page_count++) {
			if ( obj.page_count == 0 ) {
				let item_hash = obj.make_header(store_ic,store_ic_dash);
				if ( item_hash["item"].length > 0 ) {
					obj.append_td(item_hash,"th")
				}
			}
			//
			let item_hash = obj.make_line( count_start + obj.page_count, store_ic, store_ic_dash);
			if ( item_hash["item"].length > 0 ) {
				obj.append_td(item_hash,"td")
			}
		}
		//ページャーの表示
		obj.append_pager(calculate_length);
		//最大値の背景色の更新(max値は変化するのでappend_tdではできない)
		if ( (obj.before_max_step != sh.max_step) ) {
			let n_max = jQuery(".ic_item_MAX");
			if ( n_max.length > 0 ) {
				n_max.removeClass("ic_item_MAX");
				obj.before_max_step = 0;
			}
			if ( (count_start<=sh.max_step) && (sh.max_step<count_end) ) {
				let item_n    = jQuery(".ic_item_n");
				jQuery.each(item_n, function(index) {
					let item = jQuery(item_n[index]);
					if ( item.text() == store_ic[sh.max_step].f ) {
						item.addClass("ic_item_MAX");
						obj.before_max_step = sh.max_step;
					}
				});
			}
		}
		//同じ数値(IC_SAME_COUNT_N)がIC_DEFAULT_SAME_COUNT回発生 時の背景色更新
		if ( HtVw.get_status() == IC_STATUS_COUNT_OVER ) {
			let number_store_ic  = sh.number_store;
			let same_n = store_ic[store_ic.length-1].f;
			let item_n    = jQuery(".ic_item_n");
			item_n.removeClass("ic_item_SAME");
			jQuery.each(item_n, function(index) {
				let item = jQuery(item_n[index]);
				if ( item.text() == same_n ) {
					item.addClass("ic_item_SAME");
				}
			});
		}
	}

	append_pager(calculate_length = 0) {
		let obj = this;
		let pager_half = Math. floor(obj.pager_max/2);
		let pager_last = Math. floor(calculate_length / obj.page_count_max);
		if ( (calculate_length % obj.page_count_max) > 0 ) {
			pager_last++;
		}
		let page_now = undefined;
		if ( pager_last <= obj.pager_max ) {
			page_now = 1;
		} else {
			page_now = obj.page - pager_half;
			if ( page_now < 1 ) {
				page_now = 1;
			}
			if ( (obj.page + pager_half) > pager_last ) {
				page_now = (pager_last - obj.pager_max) +1;
			}
		}
		obj.pager_ct.parent().addClass("ic_list_pager_hide");
		obj.pager_ct.removeClass("ic_list_pager_select");
		for ( let pager_count=0; pager_count<obj.pager_max; pager_count++) {
			let count_start = (page_now-1)*obj.page_count_max;
			let count_end   = page_now*obj.page_count_max-1;
			if ( count_end > calculate_length ) {
				count_end = calculate_length-1;
			}
			let content_ct_up = jQuery(obj.pager_ct[pager_count]);
			let content_ct_dw = jQuery(obj.pager_ct[pager_count+obj.pager_max]);
			content_ct_up.text(count_start+"-"+count_end);
			content_ct_dw.text(count_start+"-"+count_end);
			content_ct_up.data("page",page_now);
			content_ct_dw.data("page",page_now);
			if ( page_now == obj.page ) {
				content_ct_up.addClass("ic_list_pager_select");
				content_ct_dw.addClass("ic_list_pager_select");
			}
			content_ct_up.parent().removeClass("ic_list_pager_hide");
			content_ct_dw.parent().removeClass("ic_list_pager_hide");
			//
			page_now++;
			if ( page_now > pager_last ) {
				break;
			}
		}
		if ( pager_last > obj.page ) {
			obj.pager_ed.text("最後>>"+(calculate_length-1));
		}
		//
		for ( let pager_count=1; pager_count<=pager_last; pager_count++) {
			obj.pager_sl.each(function(index) {
				let count_start = (pager_count-1)*obj.page_count_max;
				let count_end   = pager_count*obj.page_count_max-1;
				if ( count_end > calculate_length ) {
					count_end = calculate_length-1;
				}
				let sel = jQuery(obj.pager_sl[index]);
				let opt = sel.children();
				let content_opt = undefined;
				if ( opt[pager_count-1] == undefined ) {
					let option = jQuery("<option>" ,{
						"class":"ic_list_pager_opt",
						"text":count_start+"-"+count_end,
						"value":pager_count,
						"data-page":pager_count,
					}, );
					sel.append(option);
				} else {
					content_opt = jQuery(opt[pager_count-1]);
					content_opt.text(count_start+"-"+count_end);
					content_opt.data("page",pager_count);
				}
			});
			//
		}
	}

	redraw(taeget_page = 1) {
		let obj = this;
		//"start","previos","next","end"
		let calculate_length = iCRM.get_store_hash(IC_CLASS_NAME_ICOLLATZ).store.length;
		let pager_last = Math. floor(calculate_length / obj.page_count_max);
		if ( (calculate_length % obj.page_count_max) > 0 ) {
			pager_last++;
		}
		let page = obj.page;
		if ( taeget_page == "start" ) {
			page = 1;
		} else if ( taeget_page == "previos" ) {
			page--;
			if ( page < 1 ) {
				page = 1;
			}
		} else if ( taeget_page == "next" ) {
			page++;
			if ( page > pager_last ) {
				page = pager_last;
			}
		} else if ( taeget_page == "end" ) {
			page = pager_last;
		} else {
			page = taeget_page;
		}
		if ( page == obj.page ) {
			return;
		}
		obj.page = page;
		obj.page_count      = 0;
		obj.before_max_step = 0;
		//
		obj.pager_sl.val(page);
		//テーブルを消して再度追加
		let tr = jQuery(".ic_tr");
		tr.remove();
		obj.append(); //インターバルタイマー経由のic_view使っても変わらないので簡単な処理とする
	}
	
	text_copy() {
		let exec_flag = false;
		let supportsDOMRanges = document.implementation.hasFeature("Range", "2.0");
		if ( supportsDOMRanges == true ) {
			let range = document.createRange();
			let table = document.getElementById("ic_list_table");
			if ( table != null ) {
				window.getSelection().removeAllRanges();	//既に選択済みのものがあれば消す
				range.selectNodeContents(table);
				window.getSelection().addRange(range);
				document.execCommand("copy");
				window.getSelection().removeRange(range);
				exec_flag = true;
			}
		} else {
			window.alert("ブラウザが未対応のためコピーできませんでした。");
		}
		return exec_flag;
	}
}

//ViewTextクラス
class ViewText extends SuperView {
	constructor(mode = IC_TEXT_MODE_CSV, page = undefined) {
		super();
		let obj = this;
		obj.mode = mode;
		obj.inner = jQuery("<pre>",{ "id":"ic_list_inner","class":"ic_list_inner", });
		HtVw.item_list.append(obj.inner);
	}

	append_line(calculate_length) {
		let obj = this;
		let store_ic  = iCRM.get_store_hash(IC_CLASS_NAME_ICOLLATZ).store;
		let store_ic_dash = undefined;
		if ( 
		    ( obj.n_dash == true ) ||
		    ( obj.n_dash_radix == true ) ||
		    ( obj.d == true ) ||
		    ( obj.d_radix == true ) 
		) {
			store_ic_dash = iCRM.get_store_hash(IC_CLASS_NAME_ICOLLATZCORRECT).store;
		}
		let count = undefined;
		for ( count=obj.count; count<calculate_length; count++ ) {
			if ( count == 0 ) {
				obj.inner.append(
					"r="+store_ic[count].radix.toString(10)+obj.mode+
					"k="+store_ic[count].k.toString(10)+"\n");
				let hash = obj.make_header(store_ic,store_ic_dash);
				if ( hash["item"].length > 0 ) {
					let str = hash["item"].join(obj.mode);
					obj.inner.append(str+"\n");
				}
			}
			//
			let hash = obj.make_line(count,store_ic,store_ic_dash);
			if ( hash["item"].length > 0 ) {
				let str = hash["item"].join(obj.mode);
				obj.inner.append(str+"\n");
			}
		}
		obj.count = count;
	}

	redraw(taget_page = undefined) {
		//インターバルタイマーにしたところで、
		//全部描画するまで待つことになるので
		//Rev1.0では実装見送り(呼び出すところも作ってない)
	}

	text_copy() {
		if( !navigator.clipboard ) {
			window.alert("クリップボードにコピーできませんでした。");
		} else {
			let copyText = document.querySelector(".ic_list_inner").textContent;
			//非同期処理のため、成功失敗はこの時点ではわからない
			navigator.clipboard.writeText(copyText).then(
				function() {
					window.alert("クリップボードにコピーしました。");
				},
				function() {
					window.alert("クリップボードにコピーできませんでした。");
				}
			);
		}
		return false;	//falseを返してメッセージを複数出さない
	}
}

//-----------------------------------------------------------------------------
//function定義
//-----------------------------------------------------------------------------
jQuery(document).ready(function() {
	//初期化
	iCRM = new iCollatzResultManager();
	HtVw = new HtmlView();
	HtVw.ic_oninput();
	//
	jQuery("#ic_same_count").text(IC_DEFAULT_SAME_COUNT.toString(10));
	jQuery("#ic_input").on("input", function() {
		HtVw.ic_oninput();
	});
	jQuery("#ic_start").on("click", function() {
		HtVw.ic_start_onclike();
	});
	jQuery("#ic_pause").on("click", function() {
		HtVw.ic_pause_onclike();
	});
	jQuery("#ic_stop").on("click", function() {
		HtVw.ic_stop_onclike();
	});
	jQuery("#ic_text_copy").on("click", function() {
		HtVw.ic_text_copy_onclike();
	});
	jQuery("#ic_clear").on("click", function() {
		HtVw.ic_clear_onclike();
	});
	//
	jQuery("#ic_sponsor1").on("click", function() {
		HtVw.ic_hide(this,"#ic_sponsor1_content");
	});
	jQuery("#ic_sponsor2").on("click", function() {
		HtVw.ic_hide(this,"#ic_sponsor2_content");
	});
	jQuery("#ic_formula").on("click", function() {
		HtVw.ic_hide(this,"#ic_formula_content");
	});
	jQuery("#ic_display").on("click", function() {
		HtVw.ic_hide(this,"#ic_display_content");
	});
	//
	jQuery("#ic_display_all_on").on("click", function() {
		HtVw.ic_display_checkbox(this,true);
	});
	jQuery("#ic_display_all_of").on("click", function() {
		HtVw.ic_display_checkbox(this,false);
	});
	jQuery("#ic_display_dash_all_on").on("click", function() {
		HtVw.ic_display_checkbox(this,true);
	});
	jQuery("#ic_display_dash_all_of").on("click", function() {
		HtVw.ic_display_checkbox(this,false);
	});
	//
	jQuery("input:radio[id ^= 'ic_display_item_width']").on("change", function() {
		HtVw.ic_display_item_width();
	});
	jQuery("input:radio[id ^= 'ic_display_line']").on("change", function() {
		HtVw.ic_display_row();
	});
});

//-----------------------------------------------------------------------------

icollatz.css

/* iCollatz演算ブラウザ(BigInt)版(iCCBE:Infinite Collatz Calculator BigInt Edition) */
/* $Id$ */
/* (C)2021-2023 プログラミングの深淵を求めて https://www.seekabypro.com/ */
/* (C)2021-2023 どらテク(どらぐ~んテクノロジー) https://twitter.com/dratech2020 */

body,
select,
#icollatz {
	margin: 0px;
	padding: 2px;
	font-family: "MS ゴシック",monospace,Helvetica;
	font-size: 12pt;
	color: black;
	background-color: white;
}

.ic_label {
	line-height: 1.75em;
	padding: 0.1em;
	cursor: pointer;
	border: 1px solid #CCCCCC;
	border-radius: 0.25em;
	user-select: none;
}

.ic_label:has(> input:checked) {
	color: white;
	text-shadow: 1px 1px 1px black;
	background-color: #80A0FF;
}

.ic_label:hover {
	border:1px solid #FF6600;
	background-color:#FFFFCC;
	border-radius: 0.25em;
}

#ic_radix,
#ic_k {
	font-family: "MS ゴシック",monospace,Helvetica;
	text-align: right;
	width: 100px;
	font-size: 12pt;
}

#ic_input {
	font-family: "MS ゴシック",monospace,Helvetica;
	text-align: right;
	width: 400px;
	font-size: 12pt;
}

#ic_start_input {
	white-space: nowrap;
	overflow: auto;
	scrollbar-width: thin;
	display: block;
}

#ic_start, 
#ic_stop, 
#ic_pause,
#ic_clear,
#ic_text_copy,
#ic_display_all_on,
#ic_display_dash_all_on {
	border: 1px solid #606060;
	border-radius: 0.25em;
}

#ic_start,
#ic_display_all_on,
#ic_display_dash_all_on {
	color: #0000AA;
}

#ic_clear,
#ic_display_all_of,
#ic_display_dash_all_of {
	color: #FF0000;
}

#ic_start:disabled, 
#ic_stop:disabled, 
#ic_pause:disabled {
	background-color: #A0A0A0;
}

.ic_status,
.ic_goal_step,
.ic_goal_n_dash,
.ic_max_n ,
.ic_max_n_step ,
.ic_time,
.ic_display,
.ic_display_item_width,
.ic_display_line {
	font-size: 12pt;
	white-space: nowrap;
	overflow: auto;
	scrollbar-width: thin;
	display: block;
}

.ic_display_icollatz,
.ic_display_icollatz_dash,
.ic_display_text_type,
.ic_display_item_width {
	margin-bottom: 4px;
	overflow: auto;
	scrollbar-width: thin;
}

.ic_display_icollatz {
	border:2px solid #000000;
}

.ic_display_icollatz_dash {
	border:2px solid #008000;
}

.ic_display_text_type {
	border:2px solid #CC00CC;
}

.ic_display_item_width {
	border:2px solid #000000;
}

.ic_display_line {
	border:2px solid #0000FF;
}

#ic_status {
	text-shadow: 1px 1px 1px gray;
	font-weight: bold;
}


#ic_count_mzr,
#ic_count_mnz,
#ic_goal_step,
#ic_max_n_step,
#ic_max_n {
	text-shadow: 1px 1px 1px black;
	font-weight: bold;
}

#ic_count_mzr {
	color: #DDEBF7;
}

#ic_count_mnz {
	color: #FFF2CC;
}

#ic_goal_step {
	color: #C7A1E3;
}

#ic_max_n_step,
#ic_max_n {
	color: #C6E0B4;
}

.ic_list {
	margin: 0px;
	padding: 2px;
	font-size: 9pt;
	border:2px solid #0000FF;
	white-space: nowrap;
	width: auto;
	/* max-height: 480px; //js側 */
	overflow: auto;
	scrollbar-width: thin;
	display: block;
}

.ic_list_table {
	border-collapse: collapse;
	border-spacing: 0;
	border: none;
	padding: 0px;
	margin: 0px;
	/* width: 100%; */
}

.ic_text_MZR {
	color: #DDEBF7; /* IC_COLOR_MZR */
}

.ic_text_MNZ {
	color: #DDEBF7; /* IC_COLOR_MZR */
}

.ic_text_OPERATOR {
	color: #000080;
}

.ic_item,
.ic_head {
	padding: 0px;
	vertical-align: top;
}

.ic_tr,
.ic_th_HEAD,
.ic_td_MZR,
.ic_td_MNZ,
.ic_th_dash_HEAD,
.ic_td_dash_MZR,
.ic_td_dash_MNZ  {
	border:2px solid #000000;
	vertical-align: top;
	font-weight: normal;
	text-align: right;
	padding: 0px;
}

.ic_th_HEAD,
.ic_th_dash_HEAD  {
	text-align: center;
	background-color: #BDD7EE; /* IC_COLOR_HEAD */
}

.ic_th_dash_HEAD,
.ic_td_dash  {
	border:2px solid #008000;
}

.ic_td_MZR,
.ic_td_dash_MZR {
	background-color: #DDEBF7; /* IC_COLOR_MZR */
}

.ic_td_MNZ,
.ic_td_dash_MNZ  {
	background-color: #FFF2CC; /* IC_COLOR_MNZ */
}

.ic_item_step,
.ic_item_n,
.ic_item_n_radix,
.ic_item_calc,
.ic_item_calc_radix,
.ic_item_n_dash,
.ic_item_d,
.ic_item_n_dash_radix,
.ic_item_d_radix,
.ic_item_GOAL,
.ic_item_MAX,
.ic_item_SAME {
	padding: 1px;
	display: block;
	vertical-align: top;
}

.ic_item_GOAL {
	background-color: #C7A1E3; /* IC_COLOR_GOAL */
}

.ic_item_MAX {
	background-color: #C6E0B4; /* IC_COLOR_N_MAX */
}

.ic_item_SAME {
	background-color: #FF7F50; /* IC_COLOR_SAME */
}

.ic_item_width_scroll {
	max-width: 140px;
	overflow: auto;
	scrollbar-width: thin;
}

.ic_item_hide_span {
	cursor: pointer;
	user-select: none;
}

.ic_item_hide_display {
	display: none;
}

/*
.ic_list_pager_tr,
}
*/

.ic_list_pager_td {
	padding:0.1em 0.4em 0.1em 0;
	vertical-align: middle;
	text-align: left;
	white-space: nowrap;
}

.ic_list_pager_a_start,
.ic_list_pager_a_previos,
.ic_list_pager_a_content,
.ic_list_pager_a_next,
.ic_list_pager_a_end {
	text-align:center;
	margin:0 0.1em;
	padding:0.1em 0.2em 0.08em 0.2em;
	text-decoration:none;
	box-shadow: none;
	color:#555555;
	border:1px solid #CCCCCC;
	border-radius: 0.25em;
	background-color:#FFFFFF;
	user-select: none;
	cursor: pointer;
}

.ic_list_pager_td a:hover   {background-color:#FFCC99;}

.ic_list_pager_select {
	color:#000000;
	border:1px solid #000000;
	background-color: #80A0FF;
}

.ic_list_pager_hide {
	display: none;
}

.ic_list_pager_sel {
	font-size: 9pt;
	border: 1px solid #00AA00;
	background-color: #FFFFFF;
	text-align: right;
}

.ic_list_pager_opt {
	direction: rtl;
}

#ic_formula_content img {
	border: 2px solid blue;
}

#ic_formula_content>a:visited img{
	border: 2px solid  purple;
}

コメント

タイトルとURLをコピーしました