Tuesday, September 3, 2024

donut.c converted to donut.rs (Rust)

 I tried to convert Andy Sloane's donut.c to Rust programming language. Suggestions are welcome.

//
// donut -- rotating donut
//
// note: ported a C version by CJKim - July 9, 2024
//
// the original C version's author is Andy Sloane
//

use std::{env, thread, time::Duration};
use getopts::Options;

fn donut(delay: u64) {
    const GRIDSIZE: usize = 1760;
    const TEXTURE: [char; 12] = ['.',',','-','~', ':', ';', '=', '!', '*', '#', '$', '@'];
    let mut rot_a: f32 = 0.0;
    let mut rot_b: f32 = 0.0;

    let mut iter: usize = 0;
    loop {
        iter += 1;
        let mut z: [f32;  GRIDSIZE] = [0.0; GRIDSIZE];
        let mut b: [char; GRIDSIZE] = [' '; GRIDSIZE];
        let mut grid = b.clone();
        let mut j: f32 = 0.0;
        while j < 6.28 {
            let mut i: f32 = 0.0;
            while i < 6.28 {
                let c: f32 = i.sin();
                let d: f32 = j.cos();
                let e: f32 = rot_a.sin();
                let f: f32 = j.sin();
                let g: f32 = rot_a.cos();
                let h: f32 = d + 2.0;
                let deg: f32 = 1.0 / (c * h * e + f * g + 5.0);
                let l: f32 = i.cos();
                let m: f32 = rot_b.cos();
                let n: f32 = rot_b.sin();
                let t: f32 = c * h * g - f * e;
                let x = (40.0 + 30.0 * deg * (l * h * m - t * n)) as i32;
                let y = (12.0 + 15.0 * deg * (l * h * n + t * m)) as i32;
                let o = (x + 80 * y) as usize;
                let idx: usize = (8.0 * ((f * e - c * d * g) * m
                                - c * d * e - f * g - l * d * n)) as usize;
                if 22 > y && y > 0 && x > 0 && 80 > x && deg > z[o as usize] {
                    z[o] = deg;
                    let pidx: usize = if idx > 0 { idx } else { 0 };
                    b[o] = TEXTURE[pidx];
                }
                i += 0.02;
            }
            j += 0.07;
        }
        for k in 0..GRIDSIZE {
            // putchar(k % 80 ? b[k] : 10);
            let chr = if k % 80 == 0 { '\n' } else { b[k as usize] };
            grid[k as usize] = chr;
            rot_a += 0.00004;
            rot_b += 0.00002;
        }
        let ostr = String::from_iter(grid);     // convert chars to a string
                println!("\x1b[H{}\n{}", ostr, iter);
        // BUG: when rot_a reaches 1024 and rot_b 512, the donut no longer spins
        if rot_a > 1000.0 || rot_b > 500.0 {
            rot_a = 0.0;
            rot_b = 0.0;
        }
        thread::sleep(Duration::from_millis(delay));
    }
}

fn print_usage(prgnam: &str, opts: Options) {
    let usage = format!("usage: {} [options]", prgnam);
    println!("{}", opts.usage(&usage));
}

fn main() {
    let args: Vec<String> = env::args().collect();
    let prognam = args[0].clone();
    let mut opts = Options::new();
    opts.optopt("d", "delay", "number of milliseconds between iterations (default=30)", "milsecs");
    opts.optflag("h", "help", "print this help message and exit");
    let matches = match opts.parse(&args[1..]) {
        Ok(m)  => { m }
        Err(e) => {
            println!("{}", e.to_string());
            print_usage(&prognam, opts);
            return;
        }
    };
    if matches.opt_present("h") {
        print_usage(&prognam, opts);
        return;
    }
    let delay: u64 = match matches.opt_str("d") {
        Some(m) => {
            match m.parse() {
                Ok(x)  => { x }
                Err(e) => {
                    println!("{} - {}", "bad milliseconds specified", e);
                    print_usage(&prognam, opts);
                    return;
                }
            }
        }
        _ => { 30 as u64 }
    };
    print!("\x1b[2J\x1b[HHello, donut lovers! [Hit ^C to stop it.]");
    donut(delay);
}



donut.c converted to donut.py (Python)

Here's my version of Andy Sloane's donut.c converted to Python programming language.

#!/usr/bin/env python3
#
# python port of donut.c
#

import sys
import time
import math
import itertools

def donut() -> list:
    z = list(itertools.repeat(0.0, 1760))
    b = list(itertools.repeat(' ', 1760))
    j = 0.0
    while j < 6.28:
        i = 0.0
        while i < 6.28:
            c: float = math.sin(i)
            d: float = math.cos(j)
            e: float = math.sin(A)
            f: float = math.sin(j);
            g: float = math.cos(A);
            h: float = d + 2.0;
            D: float = 1.0 / (c * h * e + f * g + 5.0);
            l: float = math.cos(i);
            m: float = math.cos(B);
            n: float = math.sin(B);
            t: float = c * h * g - f * e;
            x = int(40 + 30 * D * (l * h * m - t * n))
            y = int(12 + 15 * D * (l * h * n + t * m))
            o = int(x + 80 * y)
            N = int(8 * ((f * e - c * d * g) * m - c * d * e - f * g - l * d * n))
            if 22 > y and y > 0 and x > 0 and 80 > x and D > z[o]:
                z[o] = D
                b[o] = ".,-~:;=!*#$@"[N if N > 0 else 0]
            i += 0.02
        j += 0.07
    for k in range(0, 1760, 80):
        b[k] = '\n'
    return b

A: float = 0.0
B: float = 0.0
sys.stdout.write('\x1b[2J')
while True:
    sys.stdout.write('\x1b[H' + ''.join(donut()) + '\n')
    A += 0.04
    B += 0.02
    time.sleep(0.03)



Sunday, September 1, 2024

Spinning Donut

Spinning Donut

Wednesday, August 21, 2024

donut.c converted to donut.go (Go)

 Mr. Andy Sloane published a piece of C code that shows a rotating doughnut on terminal. I tried to convert it to golang as I was learning Go programming language. It's true that the code should like a doughnut, but that comes later. Please send me any improvement suggestions.

/*
** donut.go - golang version of donut.c
**
*/
package main

import (
"fmt"
"math"
"strings"
"time"
)

func main() {
const GRIDSIZE int = 1760
var A float64 = 0.0
var B float64 = 0.0
z := [GRIDSIZE]float64{}
b := [GRIDSIZE]string{}
p := [...]string{".", ",", "-", "~",
":", ";", "=", "!", "*", "#", "$", "@"}

fmt.Print("\x1b[2J");

for {
for k := range b {
b[k] = " "
z[k] = 0.0
}
for j := 0.0; j < 6.28; j += 0.07 {
for i := 0.0; i < 6.28; i += 0.02 {
var c float64 = math.Sin(i)
var d float64 = math.Cos(j)
var e float64 = math.Sin(A)
var f float64 = math.Sin(j)
var g float64 = math.Cos(A)
var h float64 = d + 2
var D float64 = 1 / (c * h * e + f * g + 5)
var l float64 = math.Cos(i)
var m float64 = math.Cos(B)
var n float64 = math.Sin(B)
var t float64 = c * h * g - f * e
var x int = int(40 + 30 * D * (l * h * m - t * n))
var y int = int(12 + 15 * D * (l * h * n + t * m))
var o int = int(x + 80 * y)
var N int = int(8 * ((f * e - c * d * g) * m - c * d * e - f * g - l * d * n))
if 22 > y && y > 0 && x > 0 && 80 > x && D > z[o] {
z[o] = D
if N > 0 {
b[o] = p[N]
} else {
b[o] = "."
}
}
}
}

fmt.Print("\x1b[H")
for k := 0; k < GRIDSIZE; k += 80 {
b[k] = "\n"
}
A += 0.00004 * float64(GRIDSIZE)
B += 0.00002 * float64(GRIDSIZE)
fmt.Println(strings.Join(b[:], ""))
time.Sleep(30 * time.Millisecond);
}
}


Tuesday, December 20, 2016

Frequently Used DB2 Functions and Expressions

Get the number of days since 0001-01-01
SELECT DAYS('2016-12-25')

Convert date string to datetime type
SELECT date(to_date(string_date_column,'YYYY-MM-DD'))

Calculate difference in number of days between two dates
SELECT DAYS('2016-01-01') - DAYS('2015-01-01')

Get day of the month, month, and year
SELECT DAY('2016-12-25'), MONTH('2016-12-25'), YEAR('2016-12-25')

From DB2 v10, dates can be formatted with a desired format string
SELECT VARCHAR_FORMAT(date-column, 'YYYY-MM-DD HH:MI:SS')

Tuesday, December 6, 2016

Frequent Regular Expressions

Here are some frequently used regular expressions.

IP Address:
^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$

Social Security Number:
^\d{3}-?\d{2}-?\d{4}$

Credit Card: [Visa, MC, AmEx, and Discover]
^(?:4[0-9]{12}(?:[0-9]{3})?|5[1-5][0-9]{14}|6(?:011|5[0-9][0-9])[0-9]{12}|3[47][0-9]{13}|3(?:0[0-5]|[68][0-9])[0-9]{11}|(?:2131|1800|35\d{3})\d{11})$

Use Luhn algorithm to check if a credit card number is a valid number. Of course, the algorithm doesn't obviously check if the card is actually any good. Such must be checked with the card issuer.


Monday, November 28, 2016

Renting a Car in South Korea

Introduction:
I often traveled to South Korea. My trip was the first one for me to rent a car. Because the public transportation in Korea is ubiquitous, it's not really necessary to rental a car, especially when your destinations are in major cities like Seoul and Busan. Since there are many sites discussing how vast public transportation is in Korea, I wouldn't cover it here.

I tried to search for some information as what it's like to rent a car in Korea but couldn't find any information. Hence, it prompted me to write this blog.

International Driving Permit:
Before you leave, you must obtain an International Driving Permit. I obtained mine from a local AAA office. It's nothing more than a booklet with the information off of your own driver's license and your picture. AAA charges $20 (in 2016) for it and it is good for only one year. The valid duration is not determined by AAA but the international body that established International Driving Permit system. You can go to the AAA web site to obtain the application. Unless you want to pay extra to AAA, you may want to get your photo taken like the one you would for a passport.
Related image

Rental Companies:
There may be many companies offering rental cars in Korea; however, I tried only AVIS. The price was very reasonable. Note that AVIS is affiliated with AJ Rent-a-Car in Korea. Asking about AVIS at the airport isn't going to work too well as the folks there don't know AVIS. If you're renting a car from Hertz, you will find that Hertz is affiliated with Lotte Rent-a-Car. At the Incheon Airport, the rental car counters are located at both ends of the arrival terminal. However, you may want to go to the one near gate A instead. The one at the opposite end isn't always manned.

Rental Contract:
Note that the folks at the rental car counter will not speak English as fluently as you may wish. Please be specific as how you ask questions. Speak slowly whenever possible. You will be asked to present your passport and International Driving Permit. Your own driver's license is not much of use here. Without an International Driving Permit, you will NOT be able to rent a car. When you rent a car, you will be asked if you wish get a GPS (Koreans call it "Navi" pronounced more like "nebi" and not GPS). If you do not speak Korean, you want to make sure you get the English version. Without a GPS, it will be quite difficult to get around as the Korean road system has been evolving significantly. Also, Koreans are not really into telling you street or highway names but directions like turn left/right. Also, Korea uses the metric system. You should get some idea as what 100 meters is like.

My AVIS rental included a basic collision insurance that covers up to 300,000 wons, which is slightly less than $300. If you feel you need more, you should ask for a higher coverage. One other thing to note is that if you get into an accident and the damage takes few days to repair, you are directly liable for the days the car is out of service at the half of the daily rental rate. For example, if your daily rental rate is $20 and the two days are needed to repair the damage, you owe $20 ($20 * 50% * 2 days).

Driving:
Driving around is fairly easy. Nothing too tricky. The signs are posted both in Korean and English.
The speed limit is 80 to 100 kph on most of the highways. You should try and drive at the posted speed limit. All speedsters are caught by the traffic cameras. GPS usually warns of the upcoming traffic cameras. You should pay attention to what GPS is informing. A typical speed limit sign is:
There are many toll highways. You need to prepare a lot of money in Korean currency to pay the tolls.

On highways, often the left most lane is for buses. If you see a blue line for the left most lane, you don't want to drive in it. You will get a ticket. This situation is the only time when police actually pulls you over.

When you make a left turn, wait for a left arrow. You cannot turn left when it's green unless a sign is posted specifically to allow it. The signs are, unfortunately, only in Korean, which reads:
Right turn on red is allowed when it's safe to do so.

If you see diamond sign painted on the street, they simply mean that a traffic signal is ahead and not carpool lanes.

There are many tunnels in Korea since the 70% of Korea is mountainous. Many bridges and tunnels make the highways relatively flat.

Use your common sense to decide what to do in most cases. The traffic rules and signs are fairly logical.