
// Matrix.java
// Modified by Andrew Davison, ad@coe.psu.ac.th, March 2023

/* A version of "The Matrix" text scrolling effect.

   Uses Lanterna 3
   https://github.com/mabe02/lanterna

   Usage (Windows):
     > compile.bat Matrix.java
     > run.bat Matrix

   Usage (Linux):
     > ./compile.sh Matrix.java
     > ./run.sh Matrix

*/


import java.io.*;
import java.util.*;

import com.googlecode.lanterna.*;
import com.googlecode.lanterna.graphics.TextGraphics;
import com.googlecode.lanterna.input.*;
import com.googlecode.lanterna.screen.*;
import com.googlecode.lanterna.terminal.*;



public class Matrix 
{
  private static final char[] LETTERS =  
    { '!', '\"', '#', '$', '%', '&', '\'', '(', ')', 
      '*', '+', ',', '-', '.', '/', 
      '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 
      ':', ';', '<', '=', '>', '?', '@', 
      'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 
      'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 
      '[', '|', ']', '^', '_', '`', 
      'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 
      'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', 
      '{', '}', '~'
    };   // space not included


  private static int numCols, numRows;
  private static Random rand = new Random();


  public static void main(String[] args)
  {
    Screen scr = Utils.createScreen();
    scr.setCursorPosition(null);
    
    TerminalSize termSz = scr.getTerminalSize();
    numCols = termSz.getColumns();
    numRows = termSz.getRows();
    
    Utils.fill(scr, TextColor.ANSI.BLACK);

    char[][] grid = new char[numRows][numCols];
    for (int i = 0; i < numRows; i++)
      for (int j = 0; j < numCols; j++)
        grid[i][j] = ' '; 

    while (true) {
      KeyStroke ks = Utils.pollInput(scr);
      if (Utils.hasQuit(ks))
        break;

      update(grid);
      display(scr, grid);
      Utils.pause(150);
    }
    
    Utils.close(scr);
  }  // end of main()



  private static void update(char[][] grid)
  { 
    // move each row down one line 
    for (int i = numRows-1; i > 0; i--)
      for (int j = 0; j < numCols; j++)
        grid[i][j] = grid[i-1][j]; 

    // generate new top row
    for (int j = 0; j < numCols; j++)
       grid[0][j] = randomChar(grid[1][j]);
  } // end of update()



  private static char randomChar(char nextCh)
  {
    if (nextCh == ' ')
      return spaceOrChar(0.9);  // space is likely
    else   // next char is not a space
      return spaceOrChar(0.2);  // a space is unlikely
  }  // end of randomChar()


  private static char spaceOrChar(double prob)
  // liklihood of a space vs. a visible letter
  {
    if (rand.nextDouble() <= prob)
      return ' ';
    else 
      return LETTERS[ rand.nextInt(LETTERS.length) ];
  } // end of spaceOrChar()


  private static void display(Screen scr, char[][] grid)
  { 
    for (int i = 0; i < numRows; i++) {
      for (int j = 0; j < numCols; j++)
        Utils.setCharacter(scr, j, i, grid[i][j],
                          TextColor.ANSI.GREEN_BRIGHT,
                          TextColor.ANSI.BLACK);
    }
    Utils.refresh(scr);
  }  // end of display()



} // end of Matrix class
