Code Sketch


kundali
By: Mhalsakant School
Category: Programming
import javax.swing._
import java.awt._
import java.awt.event._
import java.awt.geom._
import scala.util.Random

// ============================================================
// KUNDALI PURAN - FULL SINGLE FILE SCALA SWING APP
// ============================================================

val frame = new JFrame("Kundali Puran - Divine Astrology")

frame.setSize(1150, 780)
frame.setResizable(false)

val root = new JPanel(new BorderLayout())
root.setBackground(new Color(8, 10, 28))

// ============================================================
// ANIMATED BACKGROUND
// ============================================================

val background = new JPanel() {

  val rnd = new Random(12345)

  val starsX = Array.fill(180)(rnd.nextInt(1150))
  val starsY = Array.fill(180)(rnd.nextInt(780))
  val starsSize = Array.fill(180)(1 + rnd.nextInt(3))
  val starsSpeed = Array.fill(180)(0.2 + rnd.nextDouble() * 1.2)

  var angle = 0.0
  var pulse = 0.0
  var moonX = -100.0

  setOpaque(true)

  override def paintComponent(g: Graphics): Unit = {
    super.paintComponent(g)

    val g2 = g.asInstanceOf[Graphics2D]

    g2.setRenderingHint(
      RenderingHints.KEY_ANTIALIASING,
      RenderingHints.VALUE_ANTIALIAS_ON
    )

    val w = getWidth
    val h = getHeight

    // --------------------------------------------------------
    // BACKGROUND GRADIENT
    // --------------------------------------------------------

    val gradient = new GradientPaint(
      0,
      0,
      new Color(7, 9, 30),
      w,
      h,
      new Color(35, 12, 62)
    )

    g2.setPaint(gradient)
    g2.fillRect(0, 0, w, h)

    // --------------------------------------------------------
    // STARS
    // --------------------------------------------------------

    var i = 0

    while (i < starsX.length) {

      val alpha =
        (130 + 100 * Math.abs(Math.sin(pulse + i * 0.17))).toInt

      g2.setColor(
        new Color(
          255,
          235,
          150,
          Math.max(50, Math.min(255, alpha))
        )
      )

      g2.fillOval(
        starsX(i),
        starsY(i),
        starsSize(i),
        starsSize(i)
      )

      i += 1
    }

    // --------------------------------------------------------
    // BIG COSMIC GLOW
    // --------------------------------------------------------

    val cx = w / 2
    val cy = h / 2

    var r = 330

    while (r > 40) {

      val alpha = (2 + (340 - r) / 25)

      g2.setColor(
        new Color(
          255,
          190,
          60,
          Math.min(25, alpha)
        )
      )

      g2.drawOval(
        cx - r,
        cy - r,
        r * 2,
        r * 2
      )

      r -= 20
    }

    // --------------------------------------------------------
    // ORBIT RINGS
    // --------------------------------------------------------

    g2.setStroke(new BasicStroke(1.2f))

    var ring = 110

    while (ring <= 310) {

      g2.setColor(
        new Color(
          255,
          200,
          80,
          45
        )
      )

      g2.drawOval(
        cx - ring,
        cy - ring,
        ring * 2,
        ring * 2
      )

      ring += 40
    }

    // --------------------------------------------------------
    // MOVING PLANET
    // --------------------------------------------------------

    val px =
      cx + Math.cos(angle) * 250

    val py =
      cy + Math.sin(angle) * 150

    g2.setColor(new Color(100, 150, 255, 50))
    g2.fillOval(
      (px - 28).toInt,
      (py - 28).toInt,
      56,
      56
    )

    g2.setColor(new Color(110, 170, 255))
    g2.fillOval(
      (px - 12).toInt,
      (py - 12).toInt,
      24,
      24
    )

    // --------------------------------------------------------
    // GOLDEN ORB
    // --------------------------------------------------------

    val orbPulse =
      75 + (Math.sin(pulse) * 8).toInt

    g2.setColor(
      new Color(
        255,
        190,
        60,
        35
      )
    )

    g2.fillOval(
      cx - orbPulse,
      cy - orbPulse,
      orbPulse * 2,
      orbPulse * 2
    )

    // --------------------------------------------------------
    // DECORATIVE LOTUS
    // --------------------------------------------------------

    val lotusY = h - 75

    g2.setColor(new Color(255, 190, 80, 120))

    var p = 0

    while (p < 7) {

      val lx =
        cx + (p - 3) * 28

      val path = new Path2D.Double()

      path.moveTo(lx, lotusY)
      path.curveTo(
        lx - 20,
        lotusY - 20,
        lx - 18,
        lotusY - 45,
        lx,
        lotusY - 55
      )

      path.curveTo(
        lx + 18,
        lotusY - 45,
        lx + 20,
        lotusY - 20,
        lx,
        lotusY
      )

      g2.fill(path)

      p += 1
    }

    // --------------------------------------------------------
    // UPDATE ANIMATION
    // --------------------------------------------------------

    angle += 0.012
    pulse += 0.045
    moonX += 0.6

    if (moonX > w + 100) {
      moonX = -100
    }
  }
}

background.setLayout(null)

// ============================================================
// TITLE
// ============================================================

val title = new JLabel(
  "<html><center><font color='#FFD76A' size='6'>? KUNDALI PURAN ?</font><br>" +
  "<font color='#FFF1B0' size='3'>Divine Astrology ? Rashi ? Cosmic Guidance</font></center></html>",
  SwingConstants.CENTER
)

title.setBounds(190, 20, 770, 105)
title.setOpaque(false)

background.add(title)

// ============================================================
// MAIN CARD
// ============================================================

val card = new JPanel()
card.setLayout(null)
card.setBackground(new Color(15, 14, 40, 235))
card.setBorder(
  BorderFactory.createLineBorder(
    new Color(255, 205, 90),
    2
  )
)

card.setBounds(85, 135, 980, 555)

background.add(card)

// ============================================================
// FORM TITLE
// ============================================================

val formTitle = new JLabel(
  "? Enter Your Birth Details ?",
  SwingConstants.CENTER
)

formTitle.setForeground(new Color(255, 220, 120))
formTitle.setFont(new Font("Serif", Font.BOLD, 27))
formTitle.setBounds(235, 18, 510, 45)

card.add(formTitle)

// ============================================================
// LABEL FUNCTION
// ============================================================

def makeLabel(
    text: String,
    x: Int,
    y: Int
): JLabel = {

  val l = new JLabel(text)

  l.setForeground(new Color(245, 235, 210))
  l.setFont(new Font("SansSerif", Font.BOLD, 15))
  l.setBounds(x, y, 180, 30)

  card.add(l)

  l
}

// ============================================================
// TEXT FIELD FUNCTION
// ============================================================

def makeField(
    x: Int,
    y: Int,
    width: Int
): JTextField = {

  val f = new JTextField()

  f.setFont(new Font("SansSerif", Font.PLAIN, 16))
  f.setForeground(new Color(30, 25, 45))
  f.setBackground(new Color(250, 245, 230))
  f.setBorder(
    BorderFactory.createLineBorder(
      new Color(220, 170, 70),
      1
    )
  )

  f.setBounds(x, y, width, 35)

  card.add(f)

  f
}

// ============================================================
// FORM FIELDS
// ============================================================

makeLabel("First Name", 55, 85)
val firstName = makeField(220, 82, 250)

makeLabel("Surname", 55, 135)
val surname = makeField(220, 132, 250)

makeLabel("Birth Date", 55, 185)
val birthDate = makeField(220, 182, 250)
birthDate.setToolTipText("Example: 15/08/2010")

makeLabel("Birth Time", 55, 235)
val birthTime = makeField(220, 232, 250)
birthTime.setToolTipText("Example: 14:30")

makeLabel("Birth Place", 55, 285)
val birthPlace = makeField(220, 282, 250)

// ============================================================
// RIGHT SIDE INFORMATION
// ============================================================

val infoBox = new JTextArea()

infoBox.setEditable(false)
infoBox.setLineWrap(true)
infoBox.setWrapStyleWord(true)
infoBox.setFont(new Font("Serif", Font.PLAIN, 16))
infoBox.setForeground(new Color(255, 239, 185))
infoBox.setBackground(new Color(25, 20, 55))
infoBox.setBorder(
  BorderFactory.createTitledBorder(
    BorderFactory.createLineBorder(
      new Color(255, 200, 80),
      1
    ),
    " ? Kundali Preview ? ",
    0,
    0,
    new Font("Serif", Font.BOLD, 16),
    new Color(255, 210, 100)
  )
)

infoBox.setText(
  "\n  Welcome to Kundali Puran.\n\n" +
  "  Enter your birth details and press\n" +
  "  GENERATE KUNDALI.\n\n" +
  "  The application will show:\n\n" +
  "  ? Rashi\n" +
  "  ? Rashi symbol\n" +
  "  ? Element\n" +
  "  ? Planet association\n" +
  "  ? Traditional deity association\n" +
  "  ? Lucky number\n" +
  "  ? General guidance\n\n" +
  "  Note: This is a traditional,\n" +
  "  entertainment-style astrology reading."
)

infoBox.setBounds(520, 82, 410, 295)

card.add(infoBox)

// ============================================================
// STATUS
// ============================================================

val status = new JLabel(
  "? Ready to generate your Kundali"
)

status.setForeground(new Color(150, 240, 180))
status.setFont(new Font("SansSerif", Font.BOLD, 14))
status.setBounds(520, 395, 410, 30)

card.add(status)

// ============================================================
// RESULT DATA
// ============================================================

case class AstroInfo(
  rashi: String,
  symbol: String,
  element: String,
  planet: String,
  deity: String,
  lucky: Int,
  nature: String,
  guidance: String
)

// ============================================================
// RASHI FUNCTION
// ============================================================

def getRashi(day: Int, month: Int): AstroInfo = {

  if ((month == 3 && day >= 21) || (month == 4 && day <= 19)) {

    AstroInfo(
      "Mesha (Aries)",
      "?",
      "Agni",
      "Mangal",
      "Shri Hanuman",
      9,
      "Energetic, direct and courageous",
      "Focus your energy on useful goals and avoid rushing decisions."
    )

  } else if ((month == 4 && day >= 20) || (month == 5 && day <= 20)) {

    AstroInfo(
      "Vrishabha (Taurus)",
      "?",
      "Prithvi",
      "Shukra",
      "Maa Lakshmi",
      6,
      "Patient, practical and steady",
      "Consistency and patience can help you move toward your goals."
    )

  } else if ((month == 5 && day >= 21) || (month == 6 && day <= 20)) {

    AstroInfo(
      "Mithuna (Gemini)",
      "?",
      "Vayu",
      "Budha",
      "Shri Ganesha",
      5,
      "Curious, communicative and adaptable",
      "Learning and communication can become important strengths."
    )

  } else if ((month == 6 && day >= 21) || (month == 7 && day <= 22)) {

    AstroInfo(
      "Karka (Cancer)",
      "?",
      "Jala",
      "Chandra",
      "Shiva",
      2,
      "Caring, emotional and intuitive",
      "Balance emotions with practical thinking."
    )

  } else if ((month == 7 && day >= 23) || (month == 8 && day <= 22)) {

    AstroInfo(
      "Simha (Leo)",
      "?",
      "Agni",
      "Surya",
      "Surya Dev",
      1,
      "Confident, expressive and warm",
      "Leadership is useful when combined with patience and listening."
    )

  } else if ((month == 8 && day >= 23) || (month == 9 && day <= 22)) {

    AstroInfo(
      "Kanya (Virgo)",
      "?",
      "Prithvi",
      "Budha",
      "Shri Ganesha",
      5,
      "Analytical, organized and thoughtful",
      "Small consistent improvements can produce strong results."
    )

  } else if ((month == 9 && day >= 23) || (month == 10 && day <= 22)) {

    AstroInfo(
      "Tula (Libra)",
      "?",
      "Vayu",
      "Shukra",
      "Maa Lakshmi",
      6,
      "Balanced, social and diplomatic",
      "Consider different viewpoints before making important choices."
    )

  } else if ((month == 10 && day >= 23) || (month == 11 && day <= 21)) {

    AstroInfo(
      "Vrishchika (Scorpio)",
      "?",
      "Jala",
      "Mangal",
      "Shri Hanuman",
      9,
      "Focused, determined and intense",
      "Use determination constructively and give yourself time to reflect."
    )

  } else if ((month == 11 && day >= 22) || (month == 12 && day <= 21)) {

    AstroInfo(
      "Dhanu (Sagittarius)",
      "?",
      "Agni",
      "Guru",
      "Shri Vishnu",
      3,
      "Optimistic, adventurous and curious",
      "Exploration and learning may open new possibilities."
    )

  } else if ((month == 12 && day >= 22) || (month == 1 && day <= 19)) {

    AstroInfo(
      "Makara (Capricorn)",
      "?",
      "Prithvi",
      "Shani",
      "Shani Dev",
      8,
      "Disciplined, patient and responsible",
      "Steady effort is more useful than trying to do everything at once."
    )

  } else if ((month == 1 && day >= 20) || (month == 2 && day <= 18)) {

    AstroInfo(
      "Kumbha (Aquarius)",
      "?",
      "Vayu",
      "Shani",
      "Shani Dev",
      8,
      "Independent, inventive and thoughtful",
      "New ideas can grow when combined with practical planning."
    )

  } else {

    AstroInfo(
      "Meena (Pisces)",
      "?",
      "Jala",
      "Guru",
      "Shri Vishnu",
      3,
      "Imaginative, compassionate and intuitive",
      "Creativity and kindness can be valuable strengths."
    )
  }
}

// ============================================================
// LUCKY NUMBER
// ============================================================

def calculateNumber(
    name: String,
    day: Int,
    month: Int,
    year: Int
): Int = {

  var total = day + month + year

  var i = 0

  while (i < name.length) {

    total += name.charAt(i).toInt

    i += 1
  }

  while (total > 9) {

    var sum = 0
    var n = total

    while (n > 0) {
      sum += n % 10
      n = n / 10
    }

    total = sum
  }

  if (total == 0) 1 else total
}

// ============================================================
// GENERATE BUTTON
// ============================================================

val generateButton = new JButton(
  "?  GENERATE KUNDALI  ?"
)

generateButton.setFont(
  new Font("SansSerif", Font.BOLD, 16)
)

generateButton.setForeground(Color.WHITE)
generateButton.setBackground(
  new Color(170, 90, 25)
)

generateButton.setFocusPainted(false)
generateButton.setBounds(70, 355, 400, 50)

card.add(generateButton)

// ============================================================
// CLEAR BUTTON
// ============================================================

val clearButton = new JButton(
  "CLEAR"
)

clearButton.setFont(
  new Font("SansSerif", Font.BOLD, 14)
)

clearButton.setForeground(Color.WHITE)
clearButton.setBackground(
  new Color(70, 55, 100)
)

clearButton.setFocusPainted(false)
clearButton.setBounds(70, 420, 190, 45)

card.add(clearButton)

// ============================================================
// EXIT BUTTON
// ============================================================

val exitButton = new JButton(
  "EXIT"
)

exitButton.setFont(
  new Font("SansSerif", Font.BOLD, 14)
)

exitButton.setForeground(Color.WHITE)
exitButton.setBackground(
  new Color(85, 45, 60)
)

exitButton.setFocusPainted(false)
exitButton.setBounds(280, 420, 190, 45)

card.add(exitButton)

// ============================================================
// GENERATE ACTION
// ============================================================

generateButton.addActionListener(
  new ActionListener {

    override def actionPerformed(
      e: ActionEvent
    ): Unit = {

      val nameText =
        firstName.getText.trim

      val surnameText =
        surname.getText.trim

      val dateText =
        birthDate.getText.trim

      val timeText =
        birthTime.getText.trim

      val placeText =
        birthPlace.getText.trim

      if (
        nameText.isEmpty ||
        surnameText.isEmpty ||
        dateText.isEmpty ||
        timeText.isEmpty ||
        placeText.isEmpty
      ) {

        JOptionPane.showMessageDialog(
          frame,
          "Please fill all birth details.",
          "Missing Details",
          JOptionPane.WARNING_MESSAGE
        )

      } else {

        val dateParts =
          dateText.split("/")

        val timeParts =
          timeText.split(":")

        if (
          dateParts.length != 3 ||
          timeParts.length != 2
        ) {

          JOptionPane.showMessageDialog(
            frame,
            "Use Date: DD/MM/YYYY\nUse Time: HH:MM",
            "Invalid Format",
            JOptionPane.ERROR_MESSAGE
          )

        } else {

          try {

            val day =
              dateParts(0).toInt

            val month =
              dateParts(1).toInt

            val year =
              dateParts(2).toInt

            val hour =
              timeParts(0).toInt

            val minute =
              timeParts(1).toInt

            if (
              day < 1 ||
              day > 31 ||
              month < 1 ||
              month > 12 ||
              year < 1900 ||
              year > 2100 ||
              hour < 0 ||
              hour > 23 ||
              minute < 0 ||
              minute > 59
            ) {

              JOptionPane.showMessageDialog(
                frame,
                "Please enter a valid date and time.",
                "Invalid Details",
                JOptionPane.ERROR_MESSAGE
              )

            } else {

              status.setText(
                "? Reading cosmic information..."
              )

              status.setForeground(
                new Color(255, 220, 100)
              )

              generateButton.setEnabled(false)

              val timer =
                new javax.swing.Timer(
                  900,
                  null
                )

              timer.addActionListener(
                new ActionListener {

                  override def actionPerformed(
                    ev: ActionEvent
                  ): Unit = {

                    timer.stop()

                    val astro =
                      getRashi(day, month)

                    val fullName =
                      nameText + " " + surnameText

                    val lucky =
                      calculateNumber(
                        fullName,
                        day,
                        month,
                        year
                      )

                    val sb =
                      new StringBuilder

                    sb.append("\n")
                    sb.append(
                      "        ? YOUR KUNDALI ?\n"
                    )
                    sb.append("\n")
                    sb.append(
                      "  Name      : "
                    )
                    sb.append(fullName)
                    sb.append("\n")

                    sb.append(
                      "  Birth     : "
                    )
                    sb.append(dateText)
                    sb.append("  ")
                    sb.append(timeText)
                    sb.append("\n")

                    sb.append(
                      "  Place     : "
                    )
                    sb.append(placeText)
                    sb.append("\n\n")

                    sb.append(
                      "  RASHI     : "
                    )
                    sb.append(astro.rashi)
                    sb.append(" ")
                    sb.append(astro.symbol)
                    sb.append("\n")

                    sb.append(
                      "  Element   : "
                    )
                    sb.append(astro.element)
                    sb.append("\n")

                    sb.append(
                      "  Planet    : "
                    )
                    sb.append(astro.planet)
                    sb.append("\n")

                    sb.append(
                      "  Deity     : "
                    )
                    sb.append(astro.deity)
                    sb.append("\n")

                    sb.append(
                      "  Lucky No. : "
                    )
                    sb.append(lucky)
                    sb.append("\n\n")

                    sb.append(
                      "  NATURE\n"
                    )
                    sb.append(
                      "  "
                    )
                    sb.append(astro.nature)
                    sb.append("\n\n")

                    sb.append(
                      "  GENERAL GUIDANCE\n"
                    )
                    sb.append(
                      "  "
                    )
                    sb.append(astro.guidance)
                    sb.append("\n\n")

                    sb.append(
                      "  ? DEVACHA HATH - Traditional association\n"
                    )
                    sb.append(
                      "  According to this simple rashi-based reading,\n"
                    )
                    sb.append(
                      "  the traditional deity association is: "
                    )
                    sb.append(astro.deity)
                    sb.append("\n\n")

                    sb.append(
                      "  ? This reading is for traditional/entertainment\n"
                    )
                    sb.append(
                      "    purposes and is not a scientific prediction."
                    )

                    infoBox.setText(
                      sb.toString
                    )

                    status.setText(
                      "? Kundali generated successfully"
                    )

                    status.setForeground(
                      new Color(130, 255, 170)
                    )

                    generateButton.setEnabled(true)
                  }
                }
              )

              timer.setRepeats(false)
              timer.start()
            }

          } catch {

            case _: NumberFormatException =>

              JOptionPane.showMessageDialog(
                frame,
                "Date and time must contain numbers only.\n\nExample:\n15/08/2010\n14:30",
                "Invalid Input",
                JOptionPane.ERROR_MESSAGE
              )
          }
        }
      }
    }
  }
)

// ============================================================
// CLEAR ACTION
// ============================================================

clearButton.addActionListener(
  new ActionListener {

    override def actionPerformed(
      e: ActionEvent
    ): Unit = {

      firstName.setText("")
      surname.setText("")
      birthDate.setText("")
      birthTime.setText("")
      birthPlace.setText("")

      infoBox.setText(
        "\n  Welcome to Kundali Puran.\n\n" +
        "  Enter your birth details and press\n" +
        "  GENERATE KUNDALI.\n\n" +
        "  The application will show:\n\n" +
        "  ? Rashi\n" +
        "  ? Rashi symbol\n" +
        "  ? Element\n" +
        "  ? Planet association\n" +
        "  ? Traditional deity association\n" +
        "  ? Lucky number\n" +
        "  ? General guidance\n\n" +
        "  Note: This is a traditional,\n" +
        "  entertainment-style astrology reading."
      )

      status.setText(
        "? Ready to generate your Kundali"
      )

      status.setForeground(
        new Color(150, 240, 180)
      )
    }
  }
)

// ============================================================
// EXIT ACTION
// ============================================================

exitButton.addActionListener(
  new ActionListener {

    override def actionPerformed(
      e: ActionEvent
    ): Unit = {

      frame.dispose()
    }
  }
)

// ============================================================
// ANIMATION TIMER
// ============================================================

val animationTimer =
  new javax.swing.Timer(
    35,
    new ActionListener {

      override def actionPerformed(
        e: ActionEvent
      ): Unit = {

        background.repaint()
      }
    }
  )

animationTimer.start()

// ============================================================
// ADD EVERYTHING
// ============================================================

root.add(
  background,
  BorderLayout.CENTER
)

frame.setContentPane(root)
frame.setLocationRelativeTo(null)

// ============================================================
// IMPORTANT: DIRECT STARTUP
// ============================================================

SwingUtilities.invokeLater(
  new Runnable {

    override def run(): Unit = {

      frame.setVisible(true)
      frame.toFront()
      frame.requestFocus()
    }
  }
)