15 puzzle game: Difference between revisions

Content added Content deleted
(added Arturo implementation)
Line 11,364:
{{libheader|rand}}
<syntaxhighlight lang="rust">extern crate rand;
 
use std::collections::HashMap;
use std::fmt;
 
use rand::Rng;
use rand::seq::SliceRandom;
use rand::Rng;
 
#[derive(Copy, Clone, PartialEq, Debug)]
enum Cell {
Line 11,376:
Empty,
}
 
#[derive(Eq, PartialEq, Hash, Debug)]
enum Direction {
Line 11,384:
Right,
}
 
enum Action {
Move(Direction),
Quit,
}
 
type Board = [Cell; 16];
const EMPTY: Board = [Cell::Empty; 16];
 
struct P15 {
board: Board,
}
 
impl P15 {
fn new() -> Self {
Line 11,403:
*cell = Cell::Card(i);
}
 
let mut rng = rand::thread_rng();
 
board.shuffle(&mut rng);
if !Self::is_valid(board) {
// random swap
let i = rng.gen_range(0, ..16);
let mut j = rng.gen_range(0, ..16);
while j == i {
j = rng.gen_range(0, ..16);
}
board.swap(i, j);
}
 
Self { board }
}
 
fn is_valid(mut board: Board) -> bool {
// TODO: optimize
let mut permutations = 0;
 
let pos = board.iter().position(|&cell| cell == Cell::Empty).unwrap();
 
if pos != 15 {
board.swap(pos, 15);
permutations += 1;
}
 
for i in 1..16 {
let pos = board
Line 11,439:
})
.unwrap();
 
if pos + 1 != i {
board.swap(pos, i - 1);
Line 11,445:
}
}
 
permutations % 2 == 0
}
 
fn get_empty_position(&self) -> usize {
self.board.iter().position(|&c| c == Cell::Empty).unwrap()
}
 
fn get_moves(&self) -> HashMap<Direction, Cell> {
let mut moves = HashMap::new();
let i = self.get_empty_position();
 
if i > 3 {
moves.insert(Direction::Up, self.board[i - 4]);
Line 11,471:
moves
}
 
fn play(&mut self, direction: &Direction) {
let i = self.get_empty_position();
Line 11,482:
};
}
 
fn is_complete(&self) -> bool {
self.board.iter().enumerate().all(|(i, &cell)| match cell {
Line 11,490:
}
}
 
impl fmt::Display for P15 {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
r#try!(writewriteln!(f, "+----+----+----+----+\n"))?;
for (i, &cell) in self.board.iter().enumerate() {
match cell {
Cell::Card(value) => r#try!(write!(f, "| {value:2} ", value))?,
Cell::Empty => r#try!(write!(f, "| "))?,
}
 
if i % 4 == 3 {
r#try!(writewriteln!(f, "|\n"))?;
r#try!(writewriteln!(f, "+----+----+----+----+\n"))?;
}
}
Line 11,508:
}
}
 
fn main() {
let mut p15 = P15::new();
 
for turns in 1.. {
println!("{p15}", p15);
match ask_action(&p15.get_moves()) {
Action::Move(direction) => {
Line 11,519:
}
Action::Quit => {
println!("Bye  !");
break;
}
}
 
if p15.is_complete() {
println!("Well done  ! You won in {turns} turns", turns);
break;
}
}
}
 
fn ask_action(moves: &HashMap<Direction, Cell>) -> Action {
use std::io::{self, Write};
use Action::*;
use Direction::*;
 
println!("Possible moves:");
 
if let Some(&Cell::Card(value)) = moves.get(&Up) {
println!("\tU) {value}", value);
}
if let Some(&Cell::Card(value)) = moves.get(&Left) {
println!("\tL) {value}", value);
}
if let Some(&Cell::Card(value)) = moves.get(&Right) {
println!("\tR) {value}", value);
}
if let Some(&Cell::Card(value)) = moves.get(&Down) {
println!("\tD) {value}", value);
}
println!("\tQ) Quit");
print!("Choose your move  : ");
io::stdout().flush().unwrap();
 
let mut action = String::new();
io::stdin().read_line(&mut action).expect("read error");
Line 11,563:
"Q" => Quit,
_ => {
println!("Unknown action: {action}", action);
ask_action(moves)
}