package com.shemnon.btc.analysis; import com.shemnon.btc.model.ICoin; import com.shemnon.btc.model.ITx; import java.util.ArrayList; import java.util.Deque; import java.util.LinkedList; import java.util.List; /** * * Created by shemnon on 18 Mar 2014. */ public class Pyramid { public static boolean isPyramidStep(ITx tx) { // idiot check if (tx == null) return false; // pyramid steps must have: // * 1 input // * 2 or more outputs // * each output has no worse than a 2:1 to each other output if (tx.getInputs().size() > 1) return false; List<ICoin> outputs = tx.getOutputs(); if (outputs.size() < 2) return false; for (int i = 0; i < outputs.size(); i++) { for (int j = i+1; j < outputs.size(); j++) { double ratio = outputs.get(i).getValue() / outputs.get(j).getValue(); if (ratio < 0.5 || ratio > 2.0) return false; } } return true; } public static List<ITx> climbPyramid(ITx tx, int limit) { List<ITx> upwards = new ArrayList<>(); ITx step = tx; while (step != null && (limit-- > 0)) { if (!isPyramidStep(step)) break; upwards.add(step); step = step.getInputs().get(0).getSourceTX(); } return upwards; } public static List<ITx> descendPyramid(ITx tx, int limit) { Deque<ITx> parents = new LinkedList<>(); parents.add(tx); parents.add(null); List<ITx> results = new ArrayList<>(); if (isPyramidStep(tx)) { results.add(tx); } while (!parents.isEmpty()) { ITx parent = parents.removeFirst(); if (parent == null) { // null is the full row marker if (limit-- < 1) { break; } parents.addLast(null); } else { parent.getOutputs().forEach(coin -> { ITx otx = coin.getTargetTX(); if (Pyramid.isPyramidStep(otx)) { results.add(otx); parents.addLast(otx); } } ); } } return results; } }