@slugbugblue/trax 0.4.0 → 0.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/tty.js DELETED
@@ -1,202 +0,0 @@
1
- /* Copyright 2021 Chad Transtrum
2
- *
3
- * Licensed under the Apache License, Version 2.0 (the "License");
4
- * you may not use this file except in compliance with the License.
5
- * You may obtain a copy of the License at
6
- *
7
- * http://www.apache.org/licenses/LICENSE-2.0
8
- *
9
- * Unless required by applicable law or agreed to in writing, software
10
- * distributed under the License is distributed on an "AS IS" BASIS,
11
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
- * See the License for the specific language governing permissions and
13
- * limitations under the License.
14
- */
15
-
16
- // Ever wanted to draw Trax boards on the console? I have.
17
-
18
- import Trax from './engine.js'
19
-
20
- const esc = '\x1b[' // start of console color escape code
21
- const off = esc + 'm' // color reset code
22
-
23
- // display a message with optional color
24
- const out = (message, fgcolor, bgcolor) => {
25
- let ansi = fgcolor || bgcolor ? esc : ''
26
- if (fgcolor) ansi += '38;5;' + fgcolor
27
- if (bgcolor) ansi += '48;5;' + bgcolor
28
- if (ansi) ansi += 'm'
29
- console.log(ansi + message + off)
30
- }
31
-
32
- let set = 'trax' // which color set should we draw with?
33
-
34
- // a little magic to display the game in progress
35
- const color_sets = { // Colors for terminal sequence: <Esc>[38;5;<color_num>m
36
- // b, B, w, W: color of line for each player, capital for a winning line
37
- // e: empty (ie, board) color, t: tile color
38
- trax: { b: 238, B: 57, e: 19, t: 74, w: 255, W: 184 },
39
- trax8: { b: 236, B: 21, e: 58, t: 137, w: 254, W: 117 },
40
- traxloop: { b: 235, B: 20, e: 17, t: 61, w: 253, W: 222 },
41
- tentative: { b: 235, B: 18, e: 19, t: 244, w: 252, W: 217 },
42
- }
43
-
44
- const ln = 'm\u2584' // lower half block -- with the leading m to terminate ansi color escape
45
- const up = 'm\u2588' // full block
46
- const lt = 'm\u2599' // lower half and left half block
47
- const rt = 'm\u259f' // lower half and right half block
48
- const fg = n => '38;5;' + String(set[n]) // foreground color_num
49
- const bg = n => '48;5;' + String(set[n]) // background color_num
50
- const sp = () => esc + bg('e') + 'm ' // lower space
51
- // tiles are displayed on two lines; the top half of the first line is empty
52
- // and the second half is composed of three characters, up color surrounded by tile color
53
- const uptty = clr => esc + fg('t') + ';' + bg('e') + ln
54
- + esc + fg(clr) + ln + esc + fg('t') + ln + ' '
55
- // the top half of the second line has both horizontal lines with a center transition
56
- // while the bottom half is the tile background color surrounding the down color
57
- const horiztty = clr => esc + fg('t') + ';' + bg(clr) + ln
58
- const dntty = (clr, oppclr, char) => esc + fg(clr) + (char === up ? '' : ';' + bg(oppclr)) + char
59
- // list of icon_char => tile line colors for easy reference in order up, right, down, left
60
- const tiles = { a: 'bbww', b: 'bwbw', c: 'bwwb', d: 'wbbw', e: 'wbwb', f: 'wwbb' }
61
-
62
- // return the ANSI codes to display a 3x1.5 block tile, one line at a time
63
- const tile_tty = (tile, top) => { // top: true for first line, false for second
64
- // quick access to tile color and its opposite in upper case
65
- let colors = { b: 'b', w: 'w', B: 'w', W: 'b' }
66
- let save = set
67
- let tentative = tile !== tile.toLowerCase()
68
- if (tentative) set = color_sets.tentative
69
- tile = tile.toLowerCase()
70
- if (!(tile in tiles)) { // winning paths are represented by adding 6 to the tile char code
71
- tile = String.fromCharCode(tile.charCodeAt(0) - 6)
72
- if (tile in tiles) {
73
- colors.w = 'W'
74
- colors.B = 'W'
75
- } else { // and another six for a black win
76
- tile = String.fromCharCode(tile.charCodeAt(0) - 6)
77
- colors.b = 'B'
78
- colors.W = 'B'
79
- }
80
- }
81
- let val = false
82
- if (tile in tiles) {
83
- tile = tiles[tile]
84
- if (top) {
85
- val = uptty(colors[tile[0]])
86
- } else {
87
- let center_char = tile[1] === tile[2] ? rt : tile[2] === tile[3] ? lt : up
88
- let centertty = dntty(colors[tile[2]], colors[tile[2].toUpperCase()], center_char)
89
- val = horiztty(colors[tile[3]]) + centertty + horiztty(colors[tile[1]]) + sp()
90
- }
91
- }
92
- set = save
93
- return val || (top ? '??? ' : '\'\'\' ')
94
- }
95
-
96
- const merge_tentative = () => {
97
- color_sets.tentative.e = set.e // copy empty color to tentative set
98
- color_sets.tentative.W = set.W
99
- color_sets.tentative.B = set.B
100
- }
101
-
102
- const print_icon = (icon, set_name) => {
103
- set = color_sets[set_name] || color_sets.trax
104
- merge_tentative(set)
105
- const on = esc + '38;5;' + String(set.t) + ';48;5;' + String(set.e) + 'm'
106
- let o1 = ' '
107
- let o2 = '1 '
108
- let row = 1
109
- let width = 1
110
- let info = []
111
- let line_width = 0
112
- while (icon.length) {
113
- let c = icon[0]
114
- icon = icon.slice(1)
115
- if (c === ':') {
116
- info.push({o: o1, w: line_width})
117
- info.push({o: o2, w: line_width})
118
- row++
119
- width = Math.max(width, line_width)
120
- line_width = 0
121
- o1 = ' '
122
- o2 = String(row).padEnd(3)
123
- } else if (c >= '0' && c <= '9') {
124
- let empty = Number(c) + 1
125
- o1 += ' '.repeat(empty * 4)
126
- o2 += ' '.repeat(empty * 4)
127
- line_width += empty
128
- } else {
129
- o1 += tile_tty(c, 'top')
130
- o2 += tile_tty(c)
131
- line_width++
132
- }
133
- }
134
- if (o1.length) {
135
- info.push({o: o1, w: line_width})
136
- info.push({o: o2, w: line_width})
137
- width = Math.max(width, line_width)
138
- }
139
- let columns = process.stdout.columns || 0
140
- let rows = process.stdout.rows || 0
141
- if (width * 4 < columns - 4 && info.length < rows - 2) {
142
- let col_out = ' '
143
- for (let col = 1; col <= width; col++) {
144
- col_out += ' ' + Trax.column(col).padEnd(3)
145
- }
146
- console.info(on + col_out.padEnd((width + 1) * 4) + off)
147
- info.forEach(line => console.info(on + line.o + ''.padEnd((width - line.w) * 4) + ' ' + off))
148
- console.info(on + ''.padEnd((width + 1) * 4) + off)
149
- } else {
150
- console.warn('Console is too small to display this game')
151
- }
152
- }
153
-
154
- // flexible way to get a Trax game object
155
- // game = existing Trax instance, or a string indicating the variant name
156
- // moves = optional list or string of moves to be made on the game
157
- // returns a Trax instance
158
- const trax_game = (game='trax', moves) => {
159
- let trax
160
- if (game instanceof Trax) {
161
- trax = game
162
- if (moves) {
163
- if (typeof moves === 'string') moves = moves.split(' ')
164
- moves.forEach(move => trax.drop_tile(move))
165
- }
166
- } else {
167
- trax = new Trax(game, moves, 'cli')
168
- }
169
- return trax
170
- }
171
-
172
- const display_game = (game='trax', moves='', tentative) => {
173
- let trax = trax_game(game, moves)
174
- let icon = trax.icon
175
- if (tentative) {
176
- let drops = trax.drop_tile(tentative)
177
- if (drops.valid) {
178
- icon = trax.tentative_icon(drops)
179
- } else {
180
- tentative = false
181
- }
182
- }
183
- console.info(trax.notation)
184
- print_icon(icon, trax.rules)
185
- if (tentative) console.info('--- tentative position ---')
186
- let name = {1: 'white', 2: 'black'}[trax.turn]
187
- if (trax.over) {
188
- if (trax.turn) {
189
- console.info(name + ' wins')
190
- } else {
191
- console.info('game end' + (tentative ? 's' : 'ed') + ' in a draw')
192
- }
193
- } else if (trax.turn) {
194
- console.info((tentative ? 'leaving ' : '') + name +' to play')
195
- }
196
- }
197
-
198
- export default {
199
- display: display_game,
200
- game: trax_game,
201
- out,
202
- }