Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion DESCRIPTION
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ Encoding: UTF-8
Package: ppcli
Type: Package
Title: Plaintext Board Game Visualizations
Version: 0.1.1
Version: 0.2.0-1
Authors@R: c(person("Trevor L.", "Davis", role=c("aut", "cre"),
email="trevor.l.davis@gmail.com",
comment = c(ORCID = "0000-0001-6341-4639")))
Expand All @@ -24,6 +24,7 @@ Suggests:
ppdf,
testthat,
tibble,
withr
Remotes: piecepackr/ppdf
Roxygen: list(markdown = TRUE)
RoxygenNote: 7.3.1
Expand Down
14 changes: 13 additions & 1 deletion NEWS.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,16 @@
ppcli 0.2.0 (development)
=========================

* `cat_piece()` and `str_piece()` adds support for the following game pieces (#4):

+ "alquerque" bit and board pieces.
+ "marbles" bit and board pieces.

- However we currently do not distinguish between the nine marble bit ranks.

* "white" `go` and `checkers` bits should now render the same
whether `piece_side` is `"bit_back"` or `"bit_face"`.

ppcli 0.1.1
===========

Expand All @@ -9,4 +22,3 @@ ppcli 0.1.1
+ It is an extraction and refinement of ``ppgames::cat_piece()``.

* ``str_piece()`` computes the character vector of Unicode plaintext boardgame diagrams (#1).

133 changes: 98 additions & 35 deletions R/str_piece.r
Original file line number Diff line number Diff line change
Expand Up @@ -158,8 +158,8 @@ get_style_rs <- function(style, big = FALSE) {
playing_cards_expansion = piecepack_ranks,
dual_piecepacks_expansion = piecepack_ranks,
subpack = piecepack_ranks,
checkers1 = rep("\u26c2", 6),
checkers2 = rep("\u26c2", 6),
checkers1 = rep_len("\u26c2", 6L),
checkers2 = rep_len("\u26c2", 6L),
chess1 = c("\u265f", "\u265e", "\u265d", "\u265c", "\u265b", "\u265a"),
chess2 = c("\u265f", "\u265e", "\u265d", "\u265c", "\u265b", "\u265a"),
dice = dominoes_ranks[-1],
Expand All @@ -171,8 +171,10 @@ get_style_rs <- function(style, big = FALSE) {
dominoes_red = dominoes_ranks,
dominoes_white = dominoes_ranks,
dominoes_yellow = dominoes_ranks,
icehouse_pieces = rep(" ", 6),
go = rep("\u25cf", 6))
icehouse_pieces = rep(" ", 6L),
alquerque = rep_len("\u25cf", 6L),
go = rep_len("\u25cf", 6L),
marbles = rep_len("\u25cf", 9L))
rs
}

Expand Down Expand Up @@ -204,21 +206,23 @@ get_style_ss <- function(style, big = FALSE) {
playing_cards_expansion = french_suits_black,
dual_piecepacks_expansion = french_suits_white,
subpack = piecepack_suits,
checkers1 = c(rep("\u26c2", 5), "\u26c0"),
checkers2 = c(rep("\u26c2", 5), "\u26c0"),
checkers1 = c(rep_len("\u26c2", 5L), "\u26c0"),
checkers2 = c(rep_len("\u26c2", 5L), "\u26c0"),
chess1 = "",
chess2 = "",
dice = rep(" ", 6),
dice_fudge = rep(" ", 6),
dice = rep_len(" ", 6L),
dice_fudge = rep_len(" ", 6L),
dominoes = dominoes_ranks,
dominoes_black = dominoes_ranks,
dominoes_blue = dominoes_ranks,
dominoes_green = dominoes_ranks,
dominoes_red = dominoes_ranks,
dominoes_white = dominoes_ranks,
dominoes_yellow = dominoes_ranks,
go = c(rep("\u25cf", 5), "\u25cb"),
icehouse_pieces = c(rep("\u25b2", 5), "\u25b3"))
alquerque = c(rep_len("\u25cf", 5L), "\u25cb"),
go = c(rep_len("\u25cf", 5L), "\u25cb"),
marbles = c(rep_len("\u25cf", 5L), "\u25cb"),
icehouse_pieces = c(rep_len("\u25b2", 5L), "\u25b3"))
ss
}

Expand All @@ -240,24 +244,26 @@ get_style_fg <- function(style) {
checkers2 = suit_colors,
dice = suit_colors,
dice_fudge = suit_colors,
dominoes = rep("black", 7L),
dominoes_black = rep(dice_colors[2L], 7L),
dominoes_blue = rep(dice_colors[4L], 7L),
dominoes_green = rep(dice_colors[3L], 7L),
dominoes_red = rep(dice_colors[1L], 7L),
dominoes_white = rep(dice_colors[6L], 7L),
dominoes_yellow = rep(dice_colors[5L], 7L),
dominoes = rep_len("black", 7L),
dominoes_black = rep_len(dice_colors[2L], 7L),
dominoes_blue = rep_len(dice_colors[4L], 7L),
dominoes_green = rep_len(dice_colors[3L], 7L),
dominoes_red = rep_len(dice_colors[1L], 7L),
dominoes_white = rep_len(dice_colors[6L], 7L),
dominoes_yellow = rep_len(dice_colors[5L], 7L),
icehouse_pieces = dice_colors,
go = suit_colors)
alquerque = suit_colors,
go = suit_colors,
marbles = suit_colors)
fg
}

color_text <- function(cm, color) {
if (color == "html") # always colorize if we'll be converting to html
rlang::local_options(cli.num_colors = 256L)
if (!isFALSE(color)) {
for (rr in seq(nrow(cm$char))) {
for (cc in seq(ncol(cm$char))) {
for (rr in seq.int(nrow(cm$char))) {
for (cc in seq.int(ncol(cm$char))) {
fg <- col_cli(cm$fg[rr, cc])
colorize <- cli::combine_ansi_styles(fg, cli::bg_br_white)
cm$char[rr, cc] <- colorize(cm$char[rr, cc])
Expand Down Expand Up @@ -301,12 +307,31 @@ clean_df <- function(df) {
df$cfg <- ifelse(is.na(df$cfg), "piecepack", df$cfg)
if (!hasName(df, "rank")) df$rank <- NA_integer_
df$rank <- ifelse(is.na(df$rank), 1L, df$rank)

# Adjust board sizes
# checkers/chess boards rank is number of cells
df$rank <- ifelse(df$rank == 1L & str_detect(df$piece_side, "^board") & str_detect(df$cfg, "[12]$"), 8L, df$rank)
df$rank <- ifelse(df$rank == 1L & str_detect(df$piece_side, "^board") & str_detect(df$cfg, "[12]$"),
8L,
df$rank)
# go board rank is number of lines
df$rank <- ifelse(str_detect(df$piece_side, "^board") & df$cfg == "go",
ifelse(df$rank == 1L, 18, df$rank - 1),
ifelse(df$rank == 1L, 18L, df$rank - 1),
df$rank)
# marbles board rank is number of holes
df$rank <- ifelse(str_detect(df$piece_side, "^board") & df$cfg == "marbles",
ifelse(df$rank == 1L, 4L, df$rank),
df$rank)
# alquerque board always has four "cells"
df$rank <- ifelse(str_detect(df$piece_side, "^board") & df$cfg == "alquerque",
4L,
df$rank)

# Checkers pieces, go stones and marbles should be "bit_back"
bit_back_cfgs <- c("alquerque", "checkers1", "checkers2", "go", "marbles")
df$piece_side <- ifelse(df$piece_side == "bit_face" & df$cfg %in% bit_back_cfgs,
"bit_back",
df$piece_side)

if (!hasName(df, "suit")) df$suit <- NA_integer_
df$suit <- ifelse(is.na(df$suit), 1L, df$suit)
if (!hasName(df, "angle")) df$angle <- NA_real_
Expand Down Expand Up @@ -377,8 +402,8 @@ add_piece <- function(cm, piece_side, suit, rank, x, y, angle, cfg, reorient = "
tile_back = add_tile_back(cm, x, y, angle, cfg, style),
bit_back = add_bit_back(cm, ss, x, y, fg),
bit_face = add_bit_face(cm, rs, x, y, fg),
board_back = add_board(cm, x, y, cell * rank, cell * rank, cell, style),
board_face = add_board(cm, x, y, cell * rank, cell * rank, cell, style),
board_back = add_board(cm, x, y, cell * rank, cell * rank, cell, cfg, style),
board_face = add_board(cm, x, y, cell * rank, cell * rank, cell, cfg, style),
matchstick_back = add_matchstick_face(cm, x, y, angle, fg, rank),
matchstick_face = add_matchstick_face(cm, x, y, angle, fg, rank),
pyramid_top = add_pyramid_top(cm, ss, x, y, angle, fg, rank),
Expand Down Expand Up @@ -670,34 +695,72 @@ add_tile_face_piecepack <- function(cm, ss, rs, x, y, angle, fg, style) {
}
cm
}
add_board <- function(cm, x, y, width = 8, height = 8, cell = 1, style = get_style("Unicode")) {

add_board <- function(cm, x, y, width = 8, height = 8, cell = 1,
cfg = "checkers1", style = get_style("Unicode")) {
cm$fg[y+-height:height, x+-width:width] <- "black"
cm <- add_border(cm, x, y, width, height, space = style$space)
cm <- add_gridlines(cm, x, y, width, height, cell)
cm <- switch(cfg,
alquerque = add_alquerque_board(cm, x, y, width, height, cell),
marbles = add_holes(cm, x, y, width, height, cell),
add_gridlines(cm, x, y, width, height, cell)
)
cm
}

add_alquerque_board <- function(cm, x, y, width = 2, height = 2, cell = 1) {
cm <- add_gridlines(cm, x, y, width, height, cell, heavy = FALSE)
xur <- x + rep(c(-3, 1), 2L)
yur <- y + rep(c(-3, 1), each = 2L)
cm$char[xur, yur] <- "\u2571"
xur <- x + rep(c(-1, 3), 2L)
yur <- y + rep(c(-1, 3), each = 2L)
cm$char[xur, yur] <- "\u2571"
xul <- x + rep(c(-3, 1), 2L)
yul <- y + rep(c(-1, 3), each = 2L)
cm$char[xul, yul] <- "\u2572"
xul <- x + rep(c(-1, 3), 2L)
yul <- y + rep(c(-3, 1), each = 2L)
cm$char[xul, yul] <- "\u2572"
cm
}

add_holes <- function(cm, x, y, width = 2, height = 2, cell = 1) {
xgs <- x + seq(cell - width, width - cell, 2 * cell)
ygs <- y + seq(cell - height, height - cell, 2 * cell)
# cm$char[ygs, xgs] <- "\u25ce"
cm$char[ygs, xgs] <- "\u25cc"
cm
}

add_gridlines <- function(cm, x, y, width = 2, height = 2, cell = 1,
has_pua_box_drawing = FALSE) {
has_pua_box_drawing = FALSE, heavy = TRUE) {
# gridlines
xgs <- x + seq(2 * cell - width, width - 2 * cell, 2 * cell)
ygs <- y + seq(2 * cell - height, height - 2 * cell, 2 * cell)
xo <- x + seq(1 - width, width - 1)
yo <- y + seq(1 - height, height - 1)

cm$char[ygs, xo] <- "\u2501" # horizontal lines
cm$char[yo, xgs] <- "\u2503" # vertical lines
cm$char[ygs, xgs] <- "\u254b" # crosses
if (heavy) {
cm$char[ygs, xo] <- "\u2501" # horizontal lines
cm$char[yo, xgs] <- "\u2503" # vertical lines
cm$char[ygs, xgs] <- "\u254b" # crosses
hv <- ifelse(has_pua_box_drawing, 3L, 2L)
} else { # "light"
cm$char[ygs, xo] <- "\u2500" # horizontal lines
cm$char[yo, xgs] <- "\u2502" # vertical lines
cm$char[ygs, xgs] <- "\u253c" # crosses
hv <- 1L
}

# intersection gridlines and border line
hv <- ifelse(has_pua_box_drawing, 3, 2)
for (xg in xgs) {
cm <- add_box_edge(cm, xg, y+height, c(NA, 1, hv, 1)) # top
cm <- add_box_edge(cm, xg, y-height, c(hv, 1, NA, 1)) # bottom
cm <- add_box_edge(cm, xg, y+height, c(NA, 1L, hv, 1L)) # top
cm <- add_box_edge(cm, xg, y-height, c(hv, 1L, NA, 1L)) # bottom
}
for (yg in ygs) {
cm <- add_box_edge(cm, x+width, yg, c(1, NA, 1, hv)) # right
cm <- add_box_edge(cm, x-width, yg, c(1, hv, 1, NA)) # left
cm <- add_box_edge(cm, x+width, yg, c(1L, NA, 1L, hv)) # right
cm <- add_box_edge(cm, x-width, yg, c(1L, hv, 1L, NA)) # left
}
cm
}
Expand Down
70 changes: 70 additions & 0 deletions tests/testthat/_snaps/cat_piece.md
Original file line number Diff line number Diff line change
Expand Up @@ -532,3 +532,73 @@



---

Code
withr::local_seed(42)
dfb <- tibble(piece_side = "board_face", suit = 4L, rank = 4L, cfg = "marbles",
x = 2, y = 2)
dfm <- tibble(piece_side = "bit_face", suit = sample.int(6L, 30L, replace = TRUE),
rank = 9L, cfg = "marbles", x = c(0.5 + rep(0:3, 4L), rep(rep(1:3, 3L)), 0.5 +
rep(1:2, 2L), 2), y = c(0.5 + rep(0:3, each = 4L), rep(1:3, each = 3L), 0.5 +
rep(1:2, each = 2L), 2))
df <- rbind(dfb, dfm)
cat_piece(dfb)
Output
┌───────┐
│◌ ◌ ◌ ◌│
│ │
│◌ ◌ ◌ ◌│
│ │
│◌ ◌ ◌ ◌│
│ │
│◌ ◌ ◌ ◌│
└───────┘
Code
cat_piece(df)
Output
┌───────┐
│○ ● ● ●│
│ ● ● ● │
│● ● ● ●│
│ ● ● ● │
│● ● ● ●│
│ ● ● ● │
│● ● ● ●│
└───────┘

---

Code
dfb <- tibble(piece_side = "board_face", x = 3, y = 3, suit = 3, cfg = "alquerque")
dfs <- tibble(piece_side = "bit_back", x = 1:5, y = 1:5, suit = 1:5, cfg = "alquerque")
df <- rbind(dfb, dfs)
cat_piece(dfb)
Output
┌─┬─┬─┬─┐
│╲│╱│╲│╱│
├─┼─┼─┼─┤
│╱│╲│╱│╲│
├─┼─┼─┼─┤
│╲│╱│╲│╱│
├─┼─┼─┼─┤
│╱│╲│╱│╲│
└─┴─┴─┴─┘


Code
cat_piece(df)
Output

┌─┬─┬─┬─●
│╲│╱│╲│╱│
├─┼─┼─●─┤
│╱│╲│╱│╲│
├─┼─●─┼─┤
│╲│╱│╲│╱│
├─●─┼─┼─┤
│╱│╲│╱│╲│
●─┴─┴─┴─┘



28 changes: 28 additions & 0 deletions tests/testthat/test_cat_piece.r
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ cat_piece <- function(df, ...) ppcli::cat_piece(df, ..., color = FALSE)
test_that("text diagrams", {
skip_if_not_installed("dplyr")
skip_if_not_installed("tibble")
skip_if_not_installed("withr")
library("tibble")

style <- get_style("unicode")
Expand Down Expand Up @@ -165,4 +166,31 @@ test_that("text diagrams", {
df <- dplyr::bind_rows(dfb, dfs)
cat_piece(df)
})

# marbles
expect_snapshot({
withr::local_seed(42)
dfb <- tibble(piece_side = "board_face", suit = 4L, rank = 4L,
cfg ="marbles", x = 2, y = 2)
dfm <- tibble(
piece_side = "bit_face",
suit = sample.int(6L, 30L, replace = TRUE),
rank = 9L,
cfg = "marbles",
x = c(0.5 + rep(0:3, 4L), rep(rep(1:3, 3L)), 0.5 + rep(1:2, 2L), 2),
y = c(0.5 + rep(0:3, each = 4L), rep(1:3, each = 3L), 0.5 + rep(1:2, each = 2L), 2)
)
df <- rbind(dfb, dfm)
cat_piece(dfb)
cat_piece(df)
})

# alquerque
expect_snapshot({
dfb <- tibble(piece_side = "board_face", x= 3, y = 3, suit = 3, cfg = "alquerque")
dfs <- tibble(piece_side = "bit_back", x = 1:5, y = 1:5, suit = 1:5, cfg = "alquerque")
df <- rbind(dfb, dfs)
cat_piece(dfb)
cat_piece(df)
})
})