15 puzzle game: Difference between revisions

Content added Content deleted
(added Arturo implementation)
Line 11,364: Line 11,364:
{{libheader|rand}}
{{libheader|rand}}
<syntaxhighlight lang="rust">extern crate rand;
<syntaxhighlight lang="rust">extern crate rand;

use std::collections::HashMap;
use std::collections::HashMap;
use std::fmt;
use std::fmt;

use rand::Rng;
use rand::seq::SliceRandom;
use rand::seq::SliceRandom;
use rand::Rng;

#[derive(Copy, Clone, PartialEq, Debug)]
#[derive(Copy, Clone, PartialEq, Debug)]
enum Cell {
enum Cell {
Line 11,376: Line 11,376:
Empty,
Empty,
}
}

#[derive(Eq, PartialEq, Hash, Debug)]
#[derive(Eq, PartialEq, Hash, Debug)]
enum Direction {
enum Direction {
Line 11,384: Line 11,384:
Right,
Right,
}
}

enum Action {
enum Action {
Move(Direction),
Move(Direction),
Quit,
Quit,
}
}

type Board = [Cell; 16];
type Board = [Cell; 16];
const EMPTY: Board = [Cell::Empty; 16];
const EMPTY: Board = [Cell::Empty; 16];

struct P15 {
struct P15 {
board: Board,
board: Board,
}
}

impl P15 {
impl P15 {
fn new() -> Self {
fn new() -> Self {
Line 11,403: Line 11,403:
*cell = Cell::Card(i);
*cell = Cell::Card(i);
}
}

let mut rng = rand::thread_rng();
let mut rng = rand::thread_rng();

board.shuffle(&mut rng);
board.shuffle(&mut rng);
if !Self::is_valid(board) {
if !Self::is_valid(board) {
// random swap
// random swap
let i = rng.gen_range(0, 16);
let i = rng.gen_range(0..16);
let mut j = rng.gen_range(0, 16);
let mut j = rng.gen_range(0..16);
while j == i {
while j == i {
j = rng.gen_range(0, 16);
j = rng.gen_range(0..16);
}
}
board.swap(i, j);
board.swap(i, j);
}
}

Self { board }
Self { board }
}
}

fn is_valid(mut board: Board) -> bool {
fn is_valid(mut board: Board) -> bool {
// TODO: optimize
// TODO: optimize
let mut permutations = 0;
let mut permutations = 0;

let pos = board.iter().position(|&cell| cell == Cell::Empty).unwrap();
let pos = board.iter().position(|&cell| cell == Cell::Empty).unwrap();

if pos != 15 {
if pos != 15 {
board.swap(pos, 15);
board.swap(pos, 15);
permutations += 1;
permutations += 1;
}
}

for i in 1..16 {
for i in 1..16 {
let pos = board
let pos = board
Line 11,439: Line 11,439:
})
})
.unwrap();
.unwrap();

if pos + 1 != i {
if pos + 1 != i {
board.swap(pos, i - 1);
board.swap(pos, i - 1);
Line 11,445: Line 11,445:
}
}
}
}

permutations % 2 == 0
permutations % 2 == 0
}
}

fn get_empty_position(&self) -> usize {
fn get_empty_position(&self) -> usize {
self.board.iter().position(|&c| c == Cell::Empty).unwrap()
self.board.iter().position(|&c| c == Cell::Empty).unwrap()
}
}

fn get_moves(&self) -> HashMap<Direction, Cell> {
fn get_moves(&self) -> HashMap<Direction, Cell> {
let mut moves = HashMap::new();
let mut moves = HashMap::new();
let i = self.get_empty_position();
let i = self.get_empty_position();

if i > 3 {
if i > 3 {
moves.insert(Direction::Up, self.board[i - 4]);
moves.insert(Direction::Up, self.board[i - 4]);
Line 11,471: Line 11,471:
moves
moves
}
}

fn play(&mut self, direction: &Direction) {
fn play(&mut self, direction: &Direction) {
let i = self.get_empty_position();
let i = self.get_empty_position();
Line 11,482: Line 11,482:
};
};
}
}

fn is_complete(&self) -> bool {
fn is_complete(&self) -> bool {
self.board.iter().enumerate().all(|(i, &cell)| match cell {
self.board.iter().enumerate().all(|(i, &cell)| match cell {
Line 11,490: Line 11,490:
}
}
}
}

impl fmt::Display for P15 {
impl fmt::Display for P15 {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
r#try!(write!(f, "+----+----+----+----+\n"));
(writeln!(f, "+----+----+----+----+"))?;
for (i, &cell) in self.board.iter().enumerate() {
for (i, &cell) in self.board.iter().enumerate() {
match cell {
match cell {
Cell::Card(value) => r#try!(write!(f, "| {:2} ", value)),
Cell::Card(value) => (write!(f, "| {value:2} "))?,
Cell::Empty => r#try!(write!(f, "| ")),
Cell::Empty => (write!(f, "| "))?,
}
}

if i % 4 == 3 {
if i % 4 == 3 {
r#try!(write!(f, "|\n"));
(writeln!(f, "|"))?;
r#try!(write!(f, "+----+----+----+----+\n"));
(writeln!(f, "+----+----+----+----+"))?;
}
}
}
}
Line 11,508: Line 11,508:
}
}
}
}

fn main() {
fn main() {
let mut p15 = P15::new();
let mut p15 = P15::new();

for turns in 1.. {
for turns in 1.. {
println!("{}", p15);
println!("{p15}");
match ask_action(&p15.get_moves()) {
match ask_action(&p15.get_moves()) {
Action::Move(direction) => {
Action::Move(direction) => {
Line 11,519: Line 11,519:
}
}
Action::Quit => {
Action::Quit => {
println!("Bye !");
println!("Bye !");
break;
break;
}
}
}
}

if p15.is_complete() {
if p15.is_complete() {
println!("Well done ! You won in {} turns", turns);
println!("Well done ! You won in {turns} turns");
break;
break;
}
}
}
}
}
}

fn ask_action(moves: &HashMap<Direction, Cell>) -> Action {
fn ask_action(moves: &HashMap<Direction, Cell>) -> Action {
use std::io::{self, Write};
use std::io::{self, Write};
use Action::*;
use Action::*;
use Direction::*;
use Direction::*;

println!("Possible moves:");
println!("Possible moves:");

if let Some(&Cell::Card(value)) = moves.get(&Up) {
if let Some(&Cell::Card(value)) = moves.get(&Up) {
println!("\tU) {}", value);
println!("\tU) {value}");
}
}
if let Some(&Cell::Card(value)) = moves.get(&Left) {
if let Some(&Cell::Card(value)) = moves.get(&Left) {
println!("\tL) {}", value);
println!("\tL) {value}");
}
}
if let Some(&Cell::Card(value)) = moves.get(&Right) {
if let Some(&Cell::Card(value)) = moves.get(&Right) {
println!("\tR) {}", value);
println!("\tR) {value}");
}
}
if let Some(&Cell::Card(value)) = moves.get(&Down) {
if let Some(&Cell::Card(value)) = moves.get(&Down) {
println!("\tD) {}", value);
println!("\tD) {value}");
}
}
println!("\tQ) Quit");
println!("\tQ) Quit");
print!("Choose your move : ");
print!("Choose your move : ");
io::stdout().flush().unwrap();
io::stdout().flush().unwrap();

let mut action = String::new();
let mut action = String::new();
io::stdin().read_line(&mut action).expect("read error");
io::stdin().read_line(&mut action).expect("read error");
Line 11,563: Line 11,563:
"Q" => Quit,
"Q" => Quit,
_ => {
_ => {
println!("Unknown action: {}", action);
println!("Unknown action: {action}");
ask_action(moves)
ask_action(moves)
}
}