<file_sep>package com.game;

public class RuleManager {
    public boolean breakShot = true;
    public boolean firstIn = false;
    public boolean pocketed8 = false;

    public boolean pocketed = false;
    public boolean pocketedCue = false;
    public boolean hitAnother = false;
    public boolean correctFirstHit = true;

    public RuleManager(){

    }

    public boolean checkForFoul(){
        return !breakShot && (!pocketed || !hitAnother || !correctFirstHit || pocketedCue);
    }

    public boolean changeTurn(){
        return checkForFoul() || !pocketed;
    }

    public boolean rebreak(){
        return false;
    }

    public void resetValues(){
        breakShot = false;
        pocketed = false;
        pocketedCue = false;
        hitAnother = false;
        correctFirstHit = false;

    }

    public boolean win(boolean p1Turn, int p1s, int p2s){
        if(p1Turn){
            if(p1s == 0 && pocketed8)
                return true;
        }
        else{
            if(p2s == 0 && pocketed8)
                return true;
        }
        return false;
    }

    public boolean lose(boolean p1Turn, int p1s, int p2s){
        if(!breakShot){
            if(p1Turn){
                if(p1s != 0 && pocketed8)
                    return true;
            }
            else{
                if(p2s != 0 && pocketed8)
                    return true;
            }
        }
        return false;
    }

    @Override
    public String toString() {
        return "RuleManager{" +
                "breakShot=" + breakShot +
                ", firstIn=" + firstIn +
                ", pocketed=" + pocketed +
                ", pocketed8=" + pocketed8 +
                ", pocketedCue=" + pocketedCue +
                ", hitAnother=" + hitAnother +
                ", correctFirstHit=" + correctFirstHit +
                '}';
    }
}
<file_sep>package com.physics;

import java.awt.*;
import java.awt.geom.Rectangle2D;

public class Vector2D {
    public double x, y;

    public Vector2D(double x, double y){
        this.x = x;
        this.y = y;
    }

    public Vector2D(Vector2D v){
        this.x = v.x;
        this.y = v.y;
    }

    public Vector2D(Point p){
        this.x = p.x;
        this.y = p.y;
    }

    public Vector2D(Segment s){
        this.x = s.end.x - s.start.x;
        this.y = s.end.y - s.start.y;
    }

    public boolean equals(Vector2D v){
        return this.x == v.x && this.y == v.y;
    }

    @Override
    public String toString() {
        return "Vector2D{" +
                "x=" + x +
                ", y=" + y +
                '}';
    }

    public Vector2D add(Vector2D v){
        this.x += v.x;
        this.y += v.y;
        return this;
    }

    public Vector2D sum(Vector2D v){
        return new Vector2D(this).add(v);
    }

    public Vector2D subtract(Vector2D v){
        this.x -= v.x;
        this.y -= v.y;
        return this;
    }

    public Vector2D difference(Vector2D v){
        return new Vector2D(this).subtract(v);
    }

    public Vector2D multiply(double a){
        this.x *= a;
        this.y *= a;
        return this;
    }

    public Vector2D times(double a){
        return new Vector2D(this).multiply(a);
    }

    public double length(){
        return Math.sqrt(this.dotProduct(this));
    }

    public Vector2D normalize(){
        if(this.isNull())
            return this;
        double l = this.length();
        if(l != 0.0) {
            this.x /= l;
            this.y /= l;
        }
        return this;
    }

    public Vector2D unit(){
        return new Vector2D(this).normalize();
    }

    public double dotProduct(Vector2D v){
        return this.x * v.x + this.y * v.y;
    }

    public boolean isNull(){
        return this.x == 0 && this.y == 0;
    }

    public Vector2D opposite() {
        return new Vector2D(this).multiply(-1);
    }

    public double dot(Vector2D v) {
        return this.dotProduct(v);
    }

    public boolean in(Rectangle2D.Double r){
        return this.x > r.x && this.y > r.y && this.x < r.x + r.width && this.y < r.y + r.height;
    }

    public Vector2D rotate(double angle){
        double x1 = this.x, y1 = this.y;
        double s = Math.sin(angle), c = Math.cos(angle);
        this.x = x1 * c - y1 * s;
        this.y = x1 * s + y1 * c;
        return this;
    }

    public Vector2D rotated(double angle){
        return new Vector2D(this).rotate(angle);
    }

    public void reflect(Vector2D v){
        v.rotate(-2 * Math.acos(this.unit().dot(v.unit())));
    }


}
<file_sep>package com.game;

import com.physics.Segment;
import com.physics.Vector2D;

import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.io.IOException;
import java.util.ArrayList;

public class WhiteBall extends Ball {
    public WhiteBall(Vector2D position, Vector2D velocity) throws IOException {
        super(position, velocity, 0);
    }

}
<file_sep># 8ballpool
 8 ball pool game in java
<file_sep>package com.game;

import com.physics.Segment;
import com.physics.Vector2D;

import javax.imageio.ImageIO;
import java.awt.*;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;

public class BallHandler {
    private ArrayList<Ball> balls = new ArrayList<>();
    private ArrayList<Socket> socks;
    private ArrayList<Ball> forRemoval = new ArrayList<>();
    public ArrayList<Ball> getBalls() {
        return balls;
    }
    private ArrayList<Segment> sides;
    private RuleManager ruleManager;
    private Player p1, p2;

    public BallHandler(ArrayList<Socket> socks, ArrayList<Segment> sides, RuleManager rm, Player p1, Player p2) throws IOException {
        balls.add(new WhiteBall(new Vector2D(720, 240), new Vector2D(0 ,0)));
        double r = balls.get(0).getRadius();
        double s = r * Math.sqrt(3);
        balls.add(new Ball(new Vector2D(150 + 2 * s, 240 + 2 * r), new Vector2D(0, 0),1));
        balls.add(new Ball(new Vector2D(150, 240 - 2 * r), new Vector2D(0,0), 2));
        balls.add(new Ball(new Vector2D(150 + s, 240 + r), new Vector2D(0, 0),3));
        balls.add(new Ball(new Vector2D(150, 240 + 2 * r), new Vector2D(0, 0),4));
        balls.add(new Ball(new Vector2D(150, 240 + 4 * r), new Vector2D(0, 0),5));
        balls.add(new Ball(new Vector2D(150 + s, 240 - 3 * r), new Vector2D(0, 0),6));
        balls.add(new Ball(new Vector2D(150 + 3 * s, 240 - r), new Vector2D(0, 0),7));
        balls.add(new Ball(new Vector2D(150 + 2 * s, 240), new Vector2D(0, 0),8));
        balls.add(new Ball(new Vector2D(150 + 4 * s, 240), new Vector2D(0, 0),9));
        balls.add(new Ball(new Vector2D(150 + s, 240 - r), new Vector2D(0, 0),10));
        balls.add(new Ball(new Vector2D(150, 240 - 4 * r), new Vector2D(0,0), 11));
        balls.add(new Ball(new Vector2D(150 + 3 * s, 240 + r), new Vector2D(0, 0),12));
        balls.add(new Ball(new Vector2D(150, 240), new Vector2D(0, 0),13));
        balls.add(new Ball(new Vector2D(150 + s, 240 + 3 * r), new Vector2D(0, 0),14));
        balls.add(new Ball(new Vector2D(150 + 2 * s, 240 - 2 * r), new Vector2D(0, 0),15));
        this.socks = socks;
        this.sides = sides;
        this.p1 = p1;
        this.p2 = p2;
        ruleManager = rm;
    }

    public void tick(boolean p1Turn){
        for(Ball ball : balls) {
            ball.tick(sides);
            for(Socket sock : socks){
                if(sock.socketed(ball)){
                    forRemoval.add(ball);
                    if(!(ball instanceof WhiteBall) && !(ball.getNum() == 8))
                        ruleManager.pocketed = true;
                    break;
                }
            }
        }
        for(Ball ball : forRemoval){
            if(!(ball instanceof WhiteBall)) {
                balls.remove(ball);
                if(!ruleManager.breakShot && !ruleManager.firstIn && ball.getNum() != 8){
                    //dont touch this, is actually necessary
                    ruleManager.correctFirstHit = true;
                    ruleManager.firstIn = true;

                    if(p1Turn){
                            for(Ball b: balls){
                                if(ball.sameSuit(b)) {
                                    p1.addBall(b);
                                }
                                else if(b.getNum() != 0 && b.getNum() != 8){
                                    p2.addBall(b);
                                }
                            }
                    }
                    else{
                        for(Ball b: balls){
                            if(ball.sameSuit(b)){
                                p2.addBall(b);
                            }
                            else if(b.getNum() != 0 && b.getNum() != 8){
                                p1.addBall(b);
                            }
                        }
                    }
                }
                else if(ball.getNum() != 0 && ball.getNum() != 8){
                    p1.removeBall(ball);
                    p2.removeBall(ball);
                    if(ball.getNum() == 8){
                        ruleManager.pocketed8 = true;
                    }
                    if(p1.getBalls().size() == 0){
                        for(Ball b : balls){
                            if(ball.getNum() == 8){
                                p1.addBall(b);
                            }
                        }
                    }
                    else if(p2.getBalls().size() == 0){
                        for(Ball b : balls){
                            if(ball.getNum() == 8){
                                p2.addBall(b);
                            }
                        }
                    }
                }
                if(ball.getNum() == 8 && !ruleManager.breakShot){
                    ruleManager.pocketed8 = true;
                }
            }
            else {
                ball.setPosition(-50, -50);
                ball.velocity = new Vector2D(0, 0);
                ruleManager.pocketedCue = true;
            }
        }

        forRemoval.removeIf((x) -> true);

        for(Ball ball : balls){
            for(Ball b : balls)
                if(ball.getNum() < b.getNum()) {
                    if (ball.resolveCollision(b)) {
                        if (ruleManager.firstIn) {
                            if (p1Turn) {
                                if (!ruleManager.hitAnother) {
                                    ruleManager.hitAnother = true;
                                    System.out.println(b);
                                    if (p1.getBalls().contains(b)) {
                                        ruleManager.correctFirstHit = true;
                                    }
                                }
                            } else {
                                if (!ruleManager.hitAnother) {
                                    ruleManager.hitAnother = true;
                                    System.out.println(b);
                                    if (p2.getBalls().contains(b)) {
                                        System.out.println(b);
                                        ruleManager.correctFirstHit = true;
                                    }
                                }
                            }
                        }
                        else{
                            ruleManager.hitAnother = true;
                        }
                    }
                }
        }
    }

    public void render(Graphics g){
        for(Ball ball : balls) {
            ball.render(g);
        }
    }

    public boolean checkForMovement(){
        for(Ball ball : balls)
            if(!ball.velocity.isNull())
                return true;
        return false;
    }

    public WhiteBall getWhiteBall(){
        return (WhiteBall) this.balls.get(0);
    }

}
