Creating The Tiles From Code¶
This step places the game tiles randomly.
Change the main
function and includes in src/main.cpp
to the following:
#include <random> // Added
int main()
{
auto main_window = MainWindow::create();
auto old_tiles = main_window->get_memory_tiles();
std::vector<TileData> new_tiles;
new_tiles.reserve(old_tiles->row_count() * 2);
for (int i = 0; i < old_tiles->row_count(); ++i) {
new_tiles.push_back(*old_tiles->row_data(i));
new_tiles.push_back(*old_tiles->row_data(i));
}
std::default_random_engine rng {};
std::shuffle(new_tiles.begin(), new_tiles.end(), rng);
auto tiles_model = std::make_shared<slint::VectorModel<TileData>>(new_tiles);
main_window->set_memory_tiles(tiles_model);
main_window->run();
}
The code takes the list of tiles, duplicates it, and shuffles it, accessing the memory_tiles
property through the C++ code.
For each top-level property, Slint generates a getter and a setter function. In this case get_memory_tiles
and set_memory_tiles
.
Since memory_tiles
is a Slint array, it’s represented as a std::shared_ptr<slint::Model>
.
You can’t change the model generated by Slint, but you can extract the tiles from it and put them
in a slint::VectorModel
which inherits from Model
.
VectorModel
lets you make changes and you can use it to replace the static generated model.
Change main.js
to the following:
import * as slint from "slint-ui";
let ui = slint.loadFile("./ui/app-window.slint");
let mainWindow = new ui.MainWindow();
let initial_tiles = mainWindow.memory_tiles;
let tiles = initial_tiles.concat(initial_tiles.map((tile) => Object.assign({}, tile)));
for (let i = tiles.length - 1; i > 0; i--) {
const j = Math.floor(Math.random() * i);
[tiles[i], tiles[j]] = [tiles[j], tiles[i]];
}
let model = new slint.ArrayModel(tiles);
mainWindow.memory_tiles = model;
await mainWindow.run();
The code takes the list of tiles, duplicates it, and shuffles it, accessing the memory_tiles
property through the JavaScript code.
As memory_tiles
is an array, it’s represented as a JavaScript Array
.
You can’t change the model generated by Slint, but you can extract the tiles from it and put them
in a slint.ArrayModel
which implements the Model
interface.
ArrayModel
allows you to make changes and you can use it to replace the static generated model.
The code uses the rand
dependency for the randomization. Add it to the Cargo.toml
file using the cargo
command.
cargo add rand@0.8
Change the main function to the following:
fn main() {
use slint::Model;
let main_window = MainWindow::new().unwrap();
// Fetch the tiles from the model
let mut tiles: Vec<TileData> = main_window.get_memory_tiles().iter().collect();
// Duplicate them to ensure that we have pairs
tiles.extend(tiles.clone());
// Randomly mix the tiles
use rand::seq::SliceRandom;
let mut rng = rand::thread_rng();
tiles.shuffle(&mut rng);
// Assign the shuffled Vec to the model property
let tiles_model = std::rc::Rc::new(slint::VecModel::from(tiles));
main_window.set_memory_tiles(tiles_model.clone().into());
main_window.run().unwrap();
}
The code takes the list of tiles, duplicates it, and shuffles it, accessing the memory_tiles
property through the Rust code.
For each top-level property,
Slint generates a getter and a setter function. In this case get_memory_tiles
and set_memory_tiles
.
Since memory_tiles
is a Slint array represented as a Rc<dyn slint::Model>
.
You can’t change the model generated by Slint, but you can extract the tiles from it and put them
in a VecModel
which implements the Model
trait.
VecModel
lets you make changes and you can use it to replace the static generated model.
Running this code opens a window that now shows a 4 by 4 grid of rectangles, which show or hide the icons when a player clicks on them.
There’s one last aspect missing now, the rules for the game.