zoukankan      html  css  js  c++  java
  • 《算法》第六章部分程序 part 1

    ▶ 书中第六章部分程序,包括在加上自己补充的代码,粒子碰撞系统及用到的粒子类

    ● 粒子系统

      1 package package01;
      2 
      3 import java.awt.Color;
      4 import edu.princeton.cs.algs4.StdIn;
      5 import edu.princeton.cs.algs4.StdDraw;
      6 import edu.princeton.cs.algs4.MinPQ;
      7 import edu.princeton.cs.algs4.Particle;
      8 
      9 public class class01
     10 {
     11     private static final double HZ = 0.5;                               // 每个时间步长内重画的次数
     12     private MinPQ<Event> pq;                                            // 优先队列
     13     private double t = 0.0;                                             // 计时器
     14     private Particle[] particles;                                       // 粒子数据列表
     15 
     16     private static class Event implements Comparable<Event>             // 碰撞事件类
     17     {
     18         private final double time;                                      // 预计事件发生时间
     19         private final Particle a, b;                                    // 事件中的粒子
     20         private final int countA, countB;                               // 粒子在加入事件中时的已碰撞的次数
     21 
     22         public Event(double inputT, Particle inputA, Particle inputB)   // 输入当前时间和两个粒子,计算碰撞事件
     23         {
     24             time = inputT;
     25             a = inputA;
     26             b = inputB;
     27             countA = (a != null) ? a.count() : -1;
     28             countB = (b != null) ? b.count() : -1;
     29         }
     30 
     31         public int compareTo(Event that)                                // 比较两个事件哪个先发生
     32         {
     33             return Double.compare(this.time, that.time);
     34         }
     35 
     36         public boolean isValid()                                        // 判断事件是否有效
     37         {
     38             return (a == null || a.count() == countA) && (b == null || b.count() == countB);// 原代码简化版
     39                                                                                             //if (a != null && a.count() != countA || b != null && b.count() != countB)     // 原代码,只要有粒子当前实际碰撞数与事件中记录的 count 不等,说明事件失效
     40                                                                                             //    return false;
     41                                                                                             //return true;
     42         }
     43     }
     44 
     45     public class01(Particle[] inputParticle)
     46     {
     47         particles = inputParticle.clone();          // 输入列表的深拷贝
     48     }
     49 
     50     private void predict(Particle a, double limit)  // 更新优先队列中关于粒子 a 的事件
     51     {
     52         if (a == null)
     53             return;
     54         for (int i = 0; i < particles.length; i++)  // 预测 a 与各粒子碰撞的时间,只要时间小于阈值就将其放入优先队列
     55         {
     56             double targetTime = t + a.timeToHit(particles[i]);
     57             if (targetTime <= limit)
     58                 pq.insert(new Event(targetTime, a, particles[i]));
     59         }
     60         double targetTimeX = t + a.timeToHitVerticalWall(), targetTimeY = t + a.timeToHitHorizontalWall();
     61         if (targetTimeX <= limit)
     62             pq.insert(new Event(targetTimeX, a, null));
     63         if (targetTimeY <= limit)
     64             pq.insert(new Event(targetTimeY, null, a));
     65     }
     66 
     67     private void redraw(double limit)               // 重画所有粒子位置
     68     {
     69         StdDraw.clear();
     70         for (int i = 0; i < particles.length; i++)
     71             particles[i].draw();
     72         StdDraw.show();
     73         StdDraw.pause(20);                          // 暂停 20 ms
     74         if (t < limit)                              // 还没到时限,加入重画事件
     75             pq.insert(new Event(t + 1.0 / HZ, null, null));
     76     }
     77 
     78     public void simulate(double limit)              // 模拟器
     79     {
     80         pq = new MinPQ<Event>();
     81         for (int i = 0; i < particles.length; i++)  // 首次计算所有粒子之间的碰撞
     82             predict(particles[i], limit);
     83         for (pq.insert(new Event(0, null, null)); !pq.isEmpty();) // 多加入一个重画所有粒子位置的事件
     84         {
     85             Event e = pq.delMin();                  // 取出发生时间最近的时间,判断是否有效
     86             if (!e.isValid())
     87                 continue;
     88             Particle a = e.a, b = e.b;
     89             for (int i = 0; i < particles.length; i++)  // 更新所有粒子位置
     90                 particles[i].move(e.time - t);
     91             t = e.time;                             // 更新当前时间
     92 
     93             if (a != null && b != null)             // 粒子 - 粒子碰撞
     94                 a.bounceOff(b);
     95             else if (a != null && b == null)        // 粒子撞竖直墙壁
     96                 a.bounceOffVerticalWall();
     97             else if (a == null && b != null)
     98                 b.bounceOffHorizontalWall();        // 粒子撞水平墙壁
     99             else if (a == null && b == null)
    100                 redraw(limit);                      // 仅重画所有粒子位置
    101             predict(a, limit);                      // 重新预测 a 与 b相关的事件
    102             predict(b, limit);
    103         }
    104     }
    105 
    106     public static void main(String[] args)
    107     {
    108         StdDraw.setCanvasSize(600, 600);            // 窗口大小
    109         StdDraw.enableDoubleBuffering();            // double 缓冲区
    110         Particle[] particles;                       // 粒子列表
    111 
    112         if (args.length == 1)                       // 输入一个参数,生成相应个数的个粒子
    113         {
    114             int n = Integer.parseInt(args[0]);
    115             particles = new Particle[n];
    116             for (int i = 0; i < n; i++)
    117                 particles[i] = new Particle();
    118         }
    119         else                                        // 否则按标准输入流依次输入每个粒子的信息
    120         {
    121             int n = StdIn.readInt();
    122             particles = new Particle[n];
    123             for (int i = 0; i < n; i++)
    124             {
    125                 double rx = StdIn.readDouble();
    126                 double ry = StdIn.readDouble();
    127                 double vx = StdIn.readDouble();
    128                 double vy = StdIn.readDouble();
    129                 double radius = StdIn.readDouble();
    130                 double mass = StdIn.readDouble();
    131                 int r = StdIn.readInt();
    132                 int g = StdIn.readInt();
    133                 int b = StdIn.readInt();
    134                 Color color = new Color(r, g, b);
    135                 particles[i] = new Particle(rx, ry, vx, vy, radius, mass, color);
    136             }
    137         }
    138         class01 system = new class01(particles);    // 模拟和输出
    139         system.simulate(10000);                     // 模拟事件 10s
    140     }
    141 }

    ● 粒子类

    package package01;
    
    import java.awt.Color;
    import edu.princeton.cs.algs4.StdDraw;
    import edu.princeton.cs.algs4.StdRandom;
    
    public class class01
    {
        private static final double INFINITY = Double.POSITIVE_INFINITY;
    
        private double rx, ry;
        private double vx, vy;
        private int count;              // 粒子已经碰撞的次数
        private final double radius;
        private final double mass;
        private final Color color;
    
        public class01(double inputRx, double inputRy, double inputVx, double inputVy, double inputRadius, double inputMass, Color inputColor)
        {
            rx = inputRx;
            ry = inputRy;
            vx = inputVx;
            vy = inputVy;
            radius = inputRadius;
            mass = inputMass;
            color = inputColor;
        }
    
        public class01()
        {
            rx = StdRandom.uniform(0.0, 1.0);
            ry = StdRandom.uniform(0.0, 1.0);
            vx = StdRandom.uniform(-0.005, 0.005);
            vy = StdRandom.uniform(-0.005, 0.005);
            radius = 0.02;
            mass = 0.5;
            color = Color.BLACK;
        }
    
        public void move(double dt)
        {
            rx += vx * dt;
            ry += vy * dt;
        }
    
        public void draw()              // 绘制粒子
        {
            StdDraw.setPenColor(color);
            StdDraw.filledCircle(rx, ry, radius);
        }
    
        public int count()
        {
            return count;
        }
    
        public double timeToHit(class01 that)
        {
            if (this == that)
                return INFINITY;
            double dx = that.rx - rx, dy = that.ry - ry, dvx = that.vx - vx, dvy = that.vy - vy;
            double dvdr = dx * dvx + dy * dvy;
            if (dvdr > 0)                   // Δx 与 Δv 同号,不会撞
                return INFINITY;
            double dvdv = dvx * dvx + dvy * dvy;
            if (dvdv == 0)                  // 速度完全相等,不会撞
                return INFINITY;
            double drdr = dx * dx + dy * dy;
            double dist = radius + that.radius;
            double d = (dvdr*dvdr) - dvdv * (drdr - dist * dist);
            return (d > 0) ? -(dvdr + Math.sqrt(d)) / dvdv : INFINITY;
        }
    
        public double timeToHitVerticalWall()
        {
            return (vx > 0) ? (1.0 - rx - radius) / vx : ((vx < 0) ? (radius - rx) / vx : INFINITY);
        }
    
        public double timeToHitHorizontalWall()
        {
            return (vy > 0) ? (1.0 - ry - radius) / vy : ((vy < 0) ? (radius - ry) / vy : INFINITY);
        }
    
        public void bounceOff(class01 that)
        {
            double dx = that.rx - rx, dy = that.ry - ry;
            double dvx = that.vx - vx, dvy = that.vy - vy;
            double dvdr = dx * dvx + dy * dvy;
            double dist = radius + that.radius;
            double magnitude = 2 * mass * that.mass * dvdr / ((mass + that.mass) * dist);
            double fx = magnitude * dx / dist, fy = magnitude * dy / dist;
            vx += fx / mass;
            vy += fy / mass;
            that.vx -= fx / that.mass;
            that.vy -= fy / that.mass;
            count++;
            that.count++;
        }
    
        public void bounceOffVerticalWall()
        {
            vx = -vx;
            count++;
        }
    
        public void bounceOffHorizontalWall()
        {
            vy = -vy;
            count++;
        }
    
        public double kineticEnergy()
        {
            return 0.5 * mass * (vx*vx + vy * vy);
        }
    }
  • 相关阅读:
    图片转字符图片(三)
    图片转字符图片(二)
    图片转字符图片(一)
    github访问不到,登陆不上
    jdk安装错误1316,jdk-10.0.1
    windows安装mongodb
    T4模板使用-初探
    Sql server 查看表引用、依赖项,删除表及约束 脚本
    安装ORACLE provider for OLE DB
    Windows Server 2012 r2 显示计算机图标
  • 原文地址:https://www.cnblogs.com/cuancuancuanhao/p/9945059.html
Copyright © 2011-2022 走看看