• Welcome to RetroCoders Community.
 

News:

Welcome to RetroCoders Community

Main Menu

Recent posts

#41
General Discussion / Registration Open for Business
Last post by ron77 - Dec 28, 2024, 09:11 AM
As of now, the new member's registration has to be approved due to Fake Account registration by spam bots and Spammers...

So, if you are interested in registering for this forum, register. Still, after that, you must send a request by e-mail with your info, including a valid e-mail, and tell us a bit about yourself, why you wish to join this forum, and what your interests are to the following email address. Don't forget to mention the nickname that you registered with. If you are approved, we'll send you an email to the email address you used to contact us, stating that you are now approved. You can log in to the forum with the password and member's nick you registered with - if you try to register but do not email us, you WILL NOT be approved, and your registration will be deleted in 60 days:

Registration Requests Email Address


REGITRATION IS NOW ENABLED - NO NEED FOR ACCOUNT APPROVAL BY ADMIN

Thank you for your Understanding...

#42
C / C++ / Donut.c - have a donut
Last post by ron77 - Dec 27, 2024, 02:08 PM
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <math.h>

int main() {
    float A = 0, B = 0;
    float i, j;
    int k;
    float z[1760];
    char b[1760];
    printf("\x1b[2J");
    for(;;) {
        memset(b,32,1760);
        memset(z,0,7040);
        for(j=0; j < 6.28; j += 0.07) {
            for(i=0; i < 6.28; i += 0.02) {
                float c = sin(i);
                float d = cos(j);
                float e = sin(A);
                float f = sin(j);
                float g = cos(A);
                float h = d + 2;
                float D = 1 / (c * h * e + f * g + 5);
                float l = cos(i);
                float m = cos(B);
                float n = sin(B);
                float t = c * h * g - f * e;
                int x = 40 + 30 * D * (l * h * m - t * n);
                int y= 12 + 15 * D * (l * h * n + t * m);
                int o = x + 80 * y;
                int N = 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;
                    b[o] = ".,-~:;=!*#$@"[N > 0 ? N : 0];
                }
            }
        }
        printf("\x1b[H");
        for(k = 0; k < 1761; k++) {
            putchar(k % 80 ? b[k] : 10);
        }
        A += 0.04;
        B += 0.02;
        usleep(30000);
    }
    return 0;
}
#43
Rust / Rust Implementation of termina...
Last post by ron77 - Dec 27, 2024, 01:59 PM
https://retrocoders.phatcode.net/index.php?topic=868.0

the rust implementation:
main.rs:
use std::fs;
use std::io::{self, Write};
use std::thread;
use std::time::Duration;
use std::ffi::CString;
use std::env;
use rand::Rng;
use anyhow::{Result, Context};
use bass_sys::*;

// File paths
const DESC1: &str = "data/des1.txt";
const OPENING_BANNER: &str = "banners/opening1.txt";
const OPENING_POINT: &str = "data/opening1.txt";
const MENU: &str = "data/mainmenu.txt";
const MONEY_MENU: &str = "data/moneyMenu.txt";
const FRIENDS_MENU: &str = "data/friendsmenu.txt";
const OVER: &str = "data/suicide.txt";
const GAME_END: &str = "data/theend.txt";
const FAMILY1: &str = "data/family1.txt";
const SCHOOL1: &str = "data/school1.txt";

// Arrays of file paths
const MONTHS: [&str; 12] = [
    "January", "February", "March", "April", "May", "June",
    "July", "August", "September", "October", "November", "December"
];

const SONGS_RAND: [&str; 12] = [
    "sound/walrus1.ogg", "sound/walrus2.ogg", "sound/walrus3.ogg",
    "sound/walrus4.ogg", "sound/walrus5.ogg", "sound/walrus6.ogg",
    "sound/walrus7.ogg", "sound/walrus8.ogg", "sound/walrus9.ogg",
    "sound/walrus10.ogg", "sound/walrus11.ogg", "sound/walrus12.ogg"
];

const MARY: [&str; 5] = [
    "data/mary1.txt", "data/mary2rehab.txt", "data/mary3pregnant.txt",
    "data/mary4jail.txt", "data/mary5dead.txt"
];

const JOE: [&str; 5] = [
    "data/joe1.txt", "data/joe2rehab.txt", "data/joe3jail.txt",
    "data/joe4.txt", "data/joe5prison.txt"
];

const FELIX: [&str; 5] = [
    "data/felix1.txt", "data/felix2.txt", "data/felix3jail.txt",
    "data/felix4rehab.txt", "data/felix5crazy.txt"
];

struct GameState {
    health: i32,
    money: i32,
    turns: usize,
    year: i32,
    is_over: bool,
    is_mary: bool,
    is_joe: bool,
    is_felix: bool,
    is_suicide: bool,
    stream: u32,
}

impl GameState {
    fn new() -> Self {
        Self {
            health: 100,
            money: 5000,
            turns: 0,
            year: 1991,
            is_over: false,
            is_mary: true,
            is_joe: true,
            is_felix: true,
            is_suicide: false,
            stream: 0,
        }
    }

    fn play_music(&mut self, path: &str) -> Result<()> {
        let mut full_path = env::current_dir()?;
        full_path.push(path);
        let path_str = full_path.to_str().unwrap();
        
        println!("Attempting to play: {}", path_str);

        if self.stream != 0 {
            BASS_StreamFree(self.stream);
            self.stream = 0;
        }

        let path_c = CString::new(path_str)?;
        self.stream = BASS_StreamCreateFile(
            0,
            path_c.as_ptr() as *const _,
            0,
            0,
            BASS_SAMPLE_LOOP
        );

        if self.stream == 0 {
            println!("BASS Error Code: {}", BASS_ErrorGetCode());
            return Ok(());
        }

        if BASS_ChannelPlay(self.stream, 0) == 0 {
            println!("Failed to play: Error code {}", BASS_ErrorGetCode());
            return Ok(());
        }
        
        Ok(())
    }

    fn stop_music(&mut self) {
        if self.stream != 0 {
            BASS_ChannelStop(self.stream);
            BASS_StreamFree(self.stream);
            self.stream = 0;
        }
    }

    fn read_file(&self, path: &str) -> Result<String> {
        let mut full_path = env::current_dir()?;
        full_path.push(path);
        fs::read_to_string(&full_path)
            .with_context(|| format!("Failed to read file: {}", full_path.display()))
    }

    fn clear_screen(&self) {
        print!("\x1B[2J\x1B[1;1H");
        io::stdout().flush().unwrap();
    }

    fn get_input(&self) -> Result<i32> {
        let mut input = String::new();
        io::stdin().read_line(&mut input)?;
        Ok(input.trim().parse()?)
    }

    fn wait_for_enter(&self) -> Result<()> {
        let mut input = String::new();
        io::stdin().read_line(&mut input)?;
        Ok(())
    }

    fn friends(&mut self) -> Result<()> {
        self.clear_screen();
        println!(
            "date: {}, {} health: {} money: {}\n\n{}",
            MONTHS[self.turns], self.year, self.health, self.money,
            self.read_file(FRIENDS_MENU)?
        );

        match self.get_input()? {
            1 => self.visit_mary()?,
            2 => self.visit_joe()?,
            3 => self.visit_felix()?,
            4 => self.visit_school()?,
            5 => self.visit_family()?,
            _ => {
                println!("INVALID INPUT!");
                thread::sleep(Duration::from_secs(5));
            }
        }
        Ok(())
    }

    fn visit_mary(&mut self) -> Result<()> {
        self.clear_screen();
        if !self.is_mary {
            println!("{}", self.read_file(MARY[4])?);
        } else {
            let mut rng = rand::thread_rng();
            let r = rng.gen_range(0..5);
            if r == 4 {
                self.is_mary = false;
            }
            println!("{}", self.read_file(MARY[r])?);
        }
        self.wait_for_enter()?;
        Ok(())
    }

    fn visit_joe(&mut self) -> Result<()> {
        self.clear_screen();
        if !self.is_joe {
            println!("{}", self.read_file(JOE[4])?);
        } else {
            let mut rng = rand::thread_rng();
            let r = rng.gen_range(0..5);
            if r == 4 {
                self.is_joe = false;
            }
            println!("{}", self.read_file(JOE[r])?);
        }
        self.wait_for_enter()?;
        Ok(())
    }

    fn visit_felix(&mut self) -> Result<()> {
        self.clear_screen();
        if !self.is_felix {
            println!("{}", self.read_file(FELIX[4])?);
        } else {
            let mut rng = rand::thread_rng();
            let r = rng.gen_range(0..5);
            if r == 4 {
                self.is_felix = false;
            }
            println!("{}", self.read_file(FELIX[r])?);
        }
        self.wait_for_enter()?;
        Ok(())
    }

    fn visit_school(&mut self) -> Result<()> {
        self.clear_screen();
        println!("{}", self.read_file(SCHOOL1)?);
        self.wait_for_enter()?;
        Ok(())
    }

    fn visit_family(&mut self) -> Result<()> {
        self.clear_screen();
        println!("{}", self.read_file(FAMILY1)?);
        self.wait_for_enter()?;
        Ok(())
    }

    fn drugs(&mut self) -> Result<()> {
        self.clear_screen();
        let mut rng = rand::thread_rng();
        let index = rng.gen_range(0..5);
        
        println!("{}", self.read_file(&format!("data/drug{}.txt", index + 1))?);
        
        match index {
            0 => self.money -= 170,
            3 => {
                self.health -= 5;
                self.money -= 350;
            }
            4 => {
                self.health -= 5;
                self.money -= 250;
            }
            _ => {}
        }
        
        self.wait_for_enter()?;
        Ok(())
    }

    fn shoplist(&mut self) -> Result<()> {
        self.clear_screen();
        let mut rng = rand::thread_rng();
        let index = rng.gen_range(0..5);
        
        println!("{}", self.read_file(&format!("data/shop{}.txt", index + 1))?);
        
        match index {
            0 => self.money += 200,
            1 => self.money += 150,
            2 => self.health -= 3,
            3 => self.money += 200,
            4 => self.health -= 3,
            _ => {}
        }
        
        self.wait_for_enter()?;
        Ok(())
    }

    fn car(&mut self) -> Result<()> {
        self.clear_screen();
        let mut rng = rand::thread_rng();
        let index = rng.gen_range(0..5);
        
        println!("{}", self.read_file(&format!("data/car{}.txt", index + 1))?);
        
        match index {
            0 => self.money += 1000,
            1 => self.money += 2000,
            2 => self.health -= 5,
            3 => self.money += 1500,
            4 => self.health -= 5,
            _ => {}
        }
        
        self.wait_for_enter()?;
        Ok(())
    }

    fn burglary(&mut self) -> Result<()> {
        self.clear_screen();
        let mut rng = rand::thread_rng();
        let index = rng.gen_range(0..5);
        
        println!("{}", self.read_file(&format!("data/burglur{}.txt", index + 1))?);
        
        match index {
            0 => self.money += 2500,
            1 => self.health -= 7,
            2 => self.health -= 7,
            3 => self.money += 2500,
            4 => self.health -= 7,
            _ => {}
        }
        
        self.wait_for_enter()?;
        Ok(())
    }

    fn get_money(&mut self) -> Result<()> {
        self.clear_screen();
        println!(
            "date: {}, {} health: {} money: {}\n\n{}",
            MONTHS[self.turns], self.year, self.health, self.money,
            self.read_file(MONEY_MENU)?
        );

        match self.get_input()? {
            1 => self.shoplist()?,
            2 => self.car()?,
            3 => self.burglary()?,
            _ => {}
        }
        
        Ok(())
    }

    fn rehab(&mut self) -> Result<()> {
        if self.money < 2800 {
            self.clear_screen();
            println!(
                "\nYOU DON'T HAVE ENOUGH MONEY FOR REHAB...\nIT COSTS 2800 AND YOU ONLY HAVE {}\n",
                self.money
            );
            self.wait_for_enter()?;
            return Ok(());
        }

        self.money -= 2800;

        for i in 0..6 {
            self.clear_screen();
            println!("{}", self.read_file(&format!("data/rehab{}.txt", i + 1))?);
            self.wait_for_enter()?;
        }

        self.health += 65;
        if self.health > 100 {
            self.health = 100;
        }

        Ok(())
    }

    fn mirror(&mut self) -> Result<()> {
        self.clear_screen();
        
        let mirror_index = match self.health {
            h if h >= 90 => 0,
            h if h >= 80 => 1,
            h if h >= 70 => 2,
            h if h >= 60 => 3,
            h if h >= 50 => 4,
            h if h >= 40 => 5,
            h if h >= 30 => 6,
            h if h >= 20 => 7,
            h if h >= 10 => 8,
            _ => 9,
        };

        println!("{}", self.read_file(&format!("data/mirror{}.txt", mirror_index + 1))?);

        if self.health < 35 {
            self.is_suicide = true;
        }

        self.wait_for_enter()?;
        Ok(())
    }

    fn suicide(&mut self) -> Result<()> {
        self.clear_screen();
        println!("{}", self.read_file(OVER)?);
        self.wait_for_enter()?;
        self.is_over = true;
        Ok(())
    }
}

fn main() -> Result<()> {
    // Initialize BASS
    if BASS_Init(-1, 44100, 0, std::ptr::null_mut(), std::ptr::null_mut()) == 0 {
        let error_code = BASS_ErrorGetCode();
        eprintln!("Error initializing BASS library: {}", error_code);
        return Ok(());
    }

    let mut game = GameState::new();
    let mut rng = rand::thread_rng();

    // Show intro
    println!("{}", game.read_file(DESC1)?);
    game.wait_for_enter()?;
    game.clear_screen();

    // Start background music
    let song_index = rng.gen_range(0..12);
    if let Err(e) = game.play_music(SONGS_RAND[song_index]) {
        eprintln!("Failed to play music: {}", e);
    }

    println!("{}", game.read_file(OPENING_BANNER)?);
    game.wait_for_enter()?;
    game.clear_screen();

    println!("{}", game.read_file(OPENING_POINT)?);
    game.wait_for_enter()?;
    game.clear_screen();

    // Main game loop
    while game.health > 0 && !game.is_over {
        game.clear_screen();

        if game.turns > 11 {
            game.turns = 0;
            game.year += 1;
        }

        if game.money < 0 {
            game.money = 0;
        }

        println!(
            "date: {}, {} health: {} money: {}\n\n{}",
            MONTHS[game.turns], game.year, game.health, game.money,
            game.read_file(MENU)?
        );

        if game.is_suicide {
            println!("PRESS 8 TO TRY AND SUICIDE");
        }

        match game.get_input()? {
            1 => {
                game.stop_music();
                let song_index = rng.gen_range(0..12);
                if let Err(e) = game.play_music(SONGS_RAND[song_index]) {
                    eprintln!("Failed to change music: {}", e);
                }
            },
            2 => game.friends()?,
            3 => game.drugs()?,
            4 => game.get_money()?,
            5 => game.rehab()?,
            6 => game.mirror()?,
            7 => game.is_over = true,
            8 if game.is_suicide => game.suicide()?,
            _ => {}
        }

        game.turns += 1;
    }

    // Show ending
    game.clear_screen();
    println!("{}", game.read_file(GAME_END)?);
    game.wait_for_enter()?;

    // Cleanup
    game.stop_music();
    BASS_Free();

    Ok(())
}

Cargo.toml:
[package]
name = "rust_trainspotting_II_game"
version = "0.1.0"
edition = "2021"

[dependencies]
rand = "0.8"
bass-sys = "2.1"
anyhow = "1.0"
#44
Rust / Danny chatbot in Rust
Last post by ron77 - Dec 27, 2024, 01:54 PM
use std::fs::File;
use std::io::{self, BufRead, BufReader, Write};
use std::process::Command;
use std::collections::HashMap;
use rand::prelude::*;
use anyhow::{Result, Context as _};

// const MAX_STRING_LENGTH: usize = 1000;
// const MAX_KEYWORDS: usize = 20;
// const MAX_REPLIES: usize = 50;
const MAX_MEMORY: usize = 15;

#[derive(Default)]
struct ArraySet {
    keywords: Vec<String>,
    replies: Vec<String>,
}

#[derive(Default)]
struct ChatBot {
    key_reply: Vec<ArraySet>,
    default_replies: Vec<String>,
    memory: Vec<String>,
    word_swaps: HashMap<String, String>,
    rng: ThreadRng,
    single_line_mode: bool,
}

impl ChatBot {
    fn new() -> Self {
        Self {
            key_reply: Vec::new(),
            default_replies: Vec::new(),
            memory: Vec::with_capacity(MAX_MEMORY),
            word_swaps: HashMap::new(),
            rng: thread_rng(),
            single_line_mode: true,
        }
    }

    fn load_arrays(&mut self, filename: &str) -> Result<()> {
        let file = File::open(filename)
            .with_context(|| format!("Failed to open file: {}", filename))?;
        let reader = BufReader::new(file);
        let mut current_set: Option<ArraySet> = None;

        for line in reader.lines() {
            let line = line?;
            if line.starts_with("d1:") {
                self.default_replies.push(line[3..].to_string());
            } else if line.starts_with("k:") {
                if current_set.is_some() && !current_set.as_ref().unwrap().replies.is_empty() {
                    if let Some(set) = current_set.take() {
                        self.key_reply.push(set);
                    }
                }
                
                if current_set.is_none() {
                    current_set = Some(ArraySet::default());
                }
                
                if let Some(set) = &mut current_set {
                    set.keywords.push(line[2..].to_string());
                }
            } else if line.starts_with("r:") {
                if let Some(set) = &mut current_set {
                    set.replies.push(line[2..].to_string());
                }
            }
        }

        if let Some(set) = current_set {
            self.key_reply.push(set);
        }

        println!("Number of keywords-replies pair groups: {}", self.key_reply.len());
        Ok(())
    }

    fn load_swap_words(&mut self, filename: &str) -> Result<()> {
        let file = File::open(filename)
            .with_context(|| format!("Failed to open swap words file: {}", filename))?;
        let reader = BufReader::new(file);

        for line in reader.lines() {
            let line = line?;
            if line.starts_with("s:") {
                if let Some(pos) = line[2..].find('>') {
                    let (word_in, word_out) = line[2..].split_at(pos);
                    self.word_swaps.insert(
                        word_in.to_string(),
                        word_out[1..].to_string()
                    );
                }
            }
        }
        Ok(())
    }

    fn swap_words(&self, input: &str) -> String {
        input
            .split_whitespace()
            .map(|word| {
                self.word_swaps
                    .get(word)
                    .map_or(word.to_string(), |w| w.clone())
            })
            .collect::<Vec<_>>()
            .join(" ")
    }

    fn isolate_punctuation(s: &str) -> String {
        s.chars()
            .map(|c| {
                if "?!,.:;<>(){}[]".contains(c) {
                    format!(" {} ", c)
                } else {
                    c.to_string()
                }
            })
            .collect()
    }

    fn process_reply(&mut self, reply: &str, user_input: &str) -> String {
        if !reply.ends_with('*') {
            return reply.to_string();
        }

        let reply = &reply[..reply.len() - 1];
        
        if self.memory.len() < MAX_MEMORY {
            self.memory.push(user_input.to_string());
        }
        
        for set in &self.key_reply {
            for keyword in &set.keywords {
                if user_input.contains(keyword.as_str()) {
                    if let Some(rest) = user_input.split(keyword.as_str()).nth(1) {
                        let swapped = self.swap_words(rest);
                        return format!("{} {}", reply, swapped);
                    }
                }
            }
        }
        
        reply.to_string()
    }

    fn user_question(&mut self, txt: &str) -> String {
        let mut matched_replies = Vec::new();
        let mut found = false;

        for set in &self.key_reply {
            for keyword in &set.keywords {
                if txt.contains(keyword.as_str()) {
                    if let Some(reply) = set.replies.choose(&mut self.rng).cloned() {
                        matched_replies.push(reply);
                        found = true;
                        break;
                    }
                }
            }
        }

        let processed_replies: Vec<String> = matched_replies.into_iter()
            .map(|reply| self.process_reply(&reply, txt))
            .collect();

        if !processed_replies.is_empty() {
            if self.single_line_mode {
                processed_replies.join(" | ")
            } else {
                processed_replies.join("\n")
            }
        } else if !found && !self.default_replies.is_empty() {
            self.default_replies
                .choose(&mut self.rng)
                .cloned()
                .unwrap_or_else(|| "I don't understand. Can you rephrase that?".to_string())
        } else {
            "I don't understand. Can you rephrase that?".to_string()
        }
    }

    fn commands(&mut self, txt: &str) -> String {
        if txt.starts_with("/") {
            match txt {
                "/single" => {
                    self.single_line_mode = true;
                    return "Switched to single-line mode.".to_string();
                }
                "/multi" => {
                    self.single_line_mode = false;
                    return "Switched to multi-line mode.".to_string();
                }
                _ => {}
            }
        }

        let isolated = Self::isolate_punctuation(txt);
        let lowercase = isolated.to_lowercase();
        self.user_question(&lowercase)
    }

    fn speak(&self, text: &str) -> Result<()> {
        Command::new("voice")
            .args(["-r", "-1", "-n", "Microsoft David Desktop", text])
            .spawn()
            .with_context(|| "Failed to start TTS process")?
            .wait()
            .with_context(|| "Failed to wait for TTS process")?;
        Ok(())
    }
}

fn main() -> Result<()> {
    println!("CHATBOT DANNY IN RUST VERSION 1.0.0");
    println!("Commands:");
    println!("  /single - Switch to single-line mode");
    println!("  /multi  - Switch to multi-line mode");
    println!("  quit    - Exit the program");
    
    let mut chatbot = ChatBot::new();
    chatbot.load_arrays("database.txt")?;
    chatbot.load_swap_words("swapwords.txt")?;

    let stdin = io::stdin();
    let mut stdout = io::stdout();
    
    loop {
        print!("> ");
        stdout.flush()?;
        
        let mut input = String::new();
        stdin.lock().read_line(&mut input)?;
        let input = input.trim();
        
        if input == "quit" {
            break;
        }
        
        let response = chatbot.commands(input);
        
        if chatbot.single_line_mode {
            println!("{}", response);
            chatbot.speak(&response)?;
        } else {
            for line in response.lines() {
                println!("{}", line);
                chatbot.speak(line)?;
            }
        }
    }

    Ok(())
}

https://retrocoders.phatcode.net/index.php?topic=840.0
#45
Rust / Rust Donut
Last post by ron77 - Dec 27, 2024, 01:52 PM
use std::{thread, time::Duration};

fn main() {
    let mut a = 0.0f32;
    let mut b = 0.0f32;
    let mut z = vec![0.0f32; 1760];
    let mut buffer = vec![' '; 1760];
    
    // Clear screen
    print!("\x1b[2J");
    
    loop {
        // Reset buffers
        buffer.fill(' ');
        z.fill(0.0);
        
        let mut j = 0.0f32;
        while j < 6.28 {
            let mut i = 0.0f32;
            while i < 6.28 {
                let c = i.sin();
                let d = j.cos();
                let e = a.sin();
                let f = j.sin();
                let g = a.cos();
                let h = d + 2.0;
                let d = 1.0 / (c * h * e + f * g + 5.0);
                let l = i.cos();
                let m = b.cos();
                let n = b.sin();
                let t = c * h * g - f * e;
                let x = (40.0 + 30.0 * d * (l * h * m - t * n)) as i32;
                let y = (12.0 + 15.0 * d * (l * h * n + t * m)) as i32;
                let o = (x + 80 * y) as usize;
                let luminance = (8.0 * ((f * e - c * d * g) * m - c * d * e - f * g - l * d * n)) as i32;
                
                if y > 0 && y < 22 && x > 0 && x < 80 && d > z[o] {
                    z[o] = d;
                    buffer[o] = ".,-~:;=!*#$@".chars().nth((luminance.max(0) as usize).min(11)).unwrap();
                }
                
                i += 0.02;
            }
            j += 0.07;
        }
        
        // Move cursor to home position
        print!("\x1b[H");
        
        // Print the frame
        for k in 0..1760 {
            if k % 80 == 0 {
                println!();
            } else {
                print!("{}", buffer[k]);
            }
        }
        
        a += 0.04;
        b += 0.02;
        thread::sleep(Duration::from_micros(30000));
    }

}
#46
C3 / Have a Donut in C3 - donut.c3
Last post by ron77 - Dec 24, 2024, 07:41 AM
donut.c3:

module example;

import std::math;
import std::io;
import std::thread;
import libc;

fn void main()
{
    float a1 = 0;
    float b1 = 0;
    float i;
    float j;
    int k;
    float[1760] z;
    char[1760] b;
    
    io::printf("\x1b[2J");
    
    while (true)
    {
        // Initialize arrays
        for (k = 0; k < 1760; k++)
        {
            b[k] = ' ';
            z[k] = 0;
        }
        
        for (j = 0; j < 6.28; j += 0.07)
        {
            for (i = 0; i < 6.28; i += 0.02)
            {
                float c = math::sin(i);
                float d = math::cos(j);
                float e = math::sin(a1);
                float f = math::sin(j);
                float g = math::cos(a1);
                float h = d + 2;
                float d2 = 1 / (c * h * e + f * g + 5);
                float l = math::cos(i);
                float m = math::cos(b1);
                float n = math::sin(b1);
                float t = c * h * g - f * e;
                
                int x = 40 + (int)(30 * d2 * (l * h * m - t * n));
                int y = 12 + (int)(15 * d2 * (l * h * n + t * m));
                int o = x + 80 * y;
                
                int n2 = (int)(8 * ((f * e - c * d * g) * m - c * d * e - f * g - l * d * n));
                
                if (y > 0 && y < 22 && x > 0 && x < 80 && d2 > z[o])
                {
                    z[o] = d2;
                    b[o] = n2 > 0 ? ".,-~:;=!*#$@"[n2] : ".,-~:;=!*#$@"[0];
                }
            }
        }
        
        io::printf("\x1b[H");
        for (k = 0; k < 1761; k++)
        {
            libc::putchar(k % 80 ? b[k] : 10);
        }
        
        a1 += 0.04;
        b1 += 0.02;
        thread::sleep_ms(30); // Replace usleep with thread::sleep_ms
    }
}
#47
C3 / C3 chatbot Danny
Last post by ron77 - Dec 24, 2024, 05:26 AM
hi all, well i converted my chatbot from C to C3 here is the code:

module c3_danny_std;

import std;
import libc;
import std::math::random;

extern fn char* strdup(char* s);

const int MAX_STRING_LENGTH = 1000;
const int MAX_ARRAY_SIZE = 1000;
const int MAX_KEYWORDS = 50;
const int MAX_REPLIES = 50;
const int MAX_MATCHES = 10;
const int MAX_SWAP_WORDS = 100;
const int MAX_MEMORY = 15;

/*
s:are>am
s:am>are
s:were>was
s:was>were
s:you>i
s:i>you
s:your>my
s:my>your
s:i've>you've
s:you've>i've
s:i'm>you're
s:you're>i'm
s:me>you
s:i'll>you'll
s:you'll>i'll
*/




String[] word_in = {
    "are",
    "am",
    "were",
    "was",
    "you",
    "i",
    "your",
    "my",
    "i've",
    "you've",
    "i'm",
    "you're",
    "me",
    "i'll",
    "you'll",

};
String[] word_out = {
    "am",
    "are",
    "was",
    "were",
    "i",
    "you",
    "my",
    "your",
    "you've",
    "i've",
    "you're",
    "i'm",
    "you",
    "you'll",
    "i'll",

};



String[MAX_SWAP_WORDS] wordIn;
String[MAX_SWAP_WORDS] wordOut;
int wCnt = 0;

String[MAX_MEMORY] memory;
int memoryCount = 0;

struct ArraySet {
    String[MAX_KEYWORDS] keywords;
    String[MAX_REPLIES] replies;
    int keywordCount;
    int replyCount;
} 

ArraySet[MAX_ARRAY_SIZE] g_Key_Reply;
int g_Key_ReplyCount = 0;

String[MAX_ARRAY_SIZE] default_replies;
int default_reply_count = 0;

fn char* safe_strdup(char* s) {
    if (!s) return null;
    char* result = strdup(s);
    if (!result) {
        io::printfn("%s Memory allocation failed in safe_strdup\n", &std::io::stderr);
        return null;
    }
    return result;
}

fn char* isolatePunctuation(char* s) {
    char* b = malloc(libc::strlen((ZString)s) * 3 + 1);
    if (!b) return null;
    
    int j = 0;
    for (int i = 0; s[i]; i++) {
        if (libc::strchr("?!,.:;<>(){}[]", s[i])) {
            b[j++] = ' ';
            b[j++] = s[i];
            b[j++] = ' ';
        } else {
            b[j++] = s[i];
        }
    }
    b[j] = '\0';
    return b;
}

fn void loadArrays(String filename) {
    File! f = io::file::open(filename, "r");
    if (catch error = f) {
        io::printfn("Error opening file: %s: %s\n", filename, error);
        return;
    }

    defer (void)f.close();

    // String line; no needs for this
    int currentSet = -1;
    
    while (try line = io::treadline(&f)) { // line is created here automatically
        if (line.len < 3) {
            // Skip lines that aren't long enough
            continue;
        }
        if (f.eof()) break;

        if (line[0..2] == "d1:") { //(strncmp(line, "d1:", 3) == 0) {
            default_replies[default_reply_count++] = line[3..]; //strcpy(default_replies[default_reply_count++], line + 3);
        }
    
        if (line[0..1] == "k:") { //(line[0] == 'k' && line[1] == ':') {
            if (currentSet == -1 || g_Key_Reply[currentSet].replyCount > 0) {
                currentSet++;
            }
            if (currentSet >= MAX_ARRAY_SIZE) {
                io::printfn("Error: too many keyword-reply pairs\n");
                break;
            }
            if (g_Key_Reply[currentSet].keywordCount < 50) {
                String keyword = string::tformat(" %s ", line[2..]);
            g_Key_Reply[currentSet].keywords[g_Key_Reply[currentSet].keywordCount] = keyword; //line[2..];//strcpy(g_Key_Reply[currentSet].keywords[g_Key_Reply[currentSet].keywordCount], line + 2);
            g_Key_Reply[currentSet].keywordCount++;
            g_Key_ReplyCount = currentSet + 1;
            // g_Key_Reply[currentSet].replyCount = 0;
            } else {
                io::printfn("Error: too many keywords for keyword-reply pair %d\n", currentSet);
            }
        } else if (line[0..1] == "r:") { //(line[0] == 'r' && line[1] == ':') {
            if (g_Key_Reply[currentSet].replyCount < 50) {
            g_Key_Reply[currentSet].replies[g_Key_Reply[currentSet].replyCount] = line[2..];//strcpy(g_Key_Reply[currentSet].replies[g_Key_Reply[currentSet].replyCount], line + 2);
            g_Key_Reply[currentSet].replyCount++;
            // g_Key_Reply[currentSet].keywordCount = 0;
            } else {
                io::printfn("Error: too many replies for keyword %s\n", g_Key_Reply[currentSet].keywords[g_Key_Reply[currentSet].keywordCount - 1]);
            }
        }
        
    }

     //fclose(file);
    io::printfn("number of keywords-replies pair groups %d\n", currentSet);

}

fn void loadSwapWords(String filename) {
    File! f = io::file::open(filename, "r");
    if (catch error = f) {
        io::printfn("Error opening file: %s: %s\n", filename, error);
        return;
    }

    defer (void)f.close();
    String line;
    while ((line = io::treadline(&f)!!) && wCnt < MAX_SWAP_WORDS) {
        if (line.len < 3) {
            // Skip lines that aren't long enough
                continue;
        }

        if (f.eof()) break;

        //line[strcspn(line, "\n")] = 0;  // Remove newline
        if (line[0..1] == "s:") { //(line[0] == 's' && line[1] == ':') {
            int indexOfdelimiter = (int)line.index_of(">")!!;
            // if (indexOfdelimiter != null) {
                wordIn[wCnt] = line[2..indexOfdelimiter];//strcpy(wordIn[wCnt], line + 2);
                wordOut[wCnt] = line[indexOfdelimiter + 1..line.len-1];//strcpy(wordOut[wCnt], delimiter + 1);
                wCnt++;
            // }
            // char* delimiter = strchr(line + 2, '>');
            // if (delimiter) {
            //     *delimiter = '\0';
            //     strcpy(wordIn[wCnt], line + 2);
            //     strcpy(wordOut[wCnt], delimiter + 1);
            //     wCnt++;
            // }
        }
    }

     //fclose(file);
}


fn String swapWords(String input) {
    if (input == "") return "";


    // DString output;
    String output;
    // output.temp_init();
    String[] words = input.tsplit(" ");
    String temp = "";
 

    foreach (j, word: words) {
        String result = word;
        bool swapped = false;

        foreach (i, swap_word: word_in) {
            if (word == word_in[i]) {
                result = word_out[i];
                break;
            }
        }

        output = String.tconcat(output, result);
        // if (j < words.len - 1) output.append(" ");
        if (j < words.len - 1) output = String.tconcat(output, " ");
    }


    // return output.str_view();
    return output;
}



fn String processReply(String reply, String userInput) {
    if (reply == "" || userInput == "") return reply;
    
    
    if (reply[reply.len - 1] == '*') {
        // If the reply doesn't end with an asterisk, don't swap words
        // return reply;
    // } else {
        reply = reply[0:reply.len-1];  // Remove the asterisk
        // reply = reply[0..reply.len-2];
    }  
    String keyword = "";
    for (int i = 0; i < g_Key_ReplyCount; i++) {
        for (int j = 0; j < g_Key_Reply[i].keywordCount; j++) {
            if (userInput.contains(g_Key_Reply[i].keywords[j])) {
                keyword = g_Key_Reply[i].keywords[j];
                break;
            }
        }
        if (keyword != "") break;
    }

    if (keyword != "") {
        int keywordIndex = (int)userInput.index_of(keyword)!!;
        String tail = userInput[keywordIndex + keyword.len..];
        String swappedTail = swapWords(tail);

        if (swappedTail != "") {
            reply = String.tconcat(reply, " ");
            reply = String.tconcat(reply, swappedTail);
        }
    }
    // }

    return reply;
}


// fn String userQuestion(String txt) {
//     String[MAX_MATCHES] matchedReplies;
//     int matchCount = 0;
//     bool isMatch = false;   
//     String finalReply = "";

//     // Find matching replies
//     for (int i = 0; i < g_Key_ReplyCount && matchCount < MAX_MATCHES; i++) {
//         bool foundInGroup = false;
//         for (int j = 0; j < g_Key_Reply[i].keywordCount; j++) {
//             if (txt.contains(g_Key_Reply[i].keywords[j])) {
//                 if (!foundInGroup) {
//                     int replyIndex = random::rand(g_Key_Reply[i].replyCount);
//                     matchedReplies[matchCount++] = g_Key_Reply[i].replies[replyIndex];
//                     foundInGroup = true;
//                     isMatch = true;
//                 }
//             }
//         }
//     }

//     // Process replies
//     if (matchCount > 0 && isMatch && matchCount <= MAX_MATCHES) {
//         foreach (reply : matchedReplies[0..matchCount]) {
//             String processed = processReply(reply, txt);
//             if (processed != "") {
//                 if (finalReply != "") {
//                     finalReply = String.tconcat(finalReply, " ");
//                 }
//                 finalReply = String.tconcat(finalReply, processed);
//             }
//         }
//         return finalReply.trim();
//     }

//     // Default reply
//     return default_replies[random::rand(default_reply_count)];
// }


fn String userQuestion(String txt) {
    String response = "I don't understand. Can you rephrase that?";
    String[MAX_MATCHES] matchedReplies;
    int matchCount = 0;
    bool isMatch = false;   
    String combinedReply = "";

    for (int i = 0; i < g_Key_ReplyCount && matchCount < MAX_MATCHES; i++) {
        for (int j = 0; j < g_Key_Reply[i].keywordCount; j++) {
            if (txt.contains(g_Key_Reply[i].keywords[j])) {
                int replyIndex = random::rand(g_Key_Reply[i].replyCount);
                matchedReplies[matchCount++] = g_Key_Reply[i].replies[replyIndex];
                isMatch = true;
                break;
            }
        }
    }

    if (matchCount > 0 && isMatch && matchCount <= MAX_MATCHES) {
        
        for (int i = 0 ; i < matchCount ; i++) {
            String reply = matchedReplies[i];
             if (reply[reply.len-1] == '*') {
            combinedReply = String.tconcat(combinedReply, processReply(reply, txt));
            } else {
                combinedReply = String.tconcat(combinedReply, reply);
            }
            combinedReply = String.tconcat(combinedReply, " ");
            
        }
    response = combinedReply;
    } else if (!isMatch) {
        int defaultIndex = random::rand(default_reply_count);
        response = default_replies[defaultIndex];
    }

    return response;
}





fn String commands(String txt) {
    // String isolated = isolatePunctuation(txt);
    // for (int i = 0; isolated[i]; i++) {
    //     isolated[i] = tolower(isolated[i]);
    // }
    String text = string::tformat(" %s ", txt);
    String response = userQuestion(text);
    
    // free(isolated);
    return response;
}

fn void speak(String text) {
    String command;
    command = "voice -r -1 -n \"Microsoft David Desktop\" ";
    String text2 = string::tformat("\"%s\"",text);
    // command = string::tformat("%s \"%s\"", command, text2);
    command = String.tconcat(command, text2);
    // command = String.tconcat(text2, "\"");
    // String.tconcat(command, text2);
    libc::system((ZString)command);
}

fn int main() {
    libc::srand((uint)libc::time(null));
    
    loadArrays("./database.txt");
    // loadSwapWords("./swapwords.txt");

    // for (int i = 0; i < wCnt; i++) {
    //     io::printfn("wordIn[%d] = %s, wordOut[%d] = %s\n", i, wordIn[i], i, wordOut[i]);
    // }
    
    io::printfn("CHATBOT DANNY IN C3 PROGRAMMING LANGUAGE VERSION 1.1.6.5 (C) RON77\n");
    
    String input;
    String response;
    
    while (true) {
        io::printf("> ");
        //if (fgets(input, sizeof(input), stdin) == NULL) {
        input = io::treadline()!!; 
            
        
        // input[strcspn(input, "\n")] = 0;  // Remove newline
        
        if (input == "quit") break;
        
        response = commands(input);
        
        if (response != "") {
            // Split the response into separate lines and speak each one
            String line = response;
            while (line != "") {
                io::printn(line);
                io::printn("\n");
                speak(line);
                line = "";
            }
            
            // free(response);
        } else {
            io::printfn("An error occurred while processing your input.\n");
        }
    }
    
    return 0;
}

The database.txt can be found here, as well as the 'voice.exe' TTS cli engine for Windows...
https://retrocoders.phatcode.net/index.php?topic=840.0
#48
C3 / C3 ELIZA Chatbot 2 versions
Last post by ron77 - Dec 20, 2024, 04:28 AM
hi... The first version uses libc of C3 and follows the way of C-like implementation.

The second version uses the C3 standard library and implements ELIZA the full C3 way...


c3_eliza-libc.c3:
/* eliza.c
 * ys
 * original code by Weizenbaum, 1966
 * this rendition based on Charles Hayden's Java implementation from http://chayden.net/eliza/Eliza.html
 *
 * Note: There are certainly far more optimal and elegant ways to code this... we kept this
 * structure to be faithful to the original.  -scaz
 */

<*
    converted to C3 by: ronen blumberg (ron77) 2024 helped bt christoffer lerno

*>
import std;
import libc;

const int NUMKEYWORDS = 37;
const int MAXLINELEN = 80;
const int NUMSWAPS = 14;

const ZString[] KEYWORDS = {
    "CAN YOU", "CAN I", "YOU ARE", "YOURE", "I DONT", "I FEEL",
    "WHY DONT YOU", "WHY CANT I", "ARE YOU", "I CANT", "I AM", "IM ",
    "YOU ", "I WANT", "WHAT", "HOW", "WHO", "WHERE",
    "WHEN", "WHY",
    "NAME", "CAUSE", "SORRY", "DREAM", "HELLO", "HI ", "MAYBE",
    " NO", "YOUR", "ALWAYS", "THINK", "ALIKE", "YES", "FRIEND",
    "COMPUTER", "CAR", "NOKEYFOUND"
};

const ZString[2][NUMSWAPS] SWAPS = {
    {"ARE", "AM"},
    {"WERE", "WAS"},
    {"YOU", "I"},
    {"YOUR", "MY"},
    {"IVE", "YOU'VE"},
    {"IM", "YOU'RE"},
    {"YOU", "ME"},
    {"ME", "YOU"},
    {"AM", "ARE"},
    {"WAS", "WERE"},
    {"I", "YOU"},
    {"MY", "YOUR"},
    {"YOUVE", "I'VE"},
    {"YOURE", "I'M"}
};

int[37] responsesperkeyword = {
    3, 2, 4, 4, 4, 3,
    3, 2, 3, 3, 4, 4,
    3, 5, 9, 9, 9, 9,
    9, 9,
    2, 4, 4, 4, 1, 1, 5,
    5, 2, 4, 3, 7, 3, 6,
    7, 5, 6
};

const ZString[][NUMKEYWORDS] RESPONSES = {
    {   "DON'T YOU BELIEVE THAT I CAN*",
        "PERHAPS YOU WOULD LIKE TO BE ABLE TO*",
        "YOU WANT ME TO BE ABLE TO*"},
    {   "PERHAPS YOU DON'T WANT TO*",
        "DO YOU WANT TO BE ABLE TO*"},
    {   "WHAT MAKES YOU THINK I AM*",
        "DOES IT PLEASE YOU TO BELIEVE I AM*",
        "PERHAPS YOU WOULD LIKE TO BE*",
        "DO YOU SOMETIMES WISH YOU WERE*"},
    {   "WHAT MAKES YOU THINK I AM*",
        "DOES IT PLEASE YOU TO BELIEVE I AM*",
        "PERHAPS YOU WOULD LIKE TO BE*",
        "DO YOU SOMETIMES WISH YOU WERE*"},
    {   "DON'T YOU REALLY*",
        "WHY DON'T YOU*",
        "DO YOU WISH TO BE ABLE TO*",
        "DOES THAT TROUBLE YOU?"},
    {   "TELL ME MORE ABOUT SUCH FEELINGS.",
        "DO YOU OFTEN FEEL*",
        "DO YOU ENJOY FEELING*"},
    {   "DO YOU REALLY BELIEVE I DON'T*",
        "PERHAPS IN GOOD TIME I WILL*",
        "DO YOU WANT ME TO*"},
    {   "DO YOU THINK YOU SHOULD BE ABLE TO*",
        "WHY CAN'T YOU*"},
    {   "WHY ARE YOU INTERESTED IN WHETHER OR NOT I AM*",
        "WOULD YOU PREFER IF I WERE NOT*",
        "PERHAPS IN YOUR FANTASIES I AM*"},
    {   "HOW DO YOU KNOW YOU CAN'T*",
        "HAVE YOU TRIED?",
        "PERHAPS YOU CAN NOW*"},
    {   "DID YOU COME TO ME BECAUSE YOU ARE*",
        "HOW LONG HAVE YOU BEEN*",
        "DO YOU BELIEVE IT IS NORMAL TO BE*",
        "DO YOU ENJOY BEING*"},
    {   "DID YOU COME TO ME BECAUSE YOU ARE*",
        "HOW LONG HAVE YOU BEEN*",
        "DO YOU BELIEVE IT IS NORMAL TO BE*",
        "DO YOU ENJOY BEING*"},
    {   "WE WERE DISCUSSING YOU-- NOT ME.",
        "OH, I*",
        "YOU'RE NOT REALLY TALKING ABOUT ME, ARE YOU?"},
    {   "WHAT WOULD IT MEAN TO YOU IF YOU GOT*",
        "WHY DO YOU WANT*",
        "SUPPOSE YOU SOON GOT*",
        "WHAT IF YOU NEVER GOT*",
        "I SOMETIMES ALSO WANT*"},
    {   "WHY DO YOU ASK?",
        "DOES THAT QUESTION INTEREST YOU?",
        "WHAT ANSWER WOULD PLEASE YOU THE MOST?",
        "WHAT DO YOU THINK?",
        "ARE SUCH QUESTIONS ON YOUR MIND OFTEN?",
        "WHAT IS IT THAT YOU REALLY WANT TO KNOW?",
        "HAVE YOU ASKED ANYONE ELSE?",
        "HAVE YOU ASKED SUCH QUESTIONS BEFORE?",
        "WHAT ELSE COMES TO MIND WHEN YOU ASK THAT?"},
    {   "WHY DO YOU ASK?",
        "DOES THAT QUESTION INTEREST YOU?",
        "WHAT ANSWER WOULD PLEASE YOU THE MOST?",
        "WHAT DO YOU THINK?",
        "ARE SUCH QUESTIONS ON YOUR MIND OFTEN?",
        "WHAT IS IT THAT YOU REALLY WANT TO KNOW?",
        "HAVE YOU ASKED ANYONE ELSE?",
        "HAVE YOU ASKED SUCH QUESTIONS BEFORE?",
        "WHAT ELSE COMES TO MIND WHEN YOU ASK THAT?"},
    {   "WHY DO YOU ASK?",
        "DOES THAT QUESTION INTEREST YOU?",
        "WHAT ANSWER WOULD PLEASE YOU THE MOST?",
        "WHAT DO YOU THINK?",
        "ARE SUCH QUESTIONS ON YOUR MIND OFTEN?",
        "WHAT IS IT THAT YOU REALLY WANT TO KNOW?",
        "HAVE YOU ASKED ANYONE ELSE?",
        "HAVE YOU ASKED SUCH QUESTIONS BEFORE?",
        "WHAT ELSE COMES TO MIND WHEN YOU ASK THAT?"},
    {   "WHY DO YOU ASK?",
        "DOES THAT QUESTION INTEREST YOU?",
        "WHAT ANSWER WOULD PLEASE YOU THE MOST?",
        "WHAT DO YOU THINK?",
        "ARE SUCH QUESTIONS ON YOUR MIND OFTEN?",
        "WHAT IS IT THAT YOU REALLY WANT TO KNOW?",
        "HAVE YOU ASKED ANYONE ELSE?",
        "HAVE YOU ASKED SUCH QUESTIONS BEFORE?",
        "WHAT ELSE COMES TO MIND WHEN YOU ASK THAT?"},
    {   "WHY DO YOU ASK?",
        "DOES THAT QUESTION INTEREST YOU?",
        "WHAT ANSWER WOULD PLEASE YOU THE MOST?",
        "WHAT DO YOU THINK?",
        "ARE SUCH QUESTIONS ON YOUR MIND OFTEN?",
        "WHAT IS IT THAT YOU REALLY WANT TO KNOW?",
        "HAVE YOU ASKED ANYONE ELSE?",
        "HAVE YOU ASKED SUCH QUESTIONS BEFORE?",
        "WHAT ELSE COMES TO MIND WHEN YOU ASK THAT?"},
    {   "WHY DO YOU ASK?",
        "DOES THAT QUESTION INTEREST YOU?",
        "WHAT ANSWER WOULD PLEASE YOU THE MOST?",
        "WHAT DO YOU THINK?",
        "ARE SUCH QUESTIONS ON YOUR MIND OFTEN?",
        "WHAT IS IT THAT YOU REALLY WANT TO KNOW?",
        "HAVE YOU ASKED ANYONE ELSE?",
        "HAVE YOU ASKED SUCH QUESTIONS BEFORE?",
        "WHAT ELSE COMES TO MIND WHEN YOU ASK THAT?"},
    {   "NAMES DON'T INTEREST ME.",
        "I DON'T CARE ABOUT NAMES-- PLEASE GO ON."},
    {   "IS THAT THE REAL REASON?",
        "DON'T ANY OTHER REASONS COME TO MIND?",
        "DOES THAT REASON EXPLAIN ANY THING ELSE?",
        "WHAT OTHER REASONS MIGHT THERE BE?"},
    {   "PLEASE DON'T APOLOGIZE.",
        "APOLOGIES ARE NOT NECESSARY.",
        "WHAT FEELINGS DO YOU HAVE WHEN YOU APOLOGIZE?",
        "DON'T BE SO DEFENSIVE!"},
    {   "WHAT DOES THAT DREAM SUGGEST TO YOU?",
        "DO YOU DREAM OFTEN?",
        "WHAT PERSONS APPEAR IN YOUR DREAMS?",
        "ARE YOU DISTURBED BY YOUR DREAMS?"},
    {   "HOW DO YOU DO--PLEASE STATE YOUR PROBLEM."},
    {   "HOW DO YOU DO--PLEASE STATE YOUR PROBLEM."},
    {   "YOU DON'T SEEM QUITE CERTAIN.",
        "WHY THE UNCERTAIN TONE?",
        "CAN'T YOU BE MORE POSITIVE?",
        "YOU AREN'T SURE?",
        "DON'T YOU KNOW?"},
    {   "ARE YOU SAYING NO JUST TO BE NEGATIVE?",
        "YOU ARE BEING A BIT NEGATIVE.",
        "WHY NOT?",
        "ARE YOU SURE?",
        "WHY NO?"},
    {   "WHY ARE YOU CONCERNED ABOUT MY*",
        "WHAT ABOUT YOUR OWN*"},
    {   "CAN YOU THINK OF A SPECIFIC EXAMPLE?",
        "WHEN?",
        "WHAT ARE YOU THINKING OF?",
        "REALLY, ALWAYS?"},
    {   "DO YOU REALLY THINK SO?",
        "BUT YOU ARE NOT SURE YOU*",
        "DO YOU DOUBT YOU*"},
    {   "IN WHAT WAY?",
        "WHAT RESEMBLANCE DO YOU SEE?",
        "WHAT DOES THE SIMILARITY SUGGEST TO YOU?",
        "WHAT OTHER CONNECTIONS DO YOU SEE?",
        "COULD THERE REALLY BE SOME CONNECTION?",
        "HOW?"},
    {   "YOU SEEM QUITE POSITIVE.",
        "ARE YOU SURE?",
        "I SEE.",
        "I UNDERSTAND."},
    {   "WHY DO YOU BRING UP THE TOPIC OF FRIENDS?",
        "DO YOUR FRIENDS WORRY YOU?",
        "DO YOUR FRIENDS PICK ON YOU?",
        "ARE YOU SURE YOU HAVE ANY FRIENDS?",
        "DO YOU IMPOSE ON YOUR FRIENDS?",
        "PERHAPS YOUR LOVE FOR FRIENDS WORRIES YOU?"},
    {   "DO COMPUTERS WORRY YOU?",
        "ARE YOU TALKING ABOUT ME IN PARTICULAR?",
        "ARE YOU FRIGHTENED BY MACHINES?",
        "WHY DO YOU MENTION COMPUTERS?",
        "WHAT DO YOU THINK MACHINES HAVE TO DO WITH YOUR PROBLEM?",
        "DON'T YOU THINK COMPUTERS CAN HELP PEOPLE?",
        "WHAT IS IT ABOUT MACHINES THAT WORRIES YOU?"},
    {   "OH, DO YOU LIKE CARS?",
        "MY FAVORITE CAR IS A LAMBORGINI COUNTACH. WHAT IS YOUR FAVORITE     CAR?",
        "MY FAVORITE CAR COMPANY IS FERRARI.  WHAT IS YOURS?",
        "DO YOU LIKE PORSCHES?",
        "DO YOU LIKE PORSCHE TURBO CARRERAS?"},
    {   "SAY, DO YOU HAVE ANY PSYCHOLOGICAL PROBLEMS?",
        "WHAT DOES THAT SUGGEST TO YOU?",
        "I SEE.",
        "I'M NOT SURE I UNDERSTAND YOU FULLY.",
        "COME, COME ELUCIDATE YOUR THOUGHTS.",
        "CAN YOU ELABORATE ON THAT?",
        "THAT IS QUITE INTERESTING."}
};

fn void print_center(String msg) {
    int numspaces = (MAXLINELEN - (int)libc::strlen((ZString)msg)) / 2;
    for (int i = 0; i < numspaces; i++) {
        io::print(" ");
    }
    io::printn(msg);
}

fn void print_title() {
    io::printfn("\n\n");
    print_center("*** ELIZA ***");
    print_center("Original code by Weizenbaum, 1966");
    print_center("To stop Eliza, type 'bye'");
    io::printfn("\n\n");
    io::printfn("HI!  I'M ELIZA.  WHAT'S YOUR PROBLEM?");
}

fn void readline(char* instr) {
    char c;
    int slen = 0;

    c = (char)libc::getchar();
    while (c != '\n') {
        // removes punctuation and sets to uppercase
        if (c.is_alpha() || c.is_space()) {
            instr[slen++] = c.to_upper();
        }
        if (slen > MAXLINELEN-1) {
            io::printn("Exceeded Max Line Length");
            std::thread::exit(0);
        }
        c = (char)libc::getchar();
    }
    instr[slen] = '\0';
}

const ZString SEPARATOR = " ";

fn void main()
{
    int k,baseLength;
    int[NUMKEYWORDS] whichReply;
    char[MAXLINELEN] lastinput;
    char[MAXLINELEN] reply;
    ZString baseResponse, token;
    char[MAXLINELEN] inputstr;

    // use the first reply for each keyword match the first time you see that keyword
    for (int x=0;x< NUMKEYWORDS; x++) {
        whichReply[x] = 0;
    }

    // print a nice centered title screen
    print_title();

    lastinput[0]='\0';

    while (true) {
        readline(&inputstr);

        // check for termination
        if (libc::strcmp((ZString)&inputstr,"BYE")==0) break;

        // check for repeated entries
        if (libc::strcmp((ZString)&lastinput,(ZString)&inputstr)==0)
        {
            io::printn("PLEASE DON'T REPEAT YOURSELF!");
            continue;
        }
        libc::strncpy(&lastinput,&inputstr,libc::strlen((ZString)&inputstr)+1);

        // see if any of the keywords is contained in the input
        // if not, we use the last element of keywords as our default responses
        char *location;
        libc::strcpy((ZString)&reply,"");
        for(k=0;k<NUMKEYWORDS-1;k++)
        {
            location=libc::strstr((ZString)&inputstr, KEYWORDS[k]);
            if(location != null) break;
        }
        // Build Eliza's response
        // start with Eliza's canned response, based on the keyword match
        baseResponse = RESPONSES[k][whichReply[k]];
        baseLength = (int)libc::strlen(baseResponse);

        if(baseResponse[baseLength-1] != '*')
        {
            // if we have a baseResponse without an asterix, just use it as-is
            libc::strcat((ZString)&reply, baseResponse);
        }
        else
        {
            // if we do have an asterix, fill in the remaining with the user input
            // use all but the last character of the base response
            libc::strncat((ZString)&reply, baseResponse, (usz)baseLength-1);

            // now add in the rest of the user's input, starting at <location>
            // but skip over the keyword itself
            location+=libc::strlen(KEYWORDS[k]);
            // take them one word at a time, so that we can substitute pronouns
            token = libc::strtok((ZString)location, SEPARATOR);
            while(token != null)
            {
                for(int s=0;s<NUMSWAPS;s++)
                {
                    if(libc::strcmp(SWAPS[s][0], token) == 0)
                    {
                        token = (ZString) SWAPS[s][1];
                        break;
                    }
                }
                libc::strcat((ZString)&reply,SEPARATOR);
                libc::strcat((ZString)&reply, token);
                token=libc::strtok(null, SEPARATOR);
            };
            libc::strcat((ZString)&reply, "?");
        }
        io::printfn("%s", (ZString)&reply);

        // next time, use the next appropriate reply for that keyword
        whichReply[k]++;
        if ( whichReply[k] >= responsesperkeyword[k]) whichReply[k] = 0;

    }

    io::printn( "GOODBYE!  THANKS FOR VISITING WITH ME...");

}


c3_eliza-std.c3:
/* eliza.c  
 * ys
 * original code by Weizenbaum, 1966
 * this rendition based on Charles Hayden's Java implementation from http://chayden.net/eliza/Eliza.html
 *
 * Note: There are certainly far more optimal and elegant ways to code this... we kept this
 * structure to be faithful to the original.  -scaz 
 */

<* 
    converted to C3 by: ronen blumberg (ron77) 2024

*>
import std;
import libc;


const int NUMKEYWORDS = 37;
const int MAXLINELEN = 80;
const int NUMSWAPS = 14;

const String[] KEYWORDS = {
    "CAN YOU", "CAN I", "YOU ARE", "YOURE", "I DONT", "I FEEL",
    "WHY DONT YOU", "WHY CANT I", "ARE YOU", "I CANT", "I AM", "IM ",
    "YOU ", "I WANT", "WHAT", "HOW", "WHO", "WHERE",
    "WHEN", "WHY",
    "NAME", "CAUSE", "SORRY", "DREAM", "HELLO", "HI ", "MAYBE",
    " NO", "YOUR", "ALWAYS", "THINK", "ALIKE", "YES", "FRIEND",
    "COMPUTER", "CAR", "NOKEYFOUND"
};

const String[2][NUMSWAPS] SWAPS = {
    {"ARE", "AM"},
    {"WERE", "WAS"},
    {"YOU", "I"},
    {"YOUR", "MY"},
    {"IVE", "YOU'VE"},
    {"IM", "YOU'RE"},
    {"YOU", "ME"},
    {"ME", "YOU"},
    {"AM", "ARE"},
    {"WAS", "WERE"},
    {"I", "YOU"},
    {"MY", "YOUR"},
    {"YOUVE", "I'VE"},
    {"YOURE", "I'M"}
};

int[NUMKEYWORDS] responsesperkeyword = {
    3, 2, 4, 4, 4, 3,
    3, 2, 3, 3, 4, 4,
    3, 5, 9, 9, 9, 9,
    9, 9,
    2, 4, 4, 4, 1, 1, 5,
    5, 2, 4, 3, 7, 3, 6,
    7, 5, 6
};

const String[][NUMKEYWORDS] RESPONSES = {
    {   "DON'T YOU BELIEVE THAT I CAN*",
        "PERHAPS YOU WOULD LIKE TO BE ABLE TO*",
        "YOU WANT ME TO BE ABLE TO*"},
    {   "PERHAPS YOU DON'T WANT TO*",
        "DO YOU WANT TO BE ABLE TO*"},
    {   "WHAT MAKES YOU THINK I AM*",
        "DOES IT PLEASE YOU TO BELIEVE I AM*",
        "PERHAPS YOU WOULD LIKE TO BE*",
        "DO YOU SOMETIMES WISH YOU WERE*"},
    {   "WHAT MAKES YOU THINK I AM*",
        "DOES IT PLEASE YOU TO BELIEVE I AM*",
        "PERHAPS YOU WOULD LIKE TO BE*",
        "DO YOU SOMETIMES WISH YOU WERE*"},
    {   "DON'T YOU REALLY*",
        "WHY DON'T YOU*",
        "DO YOU WISH TO BE ABLE TO*",
        "DOES THAT TROUBLE YOU?"},
    {   "TELL ME MORE ABOUT SUCH FEELINGS.",
        "DO YOU OFTEN FEEL*",
        "DO YOU ENJOY FEELING*"},
    {   "DO YOU REALLY BELIEVE I DON'T*",
        "PERHAPS IN GOOD TIME I WILL*",
        "DO YOU WANT ME TO*"},
    {   "DO YOU THINK YOU SHOULD BE ABLE TO*",
        "WHY CAN'T YOU*"},
    {   "WHY ARE YOU INTERESTED IN WHETHER OR NOT I AM*",
        "WOULD YOU PREFER IF I WERE NOT*",
        "PERHAPS IN YOUR FANTASIES I AM*"},
    {   "HOW DO YOU KNOW YOU CAN'T*",
        "HAVE YOU TRIED?",
        "PERHAPS YOU CAN NOW*"},
    {   "DID YOU COME TO ME BECAUSE YOU ARE*",
        "HOW LONG HAVE YOU BEEN*",
        "DO YOU BELIEVE IT IS NORMAL TO BE*",
        "DO YOU ENJOY BEING*"},
    {   "DID YOU COME TO ME BECAUSE YOU ARE*",
        "HOW LONG HAVE YOU BEEN*",
        "DO YOU BELIEVE IT IS NORMAL TO BE*",
        "DO YOU ENJOY BEING*"},
    {   "WE WERE DISCUSSING YOU-- NOT ME.",
        "OH, I*",
        "YOU'RE NOT REALLY TALKING ABOUT ME, ARE YOU?"},
    {   "WHAT WOULD IT MEAN TO YOU IF YOU GOT*",
        "WHY DO YOU WANT*",
        "SUPPOSE YOU SOON GOT*",
        "WHAT IF YOU NEVER GOT*",
        "I SOMETIMES ALSO WANT*"},
    {   "WHY DO YOU ASK?",
        "DOES THAT QUESTION INTEREST YOU?",
        "WHAT ANSWER WOULD PLEASE YOU THE MOST?",
        "WHAT DO YOU THINK?",
        "ARE SUCH QUESTIONS ON YOUR MIND OFTEN?",
        "WHAT IS IT THAT YOU REALLY WANT TO KNOW?",
        "HAVE YOU ASKED ANYONE ELSE?",
        "HAVE YOU ASKED SUCH QUESTIONS BEFORE?",
        "WHAT ELSE COMES TO MIND WHEN YOU ASK THAT?"},
    {   "WHY DO YOU ASK?",
        "DOES THAT QUESTION INTEREST YOU?",
        "WHAT ANSWER WOULD PLEASE YOU THE MOST?",
        "WHAT DO YOU THINK?",
        "ARE SUCH QUESTIONS ON YOUR MIND OFTEN?",
        "WHAT IS IT THAT YOU REALLY WANT TO KNOW?",
        "HAVE YOU ASKED ANYONE ELSE?",
        "HAVE YOU ASKED SUCH QUESTIONS BEFORE?",
        "WHAT ELSE COMES TO MIND WHEN YOU ASK THAT?"},
    {   "WHY DO YOU ASK?",
        "DOES THAT QUESTION INTEREST YOU?",
        "WHAT ANSWER WOULD PLEASE YOU THE MOST?",
        "WHAT DO YOU THINK?",
        "ARE SUCH QUESTIONS ON YOUR MIND OFTEN?",
        "WHAT IS IT THAT YOU REALLY WANT TO KNOW?",
        "HAVE YOU ASKED ANYONE ELSE?",
        "HAVE YOU ASKED SUCH QUESTIONS BEFORE?",
        "WHAT ELSE COMES TO MIND WHEN YOU ASK THAT?"},
    {   "WHY DO YOU ASK?",
        "DOES THAT QUESTION INTEREST YOU?",
        "WHAT ANSWER WOULD PLEASE YOU THE MOST?",
        "WHAT DO YOU THINK?",
        "ARE SUCH QUESTIONS ON YOUR MIND OFTEN?",
        "WHAT IS IT THAT YOU REALLY WANT TO KNOW?",
        "HAVE YOU ASKED ANYONE ELSE?",
        "HAVE YOU ASKED SUCH QUESTIONS BEFORE?",
        "WHAT ELSE COMES TO MIND WHEN YOU ASK THAT?"},
    {   "WHY DO YOU ASK?",
        "DOES THAT QUESTION INTEREST YOU?",
        "WHAT ANSWER WOULD PLEASE YOU THE MOST?",
        "WHAT DO YOU THINK?",
        "ARE SUCH QUESTIONS ON YOUR MIND OFTEN?",
        "WHAT IS IT THAT YOU REALLY WANT TO KNOW?",
        "HAVE YOU ASKED ANYONE ELSE?",
        "HAVE YOU ASKED SUCH QUESTIONS BEFORE?",
        "WHAT ELSE COMES TO MIND WHEN YOU ASK THAT?"},
    {   "WHY DO YOU ASK?",
        "DOES THAT QUESTION INTEREST YOU?",
        "WHAT ANSWER WOULD PLEASE YOU THE MOST?",
        "WHAT DO YOU THINK?",
        "ARE SUCH QUESTIONS ON YOUR MIND OFTEN?",
        "WHAT IS IT THAT YOU REALLY WANT TO KNOW?",
        "HAVE YOU ASKED ANYONE ELSE?",
        "HAVE YOU ASKED SUCH QUESTIONS BEFORE?",
        "WHAT ELSE COMES TO MIND WHEN YOU ASK THAT?"},
    {   "NAMES DON'T INTEREST ME.",
        "I DON'T CARE ABOUT NAMES-- PLEASE GO ON."},
    {   "IS THAT THE REAL REASON?",
        "DON'T ANY OTHER REASONS COME TO MIND?",
        "DOES THAT REASON EXPLAIN ANY THING ELSE?",
        "WHAT OTHER REASONS MIGHT THERE BE?"},
    {   "PLEASE DON'T APOLOGIZE.",
        "APOLOGIES ARE NOT NECESSARY.",
        "WHAT FEELINGS DO YOU HAVE WHEN YOU APOLOGIZE?",
        "DON'T BE SO DEFENSIVE!"},
    {   "WHAT DOES THAT DREAM SUGGEST TO YOU?",
        "DO YOU DREAM OFTEN?",
        "WHAT PERSONS APPEAR IN YOUR DREAMS?",
        "ARE YOU DISTURBED BY YOUR DREAMS?"},
    {   "HOW DO YOU DO--PLEASE STATE YOUR PROBLEM."},
    {   "HOW DO YOU DO--PLEASE STATE YOUR PROBLEM."},
    {   "YOU DON'T SEEM QUITE CERTAIN.",
        "WHY THE UNCERTAIN TONE?",
        "CAN'T YOU BE MORE POSITIVE?",
        "YOU AREN'T SURE?",
        "DON'T YOU KNOW?"},
    {   "ARE YOU SAYING NO JUST TO BE NEGATIVE?",
        "YOU ARE BEING A BIT NEGATIVE.",
        "WHY NOT?",
        "ARE YOU SURE?",
        "WHY NO?"},
    {   "WHY ARE YOU CONCERNED ABOUT MY*",
        "WHAT ABOUT YOUR OWN*"},
    {   "CAN YOU THINK OF A SPECIFIC EXAMPLE?",
        "WHEN?",
        "WHAT ARE YOU THINKING OF?",
        "REALLY, ALWAYS?"},
    {   "DO YOU REALLY THINK SO?",
        "BUT YOU ARE NOT SURE YOU*",
        "DO YOU DOUBT YOU*"},
    {   "IN WHAT WAY?",
        "WHAT RESEMBLANCE DO YOU SEE?",
        "WHAT DOES THE SIMILARITY SUGGEST TO YOU?",
        "WHAT OTHER CONNECTIONS DO YOU SEE?",
        "COULD THERE REALLY BE SOME CONNECTION?",
        "HOW?"},
    {   "YOU SEEM QUITE POSITIVE.",
        "ARE YOU SURE?",
        "I SEE.",
        "I UNDERSTAND."},
    {   "WHY DO YOU BRING UP THE TOPIC OF FRIENDS?",
        "DO YOUR FRIENDS WORRY YOU?",
        "DO YOUR FRIENDS PICK ON YOU?",
        "ARE YOU SURE YOU HAVE ANY FRIENDS?",
        "DO YOU IMPOSE ON YOUR FRIENDS?",
        "PERHAPS YOUR LOVE FOR FRIENDS WORRIES YOU?"},
    {   "DO COMPUTERS WORRY YOU?",
        "ARE YOU TALKING ABOUT ME IN PARTICULAR?",
        "ARE YOU FRIGHTENED BY MACHINES?",
        "WHY DO YOU MENTION COMPUTERS?",
        "WHAT DO YOU THINK MACHINES HAVE TO DO WITH YOUR PROBLEM?",
        "DON'T YOU THINK COMPUTERS CAN HELP PEOPLE?",
        "WHAT IS IT ABOUT MACHINES THAT WORRIES YOU?"},
    {   "OH, DO YOU LIKE CARS?",
        "MY FAVORITE CAR IS A LAMBORGINI COUNTACH. WHAT IS YOUR FAVORITE     CAR?",
        "MY FAVORITE CAR COMPANY IS FERRARI.  WHAT IS YOURS?",
        "DO YOU LIKE PORSCHES?",
        "DO YOU LIKE PORSCHE TURBO CARRERAS?"},
    {   "SAY, DO YOU HAVE ANY PSYCHOLOGICAL PROBLEMS?",
        "WHAT DOES THAT SUGGEST TO YOU?",
        "I SEE.",
        "I'M NOT SURE I UNDERSTAND YOU FULLY.",
        "COME, COME ELUCIDATE YOUR THOUGHTS.",
        "CAN YOU ELABORATE ON THAT?",
        "THAT IS QUITE INTERESTING."}
};

fn void print_center(String msg) {
    int numspaces = (MAXLINELEN - (int)libc::strlen((ZString)msg)) / 2;
    for (int i = 0; i < numspaces; i++) {
        io::print(" ");
    }
    io::printn(msg);
}

fn void print_title() {
    io::printfn("\n\n");
    print_center("*** ELIZA ***");
    print_center("Original code by Weizenbaum, 1966");
    print_center("To stop Eliza, type 'bye'");
    io::printfn("\n\n");
    io::printfn("HI!  I'M ELIZA.  WHAT'S YOUR PROBLEM?");
}

const String SEPARETOR = " ";

fn void main()
{
    int k,baseLength; 
    int[NUMKEYWORDS] whichReply;
    String lastinput;
    String reply;
    String baseResponse, token;
    String inputstr;
    
    // use the first reply for each keyword match the first time you see that keyword
    for (int x=0;x< NUMKEYWORDS; x++) {
        whichReply[x] = 0;
    }

    // print a nice centered title screen
    print_title();

    lastinput = "";
    
    while (true) { 
        inputstr = io::treadline()!!;
                
        // check for termination 
        if (inputstr == "BYE") break; 

        // check for repeated entries 
        if (lastinput == inputstr) 
        {
            io::printfn("PLEASE DON'T REPEAT YOURSELF!\n"); 
            continue;
        }
        lastinput = inputstr; 

        // see if any of the keywords is contained in the input 
        // if not, we use the last element of keywords as our default responses 
        String location;
        reply = "";
        for(k=0;k<NUMKEYWORDS-1;k++)
        {
            if (inputstr.contains(KEYWORDS[k])) location = KEYWORDS[k];
            // location=libc::strstr(inputstr, keywords[k]); 
            if(location != "") break;
        }
        
        // Build Eliza's response 
        // start with Eliza's canned response, based on the keyword match
        baseResponse = RESPONSES[k][whichReply[k]];
        baseLength = baseResponse.len;

        if(baseResponse[baseLength-1] != '*')
        {
            // if we have a baseResponse without an asterix, just use it as-is
            reply = baseResponse;
        }
        else
        {
            // if we do have an asterix, fill in the remaining with the user input
            // use all but the last character of the base response
            reply = baseResponse[0:baseLength-1];

            // now add in the rest of the user's input, starting at <location>
            // but skip over the keyword itself
            // location = KEYWORDS[k];
            // int keywordLength = KEYWORDS[k].len;
            // int inputLength = inputstr.len;
            // location = inputstr[keywordLength: inputstr.len];
            int keywordIndex = (int)inputstr.index_of(KEYWORDS[k])!!;
            int keywordLength = KEYWORDS[k].len;
            int startPosition = keywordIndex + keywordLength;

            // Ensure startPosition is within bounds
            if (startPosition < inputstr.len) {
                location = inputstr[startPosition..inputstr.len-1];
            } else {
                location = "";
            }
            // Remove leading spaces if necessary
            // location = location.trim_start();
            // take them one word at a time, so that we can substitute pronouns
            String[] tokens = location.split(" ");
            // String.tconcat(location, SEPARETOR);
            // String token_temp = location;
            for (int i = 0; i < tokens.len; i++) {
                token = tokens[i];
                // Substitute pronouns
                for (int s = 0; s < NUMSWAPS; s++) {
                    if (SWAPS[s][0] == token) {
                        token = SWAPS[s][1];
                        break;
                    }
                }
                // Concatenate the token to the reply
                reply = reply.tconcat(" ").concat(token);
            };
             String.tconcat(reply, "?");
            
        }
        io::printfn("%s\n", reply);
        
        // next time, use the next appropriate reply for that keyword
        whichReply[k]++;
        if ( whichReply[k] >= responsesperkeyword[k]) whichReply[k] = 0;

    } 

    io::printfn( "GOODBYE!  THANKS FOR VISITING WITH ME...\n");

}


C3_ELIZA on github
#49
C3 / C3 Links
Last post by ron77 - Dec 17, 2024, 08:32 PM
#50
C3 / C3 Text Game for Windows OS (G...
Last post by ron77 - Dec 17, 2024, 08:26 PM
SMF spam blocked by CleanTalk