Learning to program in RUST, together

Discussion of chess software programming and technical issues.

Moderators: bob, hgm, Harvey Williamson

Forum rules
This textbox is used to restore diagrams posted with the [d] tag before the upgrade.
Michael Sherwin
Posts: 3041
Joined: Fri May 26, 2006 1:00 am
Location: WY, USA
Full name: Michael Sherwin

Learning to program in RUST, together

Post by Michael Sherwin » Mon Dec 29, 2014 3:35 am

For those that want to investigate this new programming language let's begin. I downloaded RUSTC the Rust compiler, Cargo the Rust project manager, the Atom programming editor and a Rust package for atom. Somehow I got it all working.

Rust would seem to have quite a few advantages for chess programming like speed, data safety and maybe simpler SMP with race condition safety. And other advantages. You can research that for yourselves.

The downside (or another upside) to Rust is that it is very strict and so the flexibility of C is lost. If it is an upside then it is because certain mistakes are caught at compile time rather than crash the program at run time.

I have written some sample code that looks like the beginning of a chess program. Well I hope it is anyway. It compiles without warning or errors and does what it is supposed to do. So this will be session one. We can talk about what should be done better. For example Rust seems to abhor global variables so if a function needs to modify global type variables then they must(?) be transferred by a mutable reference. So the first change to this code may be to put globals into a structure and just pass a mutable reference to the structure.

In the next session I will break what we already have up into files/modules known in Rust as crates. Therefore Cargo is necessary if you want to work with crates.

Here is the first sessions code:

Code: Select all

fn main() {
  let command = 1u; // command is not mutable and is unsigned int
  let analyze = 2u;
  let compute = 3u;
  let mut run = true; // run is mutable and is boolean 
  let mut computer = command;
  let mut function = 0u;
  let mut iteration = 0u;
  initializef(&mut function, &mut computer); I like capitalized functions, not Rust
  while run {
    if computer == compute {computef(&mut function, &mut computer);}
    if computer == analyze {analyzef(&mut function, &mut computer);}
    if computer == command {commandf(&mut function, &mut computer, &mut run);}
    iteration += 1;
    println!("This is while iteration {}", iteration);
  }
  println!("End of program");
}

fn initializef(f: &mut uint, c: &mut uint) {
  println!("function is Initialize {} computer = {}", *f, *c);
  *f = 1u;
  *c = 2u;
}

fn commandf(f: &mut uint, c: &mut uint, r: &mut bool) {
  println!("function is Command {} computer = {}", *f, *c);
  *r = false;
}

fn analyzef (f: &mut uint, c: &mut uint) {
  println!("function is Analyze {} computer = {}", *f, *c);
  *f = 2u;
  *c = 3u;
}

fn computef (f: &mut uint, c: &mut uint) {
  println!("function is Compute {} computer = {}", *f, *c);
  *f = 3u;
  *c = 1u;
}
Is this interesting enough to proceed? Let me know what you think.
I hate if statements. Pawns demand if statements. Therefore I hate pawns.

zullil
Posts: 5668
Joined: Mon Jan 08, 2007 11:31 pm
Location: PA USA
Full name: Louis Zulli

Re: Learning to program in RUST, together

Post by zullil » Mon Dec 29, 2014 11:53 am

Michael Sherwin wrote:For those that want to investigate this new programming language let's begin. I downloaded RUSTC the Rust compiler, Cargo the Rust project manager, the Atom programming editor and a Rust package for atom. Somehow I got it all working.

Rust would seem to have quite a few advantages for chess programming like speed, data safety and maybe simpler SMP with race condition safety. And other advantages. You can research that for yourselves.

The downside (or another upside) to Rust is that it is very strict and so the flexibility of C is lost. If it is an upside then it is because certain mistakes are caught at compile time rather than crash the program at run time.

I have written some sample code that looks like the beginning of a chess program. Well I hope it is anyway. It compiles without warning or errors and does what it is supposed to do. So this will be session one. We can talk about what should be done better. For example Rust seems to abhor global variables so if a function needs to modify global type variables then they must(?) be transferred by a mutable reference. So the first change to this code may be to put globals into a structure and just pass a mutable reference to the structure.

In the next session I will break what we already have up into files/modules known in Rust as crates. Therefore Cargo is necessary if you want to work with crates.

Here is the first sessions code:

Code: Select all

fn main() {
  let command = 1u; // command is not mutable and is unsigned int
  let analyze = 2u;
  let compute = 3u;
  let mut run = true; // run is mutable and is boolean 
  let mut computer = command;
  let mut function = 0u;
  let mut iteration = 0u;
  initializef(&mut function, &mut computer); I like capitalized functions, not Rust
  while run {
    if computer == compute {computef(&mut function, &mut computer);}
    if computer == analyze {analyzef(&mut function, &mut computer);}
    if computer == command {commandf(&mut function, &mut computer, &mut run);}
    iteration += 1;
    println!("This is while iteration {}", iteration);
  }
  println!("End of program");
}

fn initializef(f: &mut uint, c: &mut uint) {
  println!("function is Initialize {} computer = {}", *f, *c);
  *f = 1u;
  *c = 2u;
}

fn commandf(f: &mut uint, c: &mut uint, r: &mut bool) {
  println!("function is Command {} computer = {}", *f, *c);
  *r = false;
}

fn analyzef (f: &mut uint, c: &mut uint) {
  println!("function is Analyze {} computer = {}", *f, *c);
  *f = 2u;
  *c = 3u;
}

fn computef (f: &mut uint, c: &mut uint) {
  println!("function is Compute {} computer = {}", *f, *c);
  *f = 3u;
  *c = 1u;
}
Is this interesting enough to proceed? Let me know what you think.
Have you looked at Go? It seems to offer some of the same features. I seem to recall Don Dailey expressing interest in Go for chess programming.


Michael Sherwin
Posts: 3041
Joined: Fri May 26, 2006 1:00 am
Location: WY, USA
Full name: Michael Sherwin

Re: Learning to program in RUST, together

Post by Michael Sherwin » Mon Dec 29, 2014 7:53 pm

I looked at Go and I would rather just use C. Rust though seems like it might be a language that can replace C, at least for me.

Also in benchmarks that I have seen Rust runs faster than Go. In some benchmarks Rust runs faster than C.
I hate if statements. Pawns demand if statements. Therefore I hate pawns.

Michael Sherwin
Posts: 3041
Joined: Fri May 26, 2006 1:00 am
Location: WY, USA
Full name: Michael Sherwin

Re: Learning to program in RUST, together

Post by Michael Sherwin » Mon Dec 29, 2014 7:59 pm

Hmm, well, okay I guess that makes this topic too little too late.
I hate if statements. Pawns demand if statements. Therefore I hate pawns.

vincent
Posts: 31
Joined: Tue Jan 19, 2010 7:38 am
Location: Brittany, France
Contact:

Re: Learning to program in RUST, together

Post by vincent » Mon Dec 29, 2014 9:05 pm

Michael Sherwin wrote:
Hmm, well, okay I guess that makes this topic too little too late.
On the contrary, this is the perfect time!

It's funny, I also started to write a chess engine[1] in Rust a few days ago! I was benchmarking Go and Rust (two languages with a lot of hype) against C with a naive prime number algorithm and found out that Rust was a little faster than C on my laptop with this specific code! So I naturally thought that I could try to write another engine[2] from scratch with it (and with bitboard instead of 0x88 this time).

So far I'm reading about magic bitboard move generation while playing with Rust and the language is very interesting and pleasant to use. The commands "cargo test" and "cargo bench" to run unit tests and micro benchmarks without third party libraries seem perfect for what we do.

But Rust is not 1.0 yet, it's still rapidly evolving (it's recommended to use the nightly build of the compiler for instance) but that's a good opportunity to also learn about language design and implementation.

1: https://github.com/vinc/littlewing
2: https://github.com/vinc/purplehaze

Michael Sherwin
Posts: 3041
Joined: Fri May 26, 2006 1:00 am
Location: WY, USA
Full name: Michael Sherwin

Re: Learning to program in RUST, together

Post by Michael Sherwin » Wed Jan 07, 2015 7:03 am

The "code by example" pages give examples for one type of scope situation and when I try to use basically the same syntax for another scope situation it wont work. And in other situations it seems logical that the same syntax should work-- it doesn't. So I had to look for examples of similar design and/or features and then deduce the syntax by combining ideas. So to get this up and running without warnings or errors I went around the mary_go_round a few dozen times. Very frustrating and time consuming.

A couple examples gave me the idea that structures could be accessed globally with out passing an address. I could not get that to work. Also the syntax using pointers is different from C. I tried putting the structures into a module definition in the same file but that complicated matters. I'll leave that for next time.

Anyway this is doing what it is designed to do. However, if anyone thinks that I am missing the mark in design or language features please feel free to suggest alternatives.

Code: Select all

struct G {
  command:  uint,
  analyze:  uint,
  compute:  uint,
  run:      bool,
  computer: uint,
  function: uint,
}

fn main() {
  let mut g: G = G { // if structure G is in a module the syntax is way different
    command:  1,
    analyze:  2,
    compute:  3,
    run:      true,
    computer: 1,
    function: 0
  };
  let mut iteration = 0u;
  initializef(&mut g);
  while g.run {
    if g.computer == g.compute {computef(&mut g);}
    if g.computer == g.analyze {analyzef(&mut g);}
    if g.computer == g.command {commandf(&mut g);}
    iteration += 1;
    println!("This was while iteration {}", iteration);
  }
  println!("End of program");
}

fn initializef(g: &mut G) {
  println!("function is Initialize {} computer = {}", g.function, g.computer);
  g.function = 1;
  g.computer = g.analyze;
}

fn commandf(g: &mut G) {
  println!("function is Command {} computer = {}", g.function, g.computer);
  g.run = false;
}

fn analyzef (g: &mut G) {
  println!("function is Analyze {} computer = {}", g.function, g.computer);
  g.function = 2;
  g.computer = g.compute;
}

fn computef (g: &mut G) {
  println!("function is Compute {} computer = {}", g.function, g.computer);
  g.function = 3;
  g.computer = g.command;
}
I hate if statements. Pawns demand if statements. Therefore I hate pawns.

Michael Sherwin
Posts: 3041
Joined: Fri May 26, 2006 1:00 am
Location: WY, USA
Full name: Michael Sherwin

Re: Learning to program in RUST, together

Post by Michael Sherwin » Wed Jan 07, 2015 1:49 pm

I'm up early working on this. Discovered the static keyword for creating global constants. I put them in a module definition and because of that I have to access them using the module name, like m::COMPUTE. Now I read that an external crate does not have to contain a module. So the next order of business will be to create an external crate/file and see if I need a module definition or not. Here is the code as it stands now.

note: Everything in a module including the module itself is private by default. That is why all those pub's are needed.

Code: Select all

pub mod m {
  pub static COMMAND: uint = 1;
  pub static ANALYZE: uint = 2;
  pub static COMPUTE: uint = 3;
  pub static PONDER:  uint = 4;

  #[allow(missing_copy_implementations)]
  pub struct G {
    pub run:      bool,
    pub computer: uint,
    pub function: uint,
  }
}

fn main() {
  let mut g = m::G {
    run:      true,
    computer: 1,
    function: 0
  };
  let mut iteration = 0u;
  initializef(&mut g);
  while g.run {
    if g.computer == m::COMPUTE {computef(&mut g);}
    if g.computer == m::ANALYZE {analyzef(&mut g);}
    if g.computer == m::PONDER  {ponderf (&mut g);}
    if g.computer == m::COMMAND {commandf(&mut g);}
    iteration += 1;
    println!("This was while iteration {}", iteration);
  }
  println!("End of program");
}

fn initializef(g: &mut m::G) {
  println!("function is Initialize {} computer = {}", g.function, g.computer);
  g.function = 1;
  g.computer = m::ANALYZE;
}

fn ponderf(g: &mut m::G) {
  println!("function is Ponder {} computer = {}", g.function, g.computer);
  g.function = 4;
  g.computer = m::COMMAND;
}

fn commandf(g: &mut m::G) {
  println!("function is Command {} computer = {}", g.function, g.computer);
  g.run = false;
}

fn analyzef (g: &mut m::G) {
  println!("function is Analyze {} computer = {}", g.function, g.computer);
  g.function = 2;
  g.computer = m::COMPUTE;
}

fn computef (g: &mut m::G) {
  println!("function is Compute {} computer = {}", g.function, g.computer);
  g.function = 3;
  g.computer = m::PONDER;
}
I hate if statements. Pawns demand if statements. Therefore I hate pawns.

Michael Sherwin
Posts: 3041
Joined: Fri May 26, 2006 1:00 am
Location: WY, USA
Full name: Michael Sherwin

Re: Learning to program in RUST, together

Post by Michael Sherwin » Wed Jan 07, 2015 4:31 pm

I tried to put the module definition into a file, put the file in the right directory format and run 'cargo new mycrate'. Cargo never saw mycrate. I have no clue what I am doing wrong. I guess I'm done for now until I can get this figured out. Maybe if I can find some better examples.
I hate if statements. Pawns demand if statements. Therefore I hate pawns.

Michael Sherwin
Posts: 3041
Joined: Fri May 26, 2006 1:00 am
Location: WY, USA
Full name: Michael Sherwin

Re: Learning to program in RUST, together

Post by Michael Sherwin » Thu Jan 08, 2015 5:20 am

I deleted the project and rebuilt it in the order that an example did it. It seems like a strange order. First I built the library crate that ends up with the name of my program. Like this:

cd c:\
cargo new SkyNet

That creates a SkyNet directory with a src directory under it that contains the file lib.rs. Then I put the module definition into that file. And built like this:

cd SkyNet
cargo build

The crate was built and placed in the target directory.
Then I created the main.rs file and placed it in the src directory. And built it.

cargo build

It built SkyNet.exe and put it in the target directory.

c:\SkyNet\src\lib.rs

Code: Select all

pub mod m {
  pub static COMMAND: uint = 1;
  pub static ANALYZE: uint = 2;
  pub static COMPUTE: uint = 3;
  pub static PONDER:  uint = 4;

  #[allow(missing_copy_implementations)]
  pub struct G {
    pub run:      bool,
    pub computer: uint,
    pub function: uint,
  }
} 

Notice that now the crate name has to be used also and is case sensitive.

c:\SkyNet\src\main.rs

Code: Select all

extern crate SkyNet;

fn main() {
  let mut g = SkyNet::m::G {
    run:      true,
    computer: 1,
    function: 0
  };
  let mut iteration = 0u;
  initializef(&mut g);
  while g.run {
    if g.computer == SkyNet::m::COMPUTE {computef(&mut g);}
    if g.computer == SkyNet::m::ANALYZE {analyzef(&mut g);}
    if g.computer == SkyNet::m::PONDER  {ponderf (&mut g);}
    if g.computer == SkyNet::m::COMMAND {commandf(&mut g);}
    iteration += 1;
    println!("This was while iteration {}", iteration);
  }
  println!("End of program");
}

fn initializef(g: &mut SkyNet::m::G) {
  println!("function is Initialize {} computer = {}", g.function, g.computer);
  g.function = 1;
  g.computer = SkyNet::m::ANALYZE;
}

fn ponderf(g: &mut SkyNet::m::G) {
  println!("function is Ponder {} computer = {}", g.function, g.computer);
  g.function = 4;
  g.computer = SkyNet::m::COMMAND;
}

fn commandf(g: &mut SkyNet::m::G) {
  println!("function is Command {} computer = {}", g.function, g.computer);
  g.run = false;
}

fn analyzef (g: &mut SkyNet::m::G) {
  println!("function is Analyze {} computer = {}", g.function, g.computer);
  g.function = 2;
  g.computer = SkyNet::m::COMPUTE;
}

fn computef (g: &mut SkyNet::m::G) {
  println!("function is Compute {} computer = {}", g.function, g.computer);
  g.function = 3;
  g.computer = SkyNet::m::PONDER;
}
I hate if statements. Pawns demand if statements. Therefore I hate pawns.

Post Reply