Compare commits

...

8 Commits

  1. 23
      LICENSE
  2. 181
      rules.lua
  3. 81
      stones.lua

@ -0,0 +1,23 @@
Copyright (C)2023 capitalthree
Portions Copyright (C)2018-2023 Aaron Suen <warr1024@gmail.com>
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject
to the following conditions:
The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

@ -25,21 +25,23 @@ local solid_drawtypes = {
glasslike_framed = true,
}
local S = ("S"):byte(1)
local W = ("W"):byte(1)
local E = ("E"):byte(1)
local C = ("C"):byte(1)
--[[
E: empty
E: air
E_: other empty
Etype: territory marker of some type
Stype: a go stone of some type
W: full block wall
WE0-WE3: edge concrete
WC0-WC3: corner concrete
WB: other goban concrete
--]]
local function _check_position_uncached(pos)
local node = minetest.get_node(pos)
if node.name == "air" then
return "E"
end
local reg_item = minetest.registered_items[node.name]
if not reg_item then
@ -50,18 +52,26 @@ local function _check_position_uncached(pos)
return "S" .. reg_item.go_team
end
if reg_item.groups and reg_item.groups.go_territory_marker then
return "E" .. reg_item.go_team
end
if reg_item.pattern_def then
if reg_item.pattern_def.name == "edgy" then
return "WE" .. node.param2
elseif reg_item.pattern_def.name == "corny" then
return "WC" .. node.param2
elseif reg_item.pattern_def.name == "crossy" then
return "WB"
elseif reg_item.pattern_def.name == "starcrossy" then
return "WB"
end
end
if solid_drawtypes[reg_item.drawtype] and not reg_item.groups.falling_node then
return "W"
else
return "E"
return "E_"
end
end
@ -80,8 +90,8 @@ end
local function edge_check(pos, dir, terminate)
local under = check_position(pos + down)
if under:byte(1) == W and under:len() == 3 then
local corner = (under:byte(2) == C)
if under:sub(1, 1) == "W" and under:len() == 3 then
local corner = (under:sub(2, 2) == "C")
local edge_dir = tonumber(under:sub(3, 3))
if (dir == edge_dir) or (corner and (dir == (edge_dir+1)%4)) then
@ -106,7 +116,7 @@ local function neighbor_dirs(pos)
local neighbors = {}
for i,v in pairs(directions) do
if not edge_check(pos, i) then
if not (check_position(pos + directions[i]):byte(1) == W) then
if check_position(pos + directions[i]):sub(1, 1) ~= "W" then
neighbors[#neighbors+1] = i
end
end
@ -115,16 +125,11 @@ local function neighbor_dirs(pos)
return neighbors
end
--[[
Scans for a connected group, until enumerating the whole group, or
finding a liberty. Returns list of captured nodes, or empty list if
no captures.
--]]
local function check_captures(pos)
local function connected_search(pos, final_result, early_termination_filter)
local group = {pos}
local stones = {[minetest.hash_node_position(pos)] = pos}
local checked = {}
local team = check_position(pos):sub(2,-1)
local piece = check_position(pos)
local probe = 0
while probe < #group do
@ -138,10 +143,14 @@ local function check_captures(pos)
if (not stones[newhash]) and (not checked[newhash]) then
local newnode = check_position(newpos)
if newnode:byte(1) == E then
return {capture = false, stones = stones}
elseif newnode:byte(1) == S and
newnode:sub(2, -1) == team then
local filter_result
if early_termination_filter then
filter_result = early_termination_filter(newnode)
end
if filter_result then
filter_result.stones = stones
return filter_result
elseif newnode == piece then
stones[newhash] = newpos
group[#group+1] = newpos
else
@ -151,16 +160,70 @@ local function check_captures(pos)
end
end
return {capture = true, stones = stones}
final_result = final_result()
final_result.stones = stones
return final_result
end
local function _check_captures_filter(node)
if node:sub(1, 1) == "E" then
return {capture = false}
end
end
local function _check_captures_final()
return {capture = true}
end
local function check_captures(pos)
return connected_search(pos, _check_captures_final, _check_captures_filter)
end
local function _connected_group_final()
return {}
end
local function connected_group(pos)
return connected_search(pos, _connected_group_final)
end
local function territory_search(pos, max)
if check_position(pos) ~= "E" then
return {}
end
local team
return connected_search(pos,
function()
return {team = team}
end,
function(node)
if node == "E" then
max = max - 1
if max <= 0 then
return {}
end
elseif node ~= "E_" and ((node:sub(1, 1) == "E") or (node:sub(1, 1) == "S")) and node:len() > 1 then
node = node:sub(2, -1)
if team then
if team ~= node then
return {}
end
else
team = node
end
end
end
)
end
function lc_liberties.handle_placement(pos)
cache = {}
minetest.chat_send_all(tostring(pos))
--minetest.chat_send_all(tostring(pos))
--nodecore.node_sound(pos, "dug")
local our_stone = check_position(pos)
if not (our_stone:byte(1) == S) then
if our_stone:sub(1, 1) ~= "S" then
return
end
our_stone = our_stone:sub(2, -1)
@ -181,7 +244,7 @@ function lc_liberties.handle_placement(pos)
if not checked then
local node = check_position(new_pos)
if (node:byte(1) == S) and (not (node:sub(2, -1) == our_stone)) then
if (node:sub(1, 1) == "S") and (node:sub(2, -1) ~= our_stone) then
local captures = check_captures(new_pos)
captured = captured or captures.capture
captureses[#captureses+1] = captures
@ -192,22 +255,78 @@ function lc_liberties.handle_placement(pos)
if captured then
for i,v in pairs(captureses) do
if v.capture then
local proximal = {}
local stone = minetest.get_node(v.stones[next(v.stones)]).name
local count = 0
local proximal
local proximal_c = 0
for i2, v2 in pairs(v.stones) do
nodecore.set_loud(v2, {name = "nc_fire:fire"})
local under = check_position(v2 + down)
if (under:sub(1, 1) == "W") and (under:len() > 1) then
nodecore.set_loud(v2, {name = "nc_fire:fire"})
else
nodecore.set_loud(v2, {name = "air"})
end
count = count + 1
if (v2:distance(pos) < 2.3) then
proximal_c = proximal_c + 1
if math.random(1, proximal_c) == 1 then
proximal = v2
end
end
end
-- todo: spawn itemstack of captured stones somehow
local stack_max = minetest.registered_items[stone].stack_max
while count > 0 do
nodecore.item_eject(proximal, stone .. " " .. math.min(count, stack_max), 3)
count = count - stack_max
end
end
end
else
local captures = check_captures(pos)
if captures.capture then
minetest.chat_send_all("You gotcher self a suicide move right there! size: "..#(captures.stones))
-- todo: replace with itemstack of one stone
local stone = minetest.get_node(pos).name
nodecore.set_loud(pos, {name = "air"})
nodecore.item_eject(pos, stone, 5)
end
end
end
function lc_liberties.handle_territory_fill(itemstack, placer, pointed_thing)
cache = {}
if placer.get_player_control and placer:get_player_control().aux1 then
return minetest.item_place(itemstack, placer, pointed_thing)
end
if pointed_thing and pointed_thing.above then
local territories = territory_search(pointed_thing.above, itemstack:get_count())
if territories.team then
local piece = modname .. ":territory_" .. territories.team
local count = 0
for i, v in pairs(territories.stones) do
nodecore.set_loud(v, {name = piece})
count = count + 1
end
itemstack:set_count(itemstack:get_count() - count)
end
end
return itemstack
end
function lc_liberties.handle_dig(pos, node, digger)
cache = {}
if digger.get_player_control and digger:get_player_control().aux1 then
for i, v in pairs(connected_group(pos).stones) do
minetest.node_dig(v, node, digger)
end
return true
else
return minetest.node_dig(pos, node, digger)
end
end

@ -68,20 +68,79 @@ local function reg(name, basename, basedef)
sounds = basedef.sounds,
on_construct = lc_liberties.handle_placement
on_construct = lc_liberties.handle_placement,
on_dig = lc_liberties.handle_dig,
})
local territory_name = modname .. ":territory_" .. string_lower(name)
minetest.register_node(":" .. territory_name, {
description = "Territory Marker",
drawtype = "nodebox",
node_box = {
type = "fixed",
fixed = {
{-2/16, -8/16, -2/16, 2/16, -7/16, 2/16},
{-3/16, -7/16, -3/16, 3/16, -6/16, 3/16},
{-2/16, -6/16, -2/16, 2/16, -5/16, 2/16},
}
},
selection_box = {
type = "fixed",
fixed = {-6/16, -8/16, -6/16, 6/16, 0/16, 6/16}
},
tiles = {
basedef.tiles[1]
},
paramtype = "light",
sunlight_propagates = true,
groups = {
snappy = 1,
falling_node = 1,
falling_repose = 1,
go_territory_marker = 1,
},
go_team = name,
sounds = basedef.sounds,
on_place = lc_liberties.handle_territory_fill,
on_dig = lc_liberties.handle_dig,
})
nodecore.register_craft({
label = "Chop scored cement into go stones",
action = "pummel",
toolgroups = {choppy = 3},
nodes = {
{
match = "nc_concrete:" .. name .. "_starcrossy_ply",
replace = "air"
}
},
items = {{name = piecename, count = 3, scatter = 4}},
})
nodecore.register_craft({
label = "shave " .. string_lower(desc) .. " into stones",
action = "pummel",
toolgroups = {choppy = 3},
nodes = {
{
match = "nc_concrete:" .. name .. "_starcrossy_ply",
replace = "air"
}
},
items = {{name = piecename, count = 3, scatter = 4}},
label = "Smash go stones into territory markers",
action = "pummel",
toolgroups = {thumpy = 3},
nodes = {
{
match = piecename,
replace = "air"
}
},
items = {{name = territory_name, count = 9, scatter = 4}},
})
end

Loading…
Cancel
Save